Merge branch '16100-mime-types'
[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         "net/http"
12         _ "net/http/pprof"
13         "os"
14
15         "git.arvados.org/arvados.git/sdk/go/arvados"
16         "git.arvados.org/arvados.git/sdk/go/arvadosclient"
17         "git.arvados.org/arvados.git/sdk/go/keepclient"
18         "github.com/arvados/cgofuse/fuse"
19 )
20
21 var Command = &cmd{}
22
23 type cmd struct {
24         // ready, if non-nil, will be closed when the mount is
25         // initialized.  If ready is non-nil, it RunCommand() should
26         // not be called more than once, or when ready is already
27         // closed.
28         ready chan struct{}
29         // It is safe to call Unmount only after ready has been
30         // closed.
31         Unmount func() (ok bool)
32 }
33
34 // RunCommand implements the subcommand "mount <path> [fuse options]".
35 //
36 // The "-d" fuse option (and perhaps other features) ignores the
37 // stderr argument and prints to os.Stderr instead.
38 func (c *cmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
39         logger := log.New(stderr, prog+" ", 0)
40         flags := flag.NewFlagSet(prog, flag.ContinueOnError)
41         ro := flags.Bool("ro", false, "read-only")
42         experimental := flags.Bool("experimental", false, "acknowledge this is an experimental command, and should not be used in production (required)")
43         blockCache := flags.Int("block-cache", 4, "read cache size (number of 64MiB blocks)")
44         pprof := flags.String("pprof", "", "serve Go profile data at `[addr]:port`")
45         err := flags.Parse(args)
46         if err != nil {
47                 logger.Print(err)
48                 return 2
49         }
50         if !*experimental {
51                 logger.Printf("error: experimental command %q used without --experimental flag", prog)
52                 return 2
53         }
54         if *pprof != "" {
55                 go func() {
56                         log.Println(http.ListenAndServe(*pprof, nil))
57                 }()
58         }
59
60         client := arvados.NewClientFromEnv()
61         ac, err := arvadosclient.New(client)
62         if err != nil {
63                 logger.Print(err)
64                 return 1
65         }
66         kc, err := keepclient.MakeKeepClient(ac)
67         if err != nil {
68                 logger.Print(err)
69                 return 1
70         }
71         kc.BlockCache = &keepclient.BlockCache{MaxBlocks: *blockCache}
72         host := fuse.NewFileSystemHost(&keepFS{
73                 Client:     client,
74                 KeepClient: kc,
75                 ReadOnly:   *ro,
76                 Uid:        os.Getuid(),
77                 Gid:        os.Getgid(),
78                 ready:      c.ready,
79         })
80         c.Unmount = host.Unmount
81         ok := host.Mount("", flags.Args())
82         if !ok {
83                 return 1
84         }
85         return 0
86 }