github.com/advanderveer/restic@v0.8.1-0.20171209104529-42a8c19aaea6/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  	InstallSignalHandler()
    26  }
    27  
    28  // InstallSignalHandler listens for SIGINT, and triggers the cleanup handlers.
    29  func InstallSignalHandler() {
    30  	signal.Notify(cleanupHandlers.ch, syscall.SIGINT)
    31  }
    32  
    33  // SuspendSignalHandler removes the signal handler for SIGINT.
    34  func SuspendSignalHandler() {
    35  	signal.Reset(syscall.SIGINT)
    36  }
    37  
    38  // AddCleanupHandler adds the function f to the list of cleanup handlers so
    39  // that it is executed when all the cleanup handlers are run, e.g. when SIGINT
    40  // is received.
    41  func AddCleanupHandler(f func() error) {
    42  	cleanupHandlers.Lock()
    43  	defer cleanupHandlers.Unlock()
    44  
    45  	// reset the done flag for integration tests
    46  	cleanupHandlers.done = false
    47  
    48  	cleanupHandlers.list = append(cleanupHandlers.list, f)
    49  }
    50  
    51  // RunCleanupHandlers runs all registered cleanup handlers
    52  func RunCleanupHandlers() {
    53  	cleanupHandlers.Lock()
    54  	defer cleanupHandlers.Unlock()
    55  
    56  	if cleanupHandlers.done {
    57  		return
    58  	}
    59  	cleanupHandlers.done = true
    60  
    61  	for _, f := range cleanupHandlers.list {
    62  		err := f()
    63  		if err != nil {
    64  			fmt.Fprintf(stderr, "error in cleanup handler: %v\n", err)
    65  		}
    66  	}
    67  	cleanupHandlers.list = nil
    68  }
    69  
    70  // CleanupHandler handles the SIGINT signals.
    71  func CleanupHandler(c <-chan os.Signal) {
    72  	for s := range c {
    73  		debug.Log("signal %v received, cleaning up", s)
    74  		fmt.Fprintf(stderr, "%ssignal %v received, cleaning up\n", ClearLine(), s)
    75  
    76  		code := 0
    77  		if s != syscall.SIGINT {
    78  			code = 1
    79  		}
    80  
    81  		Exit(code)
    82  	}
    83  }
    84  
    85  // Exit runs the cleanup handlers and then terminates the process with the
    86  // given exit code.
    87  func Exit(code int) {
    88  	RunCleanupHandlers()
    89  	os.Exit(code)
    90  }