12308: Add "arvados-client mount" command via cgofuse.
[arvados.git] / lib / mount / command.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package mount
6
7 import (
8         "flag"
9         "io"
10         "log"
11         "os"
12
13         "git.arvados.org/arvados.git/sdk/go/arvados"
14         "git.arvados.org/arvados.git/sdk/go/arvadosclient"
15         "git.arvados.org/arvados.git/sdk/go/keepclient"
16         "github.com/arvados/cgofuse/fuse"
17 )
18
19 var Command = &cmd{}
20
21 type cmd struct {
22         // ready, if non-nil, will be closed when the mount is
23         // initialized.  If ready is non-nil, it RunCommand() should
24         // not be called more than once, or when ready is already
25         // closed.
26         ready chan struct{}
27         // It is safe to call Unmount ounly after ready has been
28         // closed.
29         Unmount func() (ok bool)
30 }
31
32 // RunCommand implements the subcommand "mount <path> [fuse options]".
33 //
34 // The "-d" fuse option (and perhaps other features) ignores the
35 // stderr argument and prints to os.Stderr instead.
36 func (c *cmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
37         logger := log.New(stderr, prog+" ", 0)
38         flags := flag.NewFlagSet(prog, flag.ContinueOnError)
39         ro := flags.Bool("ro", false, "read-only")
40         experimental := flags.Bool("experimental", false, "acknowledge this is an experimental command, and should not be used in production (required)")
41         err := flags.Parse(args)
42         if err != nil {
43                 logger.Print(err)
44                 return 2
45         }
46         if !*experimental {
47                 logger.Printf("error: experimental command %q used without --experimental flag", prog)
48                 return 2
49         }
50
51         client := arvados.NewClientFromEnv()
52         ac, err := arvadosclient.New(client)
53         if err != nil {
54                 logger.Print(err)
55                 return 1
56         }
57         kc, err := keepclient.MakeKeepClient(ac)
58         if err != nil {
59                 logger.Print(err)
60                 return 1
61         }
62         host := fuse.NewFileSystemHost(&keepFS{
63                 Client:     client,
64                 KeepClient: kc,
65                 ReadOnly:   *ro,
66                 Uid:        os.Getuid(),
67                 Gid:        os.Getgid(),
68                 ready:      c.ready,
69         })
70         c.Unmount = host.Unmount
71         ok := host.Mount("", flags.Args())
72         if !ok {
73                 return 1
74         }
75         return 0
76 }