Allow cleanup handlers to filter the exit code

This commit is contained in:
Michael Eischer 2022-08-26 23:04:59 +02:00
parent 908f7441fe
commit d768c1c3e4
6 changed files with 22 additions and 20 deletions

View File

@ -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)
}

View File

@ -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)

View File

@ -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...)

View File

@ -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
})
}

View File

@ -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
})
}

View File

@ -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
}