diff options
-rw-r--r-- | cli_args.go | 173 | ||||
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | go.sum | 4 | ||||
-rw-r--r-- | help.go | 4 | ||||
-rw-r--r-- | init_dir.go | 2 | ||||
-rw-r--r-- | main.go | 18 | ||||
-rw-r--r-- | mount.go | 2 |
7 files changed, 108 insertions, 97 deletions
diff --git a/cli_args.go b/cli_args.go index ce15448..8dbdcd6 100644 --- a/cli_args.go +++ b/cli_args.go @@ -3,10 +3,9 @@ package main // Should be initialized before anything else. // This import line MUST be in the alphabitcally first source code file of // package main! -import _ "github.com/rfjakob/gocryptfs/internal/ensurefds012" - import ( - "flag" + _ "github.com/rfjakob/gocryptfs/internal/ensurefds012" + "fmt" "net" "os" @@ -15,8 +14,9 @@ import ( "strings" "time" - "github.com/hanwen/go-fuse/v2/fuse" + "github.com/integrii/flaggy" + "github.com/hanwen/go-fuse/v2/fuse" "github.com/rfjakob/gocryptfs/internal/configfile" "github.com/rfjakob/gocryptfs/internal/exitcodes" "github.com/rfjakob/gocryptfs/internal/stupidgcm" @@ -35,9 +35,9 @@ type argContainer struct { masterkey, mountpoint, cipherdir, cpuprofile, memprofile, ko, ctlsock, fsname, force_owner, trace, fido2 string // -extpass, -badname, -passfile can be passed multiple times - extpass, badname, passfile multipleStrings + extpass, badname, passfile []string // For reverse mode, several ways to specify exclusions. All can be specified multiple times. - exclude, excludeWildcard, excludeFrom multipleStrings + exclude, excludeWildcard, excludeFrom []string // Configuration file name override config string notifypid, scryptn int @@ -71,8 +71,6 @@ func (s *multipleStrings) Empty() bool { return len(s2) == 0 } -var flagSet *flag.FlagSet - // prefixOArgs transform options passed via "-o foo,bar" into regular options // like "-foo -bar" and prefixes them to the command line. // Testcases in TestPrefixOArgs(). @@ -126,7 +124,6 @@ func prefixOArgs(osArgs []string) ([]string, error) { // parseCliOpts - parse command line options (i.e. arguments that start with "-") func parseCliOpts() (args argContainer) { var err error - var opensslAuto string os.Args, err = prefixOArgs(os.Args) if err != nil { @@ -134,96 +131,102 @@ func parseCliOpts() (args argContainer) { os.Exit(exitcodes.Usage) } - flagSet = flag.NewFlagSet(tlog.ProgramName, flag.ContinueOnError) - flagSet.Usage = func() {} - flagSet.BoolVar(&args.debug, "d", false, "") - flagSet.BoolVar(&args.debug, "debug", false, "Enable debug output") - flagSet.BoolVar(&args.fusedebug, "fusedebug", false, "Enable fuse library debug output") - flagSet.BoolVar(&args.init, "init", false, "Initialize encrypted directory") - flagSet.BoolVar(&args.zerokey, "zerokey", false, "Use all-zero dummy master key") + flaggy.SetName(tlog.ProgramName) + flaggy.DefaultParser.ShowVersionWithVersionFlag = false + + flaggy.AddPositionalValue(&args.cipherdir, "CIPHERDIR", 1, false, "ciphertext directory") + flaggy.AddPositionalValue(&args.mountpoint, "MOUNTPOINT", 2, false, "mountpoint") + + flaggy.Bool(&args.debug, "d", "", "") + flaggy.Bool(&args.debug, "debug", "", "Enable debug output") + flaggy.Bool(&args.fusedebug, "fusedebug", "", "Enable fuse library debug output") + flaggy.Bool(&args.init, "init", "", "Initialize encrypted directory") + flaggy.Bool(&args.zerokey, "zerokey", "", "Use all-zero dummy master key") // Tri-state true/false/auto - flagSet.StringVar(&opensslAuto, "openssl", "auto", "Use OpenSSL instead of built-in Go crypto") - flagSet.BoolVar(&args.passwd, "passwd", false, "Change password") - flagSet.BoolVar(&args.fg, "f", false, "") - flagSet.BoolVar(&args.fg, "fg", false, "Stay in the foreground") - flagSet.BoolVar(&args.version, "version", false, "Print version and exit") - flagSet.BoolVar(&args.plaintextnames, "plaintextnames", false, "Do not encrypt file names") - flagSet.BoolVar(&args.quiet, "q", false, "") - flagSet.BoolVar(&args.quiet, "quiet", false, "Quiet - silence informational messages") - flagSet.BoolVar(&args.nosyslog, "nosyslog", false, "Do not redirect output to syslog when running in the background") - flagSet.BoolVar(&args.wpanic, "wpanic", false, "When encountering a warning, panic and exit immediately") - flagSet.BoolVar(&args.longnames, "longnames", true, "Store names longer than 176 bytes in extra files") - flagSet.BoolVar(&args.allow_other, "allow_other", false, "Allow other users to access the filesystem. "+ + opensslAuto := "auto" + flaggy.String(&opensslAuto, "openssl", "", "Use OpenSSL instead of built-in Go crypto") + flaggy.Bool(&args.passwd, "passwd", "", "Change password") + flaggy.Bool(&args.fg, "f", "", "") + flaggy.Bool(&args.fg, "fg", "", "Stay in the foreground") + flaggy.Bool(&args.version, "version", "", "Print version and exit") + flaggy.Bool(&args.plaintextnames, "plaintextnames", "", "Do not encrypt file names") + flaggy.Bool(&args.quiet, "q", "", "") + flaggy.Bool(&args.quiet, "quiet", "", "Quiet - silence informational messages") + flaggy.Bool(&args.nosyslog, "nosyslog", "", "Do not redirect output to syslog when running in the background") + flaggy.Bool(&args.wpanic, "wpanic", "", "When encountering a warning, panic and exit immediately") + args.longnames = true + flaggy.Bool(&args.longnames, "longnames", "", "Store names longer than 176 bytes in extra files") + flaggy.Bool(&args.allow_other, "allow_other", "", "Allow other users to access the filesystem. "+ "Only works if user_allow_other is set in /etc/fuse.conf.") - flagSet.BoolVar(&args.reverse, "reverse", false, "Reverse mode") - flagSet.BoolVar(&args.aessiv, "aessiv", false, "AES-SIV encryption") - flagSet.BoolVar(&args.nonempty, "nonempty", false, "Allow mounting over non-empty directories") - flagSet.BoolVar(&args.raw64, "raw64", true, "Use unpadded base64 for file names") - flagSet.BoolVar(&args.noprealloc, "noprealloc", false, "Disable preallocation before writing") - flagSet.BoolVar(&args.speed, "speed", false, "Run crypto speed test") - flagSet.BoolVar(&args.hkdf, "hkdf", true, "Use HKDF as an additional key derivation step") - flagSet.BoolVar(&args.serialize_reads, "serialize_reads", false, "Try to serialize read operations") - flagSet.BoolVar(&args.forcedecode, "forcedecode", false, "Force decode of files even if integrity check fails."+ + flaggy.Bool(&args.reverse, "reverse", "", "Reverse mode") + flaggy.Bool(&args.aessiv, "aessiv", "", "AES-SIV encryption") + flaggy.Bool(&args.nonempty, "nonempty", "", "Allow mounting over non-empty directories") + args.raw64 = true + flaggy.Bool(&args.raw64, "raw64", "", "Use unpadded base64 for file names") + flaggy.Bool(&args.noprealloc, "noprealloc", "", "Disable preallocation before writing") + flaggy.Bool(&args.speed, "speed", "", "Run crypto speed test") + args.hkdf = true + flaggy.Bool(&args.hkdf, "hkdf", "", "Use HKDF as an additional key derivation step") + flaggy.Bool(&args.serialize_reads, "serialize_reads", "", "Try to serialize read operations") + flaggy.Bool(&args.forcedecode, "forcedecode", "", "Force decode of files even if integrity check fails."+ " Requires gocryptfs to be compiled with openssl support and implies -openssl true") - flagSet.BoolVar(&args.hh, "hh", false, "Show this long help text") - flagSet.BoolVar(&args.info, "info", false, "Display information about CIPHERDIR") - flagSet.BoolVar(&args.sharedstorage, "sharedstorage", false, "Make concurrent access to a shared CIPHERDIR safer") - flagSet.BoolVar(&args.devrandom, "devrandom", false, "Use /dev/random for generating master key") - flagSet.BoolVar(&args.fsck, "fsck", false, "Run a filesystem check on CIPHERDIR") + flaggy.Bool(&args.hh, "hh", "", "Show this long help text") + flaggy.Bool(&args.info, "info", "", "Display information about CIPHERDIR") + flaggy.Bool(&args.sharedstorage, "sharedstorage", "", "Make concurrent access to a shared CIPHERDIR safer") + flaggy.Bool(&args.devrandom, "devrandom", "", "Use /dev/random for generating master key") + flaggy.Bool(&args.fsck, "fsck", "", "Run a filesystem check on CIPHERDIR") // Mount options with opposites - flagSet.BoolVar(&args.dev, "dev", false, "Allow device files") - flagSet.BoolVar(&args.nodev, "nodev", false, "Deny device files") - flagSet.BoolVar(&args.suid, "suid", false, "Allow suid binaries") - flagSet.BoolVar(&args.nosuid, "nosuid", false, "Deny suid binaries") - flagSet.BoolVar(&args.exec, "exec", false, "Allow executables") - flagSet.BoolVar(&args.noexec, "noexec", false, "Deny executables") - flagSet.BoolVar(&args.rw, "rw", false, "Mount the filesystem read-write") - flagSet.BoolVar(&args.ro, "ro", false, "Mount the filesystem read-only") - flagSet.BoolVar(&args.kernel_cache, "kernel_cache", false, "Enable the FUSE kernel_cache option") - flagSet.BoolVar(&args.acl, "acl", false, "Enforce ACLs") + flaggy.Bool(&args.dev, "dev", "", "Allow device files") + flaggy.Bool(&args.nodev, "nodev", "", "Deny device files") + flaggy.Bool(&args.suid, "suid", "", "Allow suid binaries") + flaggy.Bool(&args.nosuid, "nosuid", "", "Deny suid binaries") + flaggy.Bool(&args.exec, "exec", "", "Allow executables") + flaggy.Bool(&args.noexec, "noexec", "", "Deny executables") + flaggy.Bool(&args.rw, "rw", "", "Mount the filesystem read-write") + flaggy.Bool(&args.ro, "ro", "", "Mount the filesystem read-only") + flaggy.Bool(&args.kernel_cache, "kernel_cache", "", "Enable the FUSE kernel_cache option") + flaggy.Bool(&args.acl, "acl", "", "Enforce ACLs") - flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key") - flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file") - flagSet.StringVar(&args.memprofile, "memprofile", "", "Write memory profile to specified file") - flagSet.StringVar(&args.config, "config", "", "Use specified config file instead of CIPHERDIR/gocryptfs.conf") - flagSet.StringVar(&args.ko, "ko", "", "Pass additional options directly to the kernel, comma-separated list") - flagSet.StringVar(&args.ctlsock, "ctlsock", "", "Create control socket at specified path") - flagSet.StringVar(&args.fsname, "fsname", "", "Override the filesystem name") - flagSet.StringVar(&args.force_owner, "force_owner", "", "uid:gid pair to coerce ownership") - flagSet.StringVar(&args.trace, "trace", "", "Write execution trace to file") - flagSet.StringVar(&args.fido2, "fido2", "", "Protect the masterkey using a FIDO2 token instead of a password") + flaggy.String(&args.masterkey, "masterkey", "", "Mount with explicit master key") + flaggy.String(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file") + flaggy.String(&args.memprofile, "memprofile", "", "Write memory profile to specified file") + flaggy.String(&args.config, "config", "", "Use specified config file instead of CIPHERDIR/gocryptfs.conf") + flaggy.String(&args.ko, "ko", "", "Pass additional options directly to the kernel, comma-separated list") + flaggy.String(&args.ctlsock, "ctlsock", "", "Create control socket at specified path") + flaggy.String(&args.fsname, "fsname", "", "Override the filesystem name") + flaggy.String(&args.force_owner, "force_owner", "", "uid:gid pair to coerce ownership") + flaggy.String(&args.trace, "trace", "", "Write execution trace to file") + flaggy.String(&args.fido2, "fido2", "", "Protect the masterkey using a FIDO2 token instead of a password") // Exclusion options - flagSet.Var(&args.exclude, "e", "Alias for -exclude") - flagSet.Var(&args.exclude, "exclude", "Exclude relative path from reverse view") - flagSet.Var(&args.excludeWildcard, "ew", "Alias for -exclude-wildcard") - flagSet.Var(&args.excludeWildcard, "exclude-wildcard", "Exclude path from reverse view, supporting wildcards") - flagSet.Var(&args.excludeFrom, "exclude-from", "File from which to read exclusion patterns (with -exclude-wildcard syntax)") + flaggy.StringSlice(&args.exclude, "e", "exclude", "Exclude relative path from reverse view") + flaggy.StringSlice(&args.excludeWildcard, "ew", "exclude-wildcard", "Exclude path from reverse view, supporting wildcards") + flaggy.StringSlice(&args.excludeFrom, "exclude-from", "", "File from which to read exclusion patterns (with -exclude-wildcard syntax)") // multipleStrings options ([]string) - flagSet.Var(&args.extpass, "extpass", "Use external program for the password prompt") - flagSet.Var(&args.badname, "badname", "Glob pattern invalid file names that should be shown") - flagSet.Var(&args.passfile, "passfile", "Read password from file") + flaggy.StringSlice(&args.extpass, "extpass", "", "Use external program for the password prompt") + flaggy.StringSlice(&args.badname, "badname", "", "Glob pattern invalid file names that should be shown") + flaggy.StringSlice(&args.passfile, "passfile", "", "Read password from file") - flagSet.IntVar(&args.notifypid, "notifypid", 0, "Send USR1 to the specified process after "+ + flaggy.Int(&args.notifypid, "notifypid", "", "Send USR1 to the specified process after "+ "successful mount - used internally for daemonization") const scryptn = "scryptn" - flagSet.IntVar(&args.scryptn, scryptn, configfile.ScryptDefaultLogN, "scrypt cost parameter logN. Possible values: 10-28. "+ + args.scryptn = configfile.ScryptDefaultLogN + flaggy.Int(&args.scryptn, scryptn, "", "scrypt cost parameter logN. Possible values: 10-28. "+ "A lower value speeds up mounting and reduces its memory needs, but makes the password susceptible to brute-force attacks") - flagSet.DurationVar(&args.idle, "i", 0, "Alias for -idle") - flagSet.DurationVar(&args.idle, "idle", 0, "Auto-unmount after specified idle duration (ignored in reverse mode). "+ + flaggy.Duration(&args.idle, "i", "idle", "Auto-unmount after specified idle duration (ignored in reverse mode). "+ "Durations are specified like \"500s\" or \"2h45m\". 0 means stay mounted indefinitely.") var nofail bool - flagSet.BoolVar(&nofail, "nofail", false, "Ignored for /etc/fstab compatibility") + flaggy.Bool(&nofail, "nofail", "", "Ignored for /etc/fstab compatibility") var dummyString string - flagSet.StringVar(&dummyString, "o", "", "For compatibility with mount(1), options can be also passed as a comma-separated list to -o on the end.") + flaggy.String(&dummyString, "o", "", "For compatibility with mount(1), options can be also passed as a comma-separated list to -o on the end.") // Actual parsing - err = flagSet.Parse(os.Args[1:]) - if err == flag.ErrHelp { + err = flaggy.DefaultParser.Parse() + if err != nil { helpShort() os.Exit(0) } @@ -232,7 +235,7 @@ func parseCliOpts() (args argContainer) { os.Exit(exitcodes.Usage) } // We want to know if -scryptn was passed explicitly - if isFlagPassed(flagSet, scryptn) { + if false /* TODO isFlagPassed(flaggy, scryptn)*/ { args._explicitScryptn = true } // "-openssl" needs some post-processing @@ -271,7 +274,7 @@ func parseCliOpts() (args argContainer) { args.allow_other = false args.ko = "noexec" } - if !args.extpass.Empty() && len(args.passfile) != 0 { + if len(args.extpass) > 0 && len(args.passfile) != 0 { tlog.Fatal.Printf("The options -extpass and -passfile cannot be used at the same time") os.Exit(exitcodes.Usage) } @@ -279,11 +282,11 @@ func parseCliOpts() (args argContainer) { tlog.Fatal.Printf("The options -passfile and -masterkey cannot be used at the same time") os.Exit(exitcodes.Usage) } - if !args.extpass.Empty() && args.masterkey != "" { + if len(args.extpass) > 0 && args.masterkey != "" { tlog.Fatal.Printf("The options -extpass and -masterkey cannot be used at the same time") os.Exit(exitcodes.Usage) } - if !args.extpass.Empty() && args.fido2 != "" { + if len(args.extpass) > 0 && args.fido2 != "" { tlog.Fatal.Printf("The options -extpass and -fido2 cannot be used at the same time") os.Exit(exitcodes.Usage) } @@ -331,12 +334,14 @@ func countOpFlags(args *argContainer) int { // isFlagPassed finds out if the flag was explictely passed on the command line. // https://stackoverflow.com/a/54747682/1380267 -func isFlagPassed(flagSet *flag.FlagSet, name string) bool { +/* TODO +func isFlagPassed(flaggy *flag.flaggy, name string) bool { found := false - flagSet.Visit(func(f *flag.Flag) { + flaggy.Visit(func(f *flag.Flag) { if f.Name == name { found = true } }) return found } +*/ @@ -4,6 +4,7 @@ go 1.16 require ( github.com/hanwen/go-fuse/v2 v2.1.1-0.20210802120645-15a8bb029a4e + github.com/integrii/flaggy v1.4.4 // indirect github.com/jacobsa/crypto v0.0.0-20190317225127-9f44e2d11115 github.com/jacobsa/oglematchers v0.0.0-20150720000706-141901ea67cd // indirect github.com/jacobsa/oglemock v0.0.0-20150831005832-e94d794d06ff // indirect @@ -12,6 +13,7 @@ require ( github.com/pkg/xattr v0.4.1 github.com/rfjakob/eme v1.1.1 github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 + github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.5.1 // indirect golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect @@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/hanwen/go-fuse/v2 v2.1.1-0.20210802120645-15a8bb029a4e h1:mykFj7/XZmUTy/rRWaqbqHJEFU+dXfLmuigEWTlgECE= github.com/hanwen/go-fuse/v2 v2.1.1-0.20210802120645-15a8bb029a4e/go.mod h1:B1nGE/6RBFyBRC1RRnf23UpwCdyJ31eukw34oAKukAc= +github.com/integrii/flaggy v1.4.4 h1:8fGyiC14o0kxhTqm2VBoN19fDKPZsKipP7yggreTMDc= +github.com/integrii/flaggy v1.4.4/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI= github.com/jacobsa/crypto v0.0.0-20190317225127-9f44e2d11115 h1:YuDUUFNM21CAbyPOpOP8BicaTD/0klJEKt5p8yuw+uY= github.com/jacobsa/crypto v0.0.0-20190317225127-9f44e2d11115/go.mod h1:LadVJg0XuawGk+8L1rYnIED8451UyNxEMdTWCEt5kmU= github.com/jacobsa/oglematchers v0.0.0-20150720000706-141901ea67cd h1:9GCSedGjMcLZCrusBZuo4tyKLpKUPenUUqi34AkuFmA= @@ -22,6 +24,8 @@ github.com/rfjakob/eme v1.1.1 h1:t+CgvcOn+eDvj2xdglxsSnkgg8LM8jwdxnV7OnsrTn0= github.com/rfjakob/eme v1.1.1/go.mod h1:U2bmx0hDj8EyDdcxmD5t3XHDnBFnyNNc22n1R4008eM= github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 h1:G04eS0JkAIVZfaJLjla9dNxkJCPiKIGZlw9AfOhzOD0= github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94/go.mod h1:b18R55ulyQ/h3RaWyloPyER7fWQVZvimKKhnI5OfrJQ= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -3,6 +3,8 @@ package main import ( "fmt" + "github.com/integrii/flaggy" + "github.com/rfjakob/gocryptfs/internal/tlog" ) @@ -51,6 +53,6 @@ func helpLong() { fmt.Printf("\n") fmt.Printf(tUsage) fmt.Printf("\nOptions:\n") - flagSet.PrintDefaults() + flaggy.ShowHelp("") fmt.Printf(" --\n Stop option parsing\n") } diff --git a/init_dir.go b/init_dir.go index 68268a0..54a44e4 100644 --- a/init_dir.go +++ b/init_dir.go @@ -69,7 +69,7 @@ func initDir(args *argContainer) { } } // Choose password for config file - if args.extpass.Empty() && args.fido2 == "" { + if len(args.extpass) == 0 && args.fido2 == "" { tlog.Info.Printf("Choose a password for protecting your files.") } { @@ -169,7 +169,7 @@ func main() { args := parseCliOpts() // Fork a child into the background if "-fg" is not set AND we are mounting // a filesystem. The child will do all the work. - if !args.fg && flagSet.NArg() == 2 { + if !args.fg && args.cipherdir != "" && args.mountpoint != "" { ret := forkChild() os.Exit(ret) } @@ -200,8 +200,8 @@ func main() { tlog.Debug.Printf("Panicking on warnings") } // Every operation below requires CIPHERDIR. Exit if we don't have it. - if flagSet.NArg() == 0 { - if flagSet.NFlag() == 0 { + if args.cipherdir == "" { + if len(os.Args[1:]) == 0 { // Naked call to "gocryptfs". Just print the help text. helpShort() } else { @@ -212,7 +212,7 @@ func main() { os.Exit(exitcodes.Usage) } // Check that CIPHERDIR exists - args.cipherdir, _ = filepath.Abs(flagSet.Arg(0)) + args.cipherdir, _ = filepath.Abs(args.cipherdir) err = isDir(args.cipherdir) if err != nil { tlog.Fatal.Printf("Invalid cipherdir: %v", err) @@ -287,10 +287,9 @@ func main() { nOps := countOpFlags(&args) if nOps == 0 { // Default operation: mount. - if flagSet.NArg() != 2 { + if args.cipherdir == "" || args.mountpoint == "" { prettyArgs := prettyArgs() - tlog.Info.Printf("Wrong number of arguments (have %d, want 2). You passed: %s", - flagSet.NArg(), prettyArgs) + tlog.Info.Printf("Wrong number of arguments. You passed: %s", prettyArgs) tlog.Fatal.Printf("Usage: %s [OPTIONS] CIPHERDIR MOUNTPOINT [-o COMMA-SEPARATED-OPTIONS]", tlog.ProgramName) os.Exit(exitcodes.Usage) } @@ -302,9 +301,8 @@ func main() { tlog.Fatal.Printf("At most one of -info, -init, -passwd, -fsck is allowed") os.Exit(exitcodes.Usage) } - if flagSet.NArg() != 1 { - tlog.Fatal.Printf("The options -info, -init, -passwd, -fsck take exactly one argument, %d given", - flagSet.NArg()) + if args.cipherdir == "" || args.mountpoint != "" { + tlog.Fatal.Printf("The options -info, -init, -passwd, -fsck take exactly one argument") os.Exit(exitcodes.Usage) } // "-info" @@ -45,7 +45,7 @@ type AfterUnmounter interface { func doMount(args *argContainer) { // Check mountpoint var err error - args.mountpoint, err = filepath.Abs(flagSet.Arg(1)) + args.mountpoint, err = filepath.Abs(args.mountpoint) if err != nil { tlog.Fatal.Printf("Invalid mountpoint: %v", err) os.Exit(exitcodes.MountPoint) |