From d768c1c3e463cac7e79a78253230026a95a32170 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 26 Aug 2022 23:04:59 +0200 Subject: [PATCH 1/3] Allow cleanup handlers to filter the exit code --- cmd/restic/cleanup.go | 14 ++++++++------ cmd/restic/cmd_check.go | 4 ++-- cmd/restic/cmd_mount.go | 4 ++-- cmd/restic/global.go | 10 +++++----- cmd/restic/global_debug.go | 4 ++-- cmd/restic/lock.go | 6 +++--- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/cmd/restic/cleanup.go b/cmd/restic/cleanup.go index 67a007d59..61af72802 100644 --- a/cmd/restic/cleanup.go +++ b/cmd/restic/cleanup.go @@ -11,7 +11,7 @@ import ( var cleanupHandlers struct { sync.Mutex - list []func() error + list []func(code int) (int, error) done bool ch chan os.Signal } @@ -25,7 +25,7 @@ func init() { // AddCleanupHandler adds the function f to the list of cleanup handlers so // that it is executed when all the cleanup handlers are run, e.g. when SIGINT // is received. -func AddCleanupHandler(f func() error) { +func AddCleanupHandler(f func(code int) (int, error)) { cleanupHandlers.Lock() defer cleanupHandlers.Unlock() @@ -36,22 +36,24 @@ func AddCleanupHandler(f func() error) { } // RunCleanupHandlers runs all registered cleanup handlers -func RunCleanupHandlers() { +func RunCleanupHandlers(code int) int { cleanupHandlers.Lock() defer cleanupHandlers.Unlock() if cleanupHandlers.done { - return + return code } cleanupHandlers.done = true for _, f := range cleanupHandlers.list { - err := f() + var err error + code, err = f(code) if err != nil { Warnf("error in cleanup handler: %v\n", err) } } cleanupHandlers.list = nil + return code } // CleanupHandler handles the SIGINT signals. @@ -75,6 +77,6 @@ func CleanupHandler(c <-chan os.Signal) { // Exit runs the cleanup handlers and then terminates the process with the // given exit code. func Exit(code int) { - RunCleanupHandlers() + code = RunCleanupHandlers(code) os.Exit(code) } diff --git a/cmd/restic/cmd_check.go b/cmd/restic/cmd_check.go index 80b92862d..ab871e645 100644 --- a/cmd/restic/cmd_check.go +++ b/cmd/restic/cmd_check.go @@ -197,9 +197,9 @@ func runCheck(opts CheckOptions, gopts GlobalOptions, args []string) error { } cleanup := prepareCheckCache(opts, &gopts) - AddCleanupHandler(func() error { + AddCleanupHandler(func(code int) (int, error) { cleanup() - return nil + return code, nil }) repo, err := OpenRepository(gopts) diff --git a/cmd/restic/cmd_mount.go b/cmd/restic/cmd_mount.go index 747316f9f..2cc5bbdba 100644 --- a/cmd/restic/cmd_mount.go +++ b/cmd/restic/cmd_mount.go @@ -158,13 +158,13 @@ func runMount(opts MountOptions, gopts GlobalOptions, args []string) error { } } - AddCleanupHandler(func() error { + AddCleanupHandler(func(code int) (int, error) { debug.Log("running umount cleanup handler for mount at %v", mountpoint) err := umount(mountpoint) if err != nil { Warnf("unable to umount (maybe already umounted or still in use?): %v\n", err) } - return nil + return code, nil }) c, err := systemFuse.Mount(mountpoint, mountOptions...) diff --git a/cmd/restic/global.go b/cmd/restic/global.go index 3fe124dac..16afd993c 100644 --- a/cmd/restic/global.go +++ b/cmd/restic/global.go @@ -97,11 +97,11 @@ var isReadingPassword bool func init() { var cancel context.CancelFunc globalOptions.ctx, cancel = context.WithCancel(context.Background()) - AddCleanupHandler(func() error { + AddCleanupHandler(func(code int) (int, error) { // Must be called before the unlock cleanup handler to ensure that the latter is // not blocked due to limited number of backend connections, see #1434 cancel() - return nil + return code, nil }) f := cmdRoot.PersistentFlags() @@ -199,20 +199,20 @@ func restoreTerminal() { return } - AddCleanupHandler(func() error { + AddCleanupHandler(func(code int) (int, error) { // Restoring the terminal configuration while restic runs in the // background, causes restic to get stopped on unix systems with // a SIGTTOU signal. Thus only restore the terminal settings if // they might have been modified, which is the case while reading // a password. if !isReadingPassword { - return nil + return code, nil } err := checkErrno(term.Restore(fd, state)) if err != nil { fmt.Fprintf(os.Stderr, "unable to restore terminal state: %v\n", err) } - return err + return code, err }) } diff --git a/cmd/restic/global_debug.go b/cmd/restic/global_debug.go index 172f3451b..b798074d1 100644 --- a/cmd/restic/global_debug.go +++ b/cmd/restic/global_debug.go @@ -84,9 +84,9 @@ func runDebug() error { } if prof != nil { - AddCleanupHandler(func() error { + AddCleanupHandler(func(code int) (int, error) { prof.Stop() - return nil + return code, nil }) } diff --git a/cmd/restic/lock.go b/cmd/restic/lock.go index 64f82cf52..89acb0aef 100644 --- a/cmd/restic/lock.go +++ b/cmd/restic/lock.go @@ -119,7 +119,7 @@ func unlockRepo(lock *restic.Lock) { debug.Log("unable to find lock %v in the global list of locks, ignoring", lock) } -func unlockAll() error { +func unlockAll(code int) (int, error) { globalLocks.Lock() defer globalLocks.Unlock() @@ -127,11 +127,11 @@ func unlockAll() error { for _, lock := range globalLocks.locks { if err := lock.Unlock(); err != nil { debug.Log("error while unlocking: %v", err) - return err + return code, err } debug.Log("successfully removed lock") } globalLocks.locks = globalLocks.locks[:0] - return nil + return code, nil } From 5478ab22c51f4f3ee5512449164ad513c70323eb Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 26 Aug 2022 23:07:07 +0200 Subject: [PATCH 2/3] mount: return exit code 0 after receiving a SIGINT --- cmd/restic/cmd_mount.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/restic/cmd_mount.go b/cmd/restic/cmd_mount.go index 2cc5bbdba..337920c1e 100644 --- a/cmd/restic/cmd_mount.go +++ b/cmd/restic/cmd_mount.go @@ -164,6 +164,10 @@ func runMount(opts MountOptions, gopts GlobalOptions, args []string) error { if err != nil { Warnf("unable to umount (maybe already umounted or still in use?): %v\n", err) } + // replace error code of sigint + if code == 130 { + code = 0 + } return code, nil }) From 3174641ca4bde8a30cf2413555e5c00539860fcf Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 26 Aug 2022 23:17:04 +0200 Subject: [PATCH 3/3] add changelog for mount exit code filtering --- changelog/unreleased/issue-2015 | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 changelog/unreleased/issue-2015 diff --git a/changelog/unreleased/issue-2015 b/changelog/unreleased/issue-2015 new file mode 100644 index 000000000..e611bcbf8 --- /dev/null +++ b/changelog/unreleased/issue-2015 @@ -0,0 +1,10 @@ +Bugfix: Mount command should return exit code 0 after receiving Ctrl-C + +To stop the mount command, a user has to press Ctrl-C or send a SIGINT to +restic. This caused restic to exit with a non-zero exit code. + +We have changed the exit code to zero as this is the expected way to stop the +mount command. + +https://github.com/restic/restic/issues/2015 +https://github.com/restic/restic/pull/3894