diff --git a/cli_args.go b/cli_args.go index 7bde89d..2f0c936 100644 --- a/cli_args.go +++ b/cli_args.go @@ -22,7 +22,7 @@ type argContainer struct { plaintextnames, quiet, nosyslog, wpanic, longnames, allow_other, ro, reverse, aessiv, nonempty, raw64, noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info, - sharedstorage, devrandom bool + sharedstorage, devrandom, fsck bool masterkey, mountpoint, cipherdir, cpuprofile, extpass, memprofile, ko, passfile, ctlsock, fsname, force_owner, trace string // Configuration file name override @@ -133,6 +133,7 @@ func parseCliOpts() (args argContainer) { 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") 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") @@ -220,3 +221,21 @@ func prettyArgs() string { pa = pa[1 : len(pa)-1] return pa } + +// countOpFlags counts the number of operation flags we were passed. +func countOpFlags(args *argContainer) int { + var count int + if args.info { + count++ + } + if args.passwd { + count++ + } + if args.init { + count++ + } + if args.fsck { + count++ + } + return count +} diff --git a/fsck.go b/fsck.go new file mode 100644 index 0000000..645cf91 --- /dev/null +++ b/fsck.go @@ -0,0 +1,9 @@ +package main + +import ( + "log" +) + +func fsck(args *argContainer) { + log.Panic("Not yet implemented") +} diff --git a/main.go b/main.go index ea5efb3..ff137c4 100644 --- a/main.go +++ b/main.go @@ -246,45 +246,46 @@ func main() { tlog.Debug.Printf("OpenSSL enabled") } // Operation flags - if args.info && args.init || args.info && args.passwd || args.passwd && args.init { - tlog.Fatal.Printf("At most one of -info, -init, -passwd is allowed") + nOps := countOpFlags(&args) + if nOps == 0 { + // Default operation: mount. + if flagSet.NArg() != 2 { + prettyArgs := prettyArgs() + tlog.Info.Printf("Wrong number of arguments (have %d, want 2). You passed: %s", + flagSet.NArg(), prettyArgs) + tlog.Fatal.Printf("Usage: %s [OPTIONS] CIPHERDIR MOUNTPOINT [-o COMMA-SEPARATED-OPTIONS]", tlog.ProgramName) + os.Exit(exitcodes.Usage) + } + doMount(&args) + // Don't call os.Exit to give deferred functions a chance to run + return + } + if nOps > 1 { + 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()) os.Exit(exitcodes.Usage) } // "-info" if args.info { - if flagSet.NArg() > 1 { - tlog.Fatal.Printf("Usage: %s -info CIPHERDIR", tlog.ProgramName) - os.Exit(exitcodes.Usage) - } info(args.config) os.Exit(0) } // "-init" if args.init { - if flagSet.NArg() > 1 { - tlog.Fatal.Printf("Usage: %s -init [OPTIONS] CIPHERDIR", tlog.ProgramName) - os.Exit(exitcodes.Usage) - } initDir(&args) os.Exit(0) } // "-passwd" if args.passwd { - if flagSet.NArg() > 1 { - tlog.Fatal.Printf("Usage: %s -passwd [OPTIONS] CIPHERDIR", tlog.ProgramName) - os.Exit(exitcodes.Usage) - } changePassword(&args) os.Exit(0) } - // Default operation: mount. - if flagSet.NArg() != 2 { - prettyArgs := prettyArgs() - tlog.Info.Printf("Wrong number of arguments (have %d, want 2). You passed: %s", - flagSet.NArg(), prettyArgs) - tlog.Fatal.Printf("Usage: %s [OPTIONS] CIPHERDIR MOUNTPOINT [-o COMMA-SEPARATED-OPTIONS]", tlog.ProgramName) - os.Exit(exitcodes.Usage) + // "-fsck" + if args.fsck { + fsck(&args) } - doMount(&args) - // Don't call os.Exit to give deferred functions a chance to run } diff --git a/tests/cli/cli_test.go b/tests/cli/cli_test.go index 9eebc5f..2cdaf37 100644 --- a/tests/cli/cli_test.go +++ b/tests/cli/cli_test.go @@ -18,6 +18,18 @@ import ( var testPw = []byte("test") +// Extract the exit code from an error value that was returned from +// exec.Run() +func extractExitCode(err error) int { + if err == nil { + return 0 + } + // OMG this is convoluted + err2 := err.(*exec.ExitError) + code := err2.Sys().(syscall.WaitStatus).ExitStatus() + return code +} + func TestMain(m *testing.M) { test_helpers.ResetTmpDir(false) r := m.Run() @@ -332,8 +344,7 @@ func TestMountPasswordIncorrect(t *testing.T) { cDir := test_helpers.InitFS(t) // Create filesystem with password "test" pDir := cDir + ".mnt" err := test_helpers.Mount(cDir, pDir, false, "-extpass", "echo WRONG", "-wpanic=false") - // vvvvvvvvvvvvvv OMG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - exitCode := err.(*exec.ExitError).Sys().(syscall.WaitStatus).ExitStatus() + exitCode := extractExitCode(err) if exitCode != exitcodes.PasswordIncorrect { t.Errorf("want=%d, got=%d", exitcodes.PasswordIncorrect, exitCode) } @@ -362,7 +373,7 @@ func TestPasswdPasswordIncorrect(t *testing.T) { t.Fatal(err) } err = cmd.Wait() - exitCode := err.(*exec.ExitError).Sys().(syscall.WaitStatus).ExitStatus() + exitCode := extractExitCode(err) if exitCode != exitcodes.PasswordIncorrect { t.Errorf("want=%d, got=%d", exitcodes.PasswordIncorrect, exitCode) } @@ -417,3 +428,27 @@ func TestMountBackground(t *testing.T) { t.Fatal("timeout") } } + +// Test that "gocryptfs -init -info CIPHERDIR" returns an error to the +// user. Only one operation flag is allowed. +func TestMultipleOperationFlags(t *testing.T) { + // Test all combinations + opFlags := []string{"-init", "-info", "-passwd", "-fsck"} + for _, flag1 := range opFlags { + var flag2 string + for _, flag2 = range opFlags { + if flag1 == flag2 { + continue + } + args := []string{flag1, flag2, "/tmp"} + //t.Logf("testing %v", args) + cmd := exec.Command(test_helpers.GocryptfsBinary, args...) + err := cmd.Run() + exitCode := extractExitCode(err) + if exitCode != exitcodes.Usage { + t.Fatalf("this should have failed with code %d, but returned %d", + exitcodes.Usage, exitCode) + } + } + } +}