github.com/mckael/restic@v0.8.3/cmd/restic/cleanup.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "os/signal" 7 "sync" 8 "syscall" 9 10 "github.com/restic/restic/internal/debug" 11 ) 12 13 var cleanupHandlers struct { 14 sync.Mutex 15 list []func() error 16 done bool 17 ch chan os.Signal 18 } 19 20 var stderr = os.Stderr 21 22 func init() { 23 cleanupHandlers.ch = make(chan os.Signal) 24 go CleanupHandler(cleanupHandlers.ch) 25 signal.Notify(cleanupHandlers.ch, syscall.SIGINT) 26 } 27 28 // AddCleanupHandler adds the function f to the list of cleanup handlers so 29 // that it is executed when all the cleanup handlers are run, e.g. when SIGINT 30 // is received. 31 func AddCleanupHandler(f func() error) { 32 cleanupHandlers.Lock() 33 defer cleanupHandlers.Unlock() 34 35 // reset the done flag for integration tests 36 cleanupHandlers.done = false 37 38 cleanupHandlers.list = append(cleanupHandlers.list, f) 39 } 40 41 // RunCleanupHandlers runs all registered cleanup handlers 42 func RunCleanupHandlers() { 43 cleanupHandlers.Lock() 44 defer cleanupHandlers.Unlock() 45 46 if cleanupHandlers.done { 47 return 48 } 49 cleanupHandlers.done = true 50 51 for _, f := range cleanupHandlers.list { 52 err := f() 53 if err != nil { 54 fmt.Fprintf(stderr, "error in cleanup handler: %v\n", err) 55 } 56 } 57 cleanupHandlers.list = nil 58 } 59 60 // CleanupHandler handles the SIGINT signals. 61 func CleanupHandler(c <-chan os.Signal) { 62 for s := range c { 63 debug.Log("signal %v received, cleaning up", s) 64 fmt.Fprintf(stderr, "%ssignal %v received, cleaning up\n", ClearLine(), s) 65 66 code := 0 67 if s != syscall.SIGINT { 68 code = 1 69 } 70 71 Exit(code) 72 } 73 } 74 75 // Exit runs the cleanup handlers and then terminates the process with the 76 // given exit code. 77 func Exit(code int) { 78 RunCleanupHandlers() 79 os.Exit(code) 80 }