From 306a29980a272891387d53ede50a2f83df7dcfda Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 23 Apr 2023 14:56:36 +0200 Subject: [PATCH] Print stacktrace in SIGINT handler if RESTIC_DEBUG_STACKTRACE_SIGINT set The builtin mechanism to capture a stacktrace in Go is to send a SIGQUIT to the running process. However, this mechanism is not avaiable on Windows. Thus, tweak the SIGINT handler to dump a stacktrace if the environment variable `RESTIC_DEBUG_STACKTRACE_SIGINT` is set. --- CONTRIBUTING.md | 10 ++++++++++ cmd/restic/cleanup.go | 6 ++++++ internal/debug/stacktrace.go | 15 +++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 internal/debug/stacktrace.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4b4be0757..36a7c0695 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,6 +58,16 @@ Please be aware that the debug log file will contain potentially sensitive things like file and directory names, so please either redact it before uploading it somewhere or post only the parts that are really relevant. +If restic gets stuck, please also include a stacktrace in the description. +On non-Windows systems, you can send a SIGQUIT signal to restic or press +`Ctrl-\` to achieve the same result. This causes restic to print a stacktrace +and then exit immediatelly. This will not damage your repository, however, +it might be necessary to manually clean up stale lock files using +`restic unlock`. + +On Windows, please set the environment variable `RESTIC_DEBUG_STACKTRACE_SIGINT` +to `true` and press `Ctrl-C` to create a stacktrace. + Development Environment ======================= diff --git a/cmd/restic/cleanup.go b/cmd/restic/cleanup.go index 967957106..75933fe96 100644 --- a/cmd/restic/cleanup.go +++ b/cmd/restic/cleanup.go @@ -62,6 +62,12 @@ func CleanupHandler(c <-chan os.Signal) { debug.Log("signal %v received, cleaning up", s) Warnf("%ssignal %v received, cleaning up\n", clearLine(0), s) + if val, _ := os.LookupEnv("RESTIC_DEBUG_STACKTRACE_SIGINT"); val != "" { + _, _ = os.Stderr.WriteString("\n--- STACKTRACE START ---\n\n") + _, _ = os.Stderr.WriteString(debug.DumpStacktrace()) + _, _ = os.Stderr.WriteString("\n--- STACKTRACE END ---\n") + } + code := 0 if s == syscall.SIGINT { diff --git a/internal/debug/stacktrace.go b/internal/debug/stacktrace.go new file mode 100644 index 000000000..a8db83160 --- /dev/null +++ b/internal/debug/stacktrace.go @@ -0,0 +1,15 @@ +package debug + +import "runtime" + +func DumpStacktrace() string { + buf := make([]byte, 128*1024) + + for { + l := runtime.Stack(buf, true) + if l < len(buf) { + return string(buf[:l]) + } + buf = make([]byte, len(buf)*2) + } +}