blob: 80ba494407309dd5e4ed737df9121349df267e84 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The following enables go generate to generate the doc.go file.
//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go .
package main
import (
"errors"
"fmt"
"regexp"
"time"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/naming"
"v.io/v23/options"
"v.io/v23/rpc"
"v.io/v23/security"
"v.io/x/lib/cmdline"
"v.io/x/lib/vlog"
"v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/generic"
)
func main() {
cmdline.HideGlobalFlagsExcept(regexp.MustCompile(`^v23\.namespace\.root$`))
cmdline.Main(cmdRoot)
}
var cmdGlob = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runGlob),
Name: "glob",
Short: "returns all matching entries in the mount table",
Long: "returns all matching entries in the mount table",
ArgsName: "[<mount name>] <pattern>",
ArgsLong: `
<mount name> is a mount name on a mount table. Defaults to namespace root.
<pattern> is a glob pattern that is matched against all the entries below the
specified mount name.
`,
}
func runGlob(ctx *context.T, env *cmdline.Env, args []string) error {
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
if len(args) == 1 {
roots := v23.GetNamespace(ctx).Roots()
if len(roots) == 0 {
return errors.New("no namespace root")
}
args = append([]string{roots[0]}, args...)
}
if expected, got := 2, len(args); expected != got {
return env.UsageErrorf("glob: incorrect number of arguments, expected %d, got %d", expected, got)
}
name, pattern := args[0], args[1]
client := v23.GetClient(ctx)
call, err := client.StartCall(ctx, name, rpc.GlobMethod, []interface{}{pattern}, options.NoResolve{})
if err != nil {
return err
}
for {
var gr naming.GlobReply
if err := call.Recv(&gr); err != nil {
break
}
switch v := gr.(type) {
case naming.GlobReplyEntry:
fmt.Fprint(env.Stdout, v.Value.Name)
for _, s := range v.Value.Servers {
fmt.Fprintf(env.Stdout, " %s (Deadline %s)", s.Server, s.Deadline.Time)
}
fmt.Fprintln(env.Stdout)
}
}
if err := call.Finish(); err != nil {
return err
}
return nil
}
var cmdMount = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runMount),
Name: "mount",
Short: "Mounts a server <name> onto a mount table",
Long: "Mounts a server <name> onto a mount table",
ArgsName: "<mount name> <name> <ttl> [M|R]",
ArgsLong: `
<mount name> is a mount name on a mount table.
<name> is the rooted object name of the server.
<ttl> is the TTL of the new entry. It is a decimal number followed by a unit
suffix (s, m, h). A value of 0s represents an infinite duration.
[M|R] are mount options. M indicates that <name> is a mounttable. R indicates
that existing entries should be removed.
`,
}
func runMount(ctx *context.T, env *cmdline.Env, args []string) error {
got := len(args)
if got < 2 || got > 4 {
return env.UsageErrorf("mount: incorrect number of arguments, expected 2, 3, or 4, got %d", got)
}
name := args[0]
server := args[1]
var flags naming.MountFlag
var seconds uint32
if got >= 3 {
ttl, err := time.ParseDuration(args[2])
if err != nil {
return fmt.Errorf("TTL parse error: %v", err)
}
seconds = uint32(ttl.Seconds())
}
if got >= 4 {
for _, c := range args[3] {
switch c {
case 'M':
flags |= naming.MountFlag(naming.MT)
case 'R':
flags |= naming.MountFlag(naming.Replace)
}
}
}
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
client := v23.GetClient(ctx)
if err := client.Call(ctx, name, "Mount", []interface{}{server, seconds, flags}, nil, options.NoResolve{}); err != nil {
return err
}
fmt.Fprintln(env.Stdout, "Name mounted successfully.")
return nil
}
var cmdUnmount = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runUnmount),
Name: "unmount",
Short: "removes server <name> from the mount table",
Long: "removes server <name> from the mount table",
ArgsName: "<mount name> <name>",
ArgsLong: `
<mount name> is a mount name on a mount table.
<name> is the rooted object name of the server.
`,
}
func runUnmount(ctx *context.T, env *cmdline.Env, args []string) error {
if expected, got := 2, len(args); expected != got {
return env.UsageErrorf("unmount: incorrect number of arguments, expected %d, got %d", expected, got)
}
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
client := v23.GetClient(ctx)
if err := client.Call(ctx, args[0], "Unmount", []interface{}{args[1]}, nil, options.NoResolve{}); err != nil {
return err
}
fmt.Fprintln(env.Stdout, "Unmount successful or name not mounted.")
return nil
}
var cmdResolveStep = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runResolveStep),
Name: "resolvestep",
Short: "takes the next step in resolving a name.",
Long: "takes the next step in resolving a name.",
ArgsName: "<mount name>",
ArgsLong: `
<mount name> is a mount name on a mount table.
`,
}
func runResolveStep(ctx *context.T, env *cmdline.Env, args []string) error {
if expected, got := 1, len(args); expected != got {
return env.UsageErrorf("mount: incorrect number of arguments, expected %d, got %d", expected, got)
}
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
client := v23.GetClient(ctx)
var entry naming.MountEntry
if err := client.Call(ctx, args[0], "ResolveStep", nil, []interface{}{&entry}, options.NoResolve{}); err != nil {
return err
}
fmt.Fprintf(env.Stdout, "Servers: %v Suffix: %q MT: %v\n", entry.Servers, entry.Name, entry.ServesMountTable)
return nil
}
var cmdRoot = &cmdline.Command{
Name: "mounttable",
Short: "sends commands to Vanadium mounttable services",
Long: `
Command mounttable sends commands to Vanadium mounttable services.
`,
Children: []*cmdline.Command{cmdGlob, cmdMount, cmdUnmount, cmdResolveStep},
}
func blessingPatternsFromServer(ctx *context.T, server string) ([]security.BlessingPattern, error) {
vlog.Infof("Contacting %q to determine the blessings presented by it", server)
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
call, err := v23.GetClient(ctx).StartCall(ctx, server, rpc.ReservedSignature, nil)
if err != nil {
return nil, fmt.Errorf("Unable to extract blessings presented by %q: %v", server, err)
}
blessings, _ := call.RemoteBlessings()
if len(blessings) == 0 {
return nil, fmt.Errorf("No recognizable blessings presented by %q, it cannot be securely mounted", server)
}
// This translation between BlessingPattern and string is silly!
// Kill the BlessingPatterns type and make methods on that type
// functions instead!
patterns := make([]security.BlessingPattern, len(blessings))
for i := range blessings {
patterns[i] = security.BlessingPattern(blessings[i])
}
return patterns, nil
}