Add the option -allow_other to upspinfs

Fix #615.

This allows the user to specify the flag -allow_other when mounting
an upspinfs endpoint so that the upspin filesystem becomes visible
to other users of the same system.

I like to use upspinfs for development across different machines.
Building in a docker container ensures a uniform build environment no
matter what machine I happen to be using at present.  Without
-allow_other, the user that runs the docker daemon (initially root)
can't see the mount point and `docker run` will fail, and crash my
dreams of a remote filesystem.

For some background see a similar issue here:
https://github.com/moby/moby/issues/27026#issuecomment-253579983

Allowing others to see your files in upspin is probably a bad idea in
general, as it allows the users to circumvent upspinfs permissions.  The
user should probably make sure they are aware who can access their mount
point to begin with.

However, given that (1) for this flag to work, the system administrator
needs to allow the action explicitly by allowing the flag in
/etc/fuse.conf, and (2) the user may always choose to give their
credentials away to whomever they want, it seems OK to allow the flag
to exist as long as the user and the admin both know what they are doing.

Change-Id: Ib14554875ce01127eac23ee7293774545f8b4da6
Reviewed-on: https://upspin-review.googlesource.com/c/19260
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/cmd/upspinfs/fs.go b/cmd/upspinfs/fs.go
index 11d0944..1bb9b66 100644
--- a/cmd/upspinfs/fs.go
+++ b/cmd/upspinfs/fs.go
@@ -1053,15 +1053,14 @@
 
 // do is called both by main and testing to mount a FUSE file system. It exits on failure
 // and returns when the file system has been mounted and is ready for requests.
-func do(cfg upspin.Config, mountpoint string, cacheDir string, cacheSize int64) chan bool {
+func do(cfg upspin.Config, mountpoint string, cacheDir string, cacheSize int64, allowOther bool) chan bool {
 	if log.GetLevel() == "debug" {
 		fuse.Debug = debug
 	}
 
 	f := newUpspinFS(cfg, mountpoint, cacheDir, cacheSize)
 
-	c, err := fuse.Mount(
-		mountpoint,
+	opts := []fuse.MountOption{
 		fuse.FSName("upspin"),
 		fuse.Subtype("fs"),
 		fuse.LocalVolume(),
@@ -1070,7 +1069,12 @@
 		//fuse.OSXDebugFuseKernel(),
 		//fuse.NoAppleDouble(),
 		//fuse.NoAppleXattr(),
-	)
+	}
+	if allowOther {
+		opts = append(opts, fuse.AllowOther())
+	}
+
+	c, err := fuse.Mount(mountpoint, opts...)
 	if err == fuse.ErrOSXFUSENotFound {
 		log.Fatal("FUSE for macOS is not installed. See https://osxfuse.github.io/")
 	}
diff --git a/cmd/upspinfs/main.go b/cmd/upspinfs/main.go
index c086157..71dc52b 100644
--- a/cmd/upspinfs/main.go
+++ b/cmd/upspinfs/main.go
@@ -30,7 +30,10 @@
 
 const cmdName = "upspinfs"
 
-var mountpointFlag = flag.String("mountpoint", "", "`directory` on which to mount file system")
+var (
+	mountpointFlag = flag.String("mountpoint", "", "`directory` on which to mount file system")
+	allowOther     = flag.Bool("allow_other", false, "if set, allow other users to see the mount point; if using this option ensure that mount point access is strictly controlled")
+)
 
 func usage() {
 	fmt.Fprintf(os.Stderr, "Usage: %s [-mountpoint] <mount point>\n", os.Args[0])
@@ -81,7 +84,8 @@
 	if err != nil {
 		log.Fatalf("can't determine absolute path to mount point %s: %s", *mountpointFlag, err)
 	}
-	done := do(cfg, mountpoint, filepath.Join(flags.CacheDir, string(cfg.UserName())), flags.CacheSize)
+	done := do(cfg, mountpoint, filepath.Join(flags.CacheDir, string(cfg.UserName())),
+		flags.CacheSize, *allowOther)
 
 	// Serve expvar data.
 	ln, err := local.Listen("tcp", config.LocalName(cfg, cmdName))
diff --git a/cmd/upspinfs/upspinfs_test.go b/cmd/upspinfs/upspinfs_test.go
index b94b411..20e074a 100644
--- a/cmd/upspinfs/upspinfs_test.go
+++ b/cmd/upspinfs/upspinfs_test.go
@@ -135,7 +135,7 @@
 
 	// Mount the file system. It will be served in a separate go routine.
 	log.SetLevel("info")
-	do(cfg, testConfig.mountpoint, testConfig.cacheDir, maxBytes)
+	do(cfg, testConfig.mountpoint, testConfig.cacheDir, maxBytes, false)
 
 	// Create the user root, all tests will need it.
 	testConfig.root = filepath.Join(testConfig.mountpoint, testConfig.user)