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 { var cleanupHandlers struct {
sync.Mutex sync.Mutex
list []func() error list []func(code int) (int, error)
done bool done bool
ch chan os.Signal ch chan os.Signal
} }
@ -25,7 +25,7 @@ func init() {
// AddCleanupHandler adds the function f to the list of cleanup handlers so // 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 // that it is executed when all the cleanup handlers are run, e.g. when SIGINT
// is received. // is received.
func AddCleanupHandler(f func() error) { func AddCleanupHandler(f func(code int) (int, error)) {
cleanupHandlers.Lock() cleanupHandlers.Lock()
defer cleanupHandlers.Unlock() defer cleanupHandlers.Unlock()
@ -36,22 +36,24 @@ func AddCleanupHandler(f func() error) {
} }
// RunCleanupHandlers runs all registered cleanup handlers // RunCleanupHandlers runs all registered cleanup handlers
func RunCleanupHandlers() { func RunCleanupHandlers(code int) int {
cleanupHandlers.Lock() cleanupHandlers.Lock()
defer cleanupHandlers.Unlock() defer cleanupHandlers.Unlock()
if cleanupHandlers.done { if cleanupHandlers.done {
return return code
} }
cleanupHandlers.done = true cleanupHandlers.done = true
for _, f := range cleanupHandlers.list { for _, f := range cleanupHandlers.list {
err := f() var err error
code, err = f(code)
if err != nil { if err != nil {
Warnf("error in cleanup handler: %v\n", err) Warnf("error in cleanup handler: %v\n", err)
} }
} }
cleanupHandlers.list = nil cleanupHandlers.list = nil
return code
} }
// CleanupHandler handles the SIGINT signals. // 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 // Exit runs the cleanup handlers and then terminates the process with the
// given exit code. // given exit code.
func Exit(code int) { func Exit(code int) {
RunCleanupHandlers() code = RunCleanupHandlers(code)
os.Exit(code) os.Exit(code)
} }

View File

@ -197,9 +197,9 @@ func runCheck(opts CheckOptions, gopts GlobalOptions, args []string) error {
} }
cleanup := prepareCheckCache(opts, &gopts) cleanup := prepareCheckCache(opts, &gopts)
AddCleanupHandler(func() error { AddCleanupHandler(func(code int) (int, error) {
cleanup() cleanup()
return nil return code, nil
}) })
repo, err := OpenRepository(gopts) 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) debug.Log("running umount cleanup handler for mount at %v", mountpoint)
err := umount(mountpoint) err := umount(mountpoint)
if err != nil { if err != nil {
Warnf("unable to umount (maybe already umounted or still in use?): %v\n", err) 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...) c, err := systemFuse.Mount(mountpoint, mountOptions...)

View File

@ -97,11 +97,11 @@ var isReadingPassword bool
func init() { func init() {
var cancel context.CancelFunc var cancel context.CancelFunc
globalOptions.ctx, cancel = context.WithCancel(context.Background()) 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 // 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 // not blocked due to limited number of backend connections, see #1434
cancel() cancel()
return nil return code, nil
}) })
f := cmdRoot.PersistentFlags() f := cmdRoot.PersistentFlags()
@ -199,20 +199,20 @@ func restoreTerminal() {
return return
} }
AddCleanupHandler(func() error { AddCleanupHandler(func(code int) (int, error) {
// Restoring the terminal configuration while restic runs in the // Restoring the terminal configuration while restic runs in the
// background, causes restic to get stopped on unix systems with // background, causes restic to get stopped on unix systems with
// a SIGTTOU signal. Thus only restore the terminal settings if // a SIGTTOU signal. Thus only restore the terminal settings if
// they might have been modified, which is the case while reading // they might have been modified, which is the case while reading
// a password. // a password.
if !isReadingPassword { if !isReadingPassword {
return nil return code, nil
} }
err := checkErrno(term.Restore(fd, state)) err := checkErrno(term.Restore(fd, state))
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "unable to restore terminal state: %v\n", err) 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 { if prof != nil {
AddCleanupHandler(func() error { AddCleanupHandler(func(code int) (int, error) {
prof.Stop() 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) 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() globalLocks.Lock()
defer globalLocks.Unlock() defer globalLocks.Unlock()
@ -127,11 +127,11 @@ func unlockAll() error {
for _, lock := range globalLocks.locks { for _, lock := range globalLocks.locks {
if err := lock.Unlock(); err != nil { if err := lock.Unlock(); err != nil {
debug.Log("error while unlocking: %v", err) debug.Log("error while unlocking: %v", err)
return err return code, err
} }
debug.Log("successfully removed lock") debug.Log("successfully removed lock")
} }
globalLocks.locks = globalLocks.locks[:0] globalLocks.locks = globalLocks.locks[:0]
return nil return code, nil
} }