From 4c19d6410fb024c0bf0bc3be46ad6774aaa0810b Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 11 Apr 2025 23:54:02 +0200 Subject: [PATCH 1/3] backend: only move child process to foreground if already in foreground The rclone and sftp backends require starting a child process. The are first moved into the foreground and back into the background after the initial startup is done. However, this behavior is also active if restic itself is started in the background. In this case, restic changing the foreground process may confuse the shell and in case of bash causes it to exit. Thus, disable modification of the controlling process group of the tty if restic is run in the background. --- internal/backend/util/foreground_unix.go | 34 ++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/internal/backend/util/foreground_unix.go b/internal/backend/util/foreground_unix.go index 082b7f59b..b60a19c44 100644 --- a/internal/backend/util/foreground_unix.go +++ b/internal/backend/util/foreground_unix.go @@ -14,6 +14,10 @@ import ( "golang.org/x/sys/unix" ) +func tcgetpgrp(fd int) (int, error) { + return unix.IoctlGetInt(fd, unix.TIOCGPGRP) +} + func tcsetpgrp(fd int, pid int) error { // IoctlSetPointerInt silently casts to int32 internally, // so this assumes pid fits in 31 bits. @@ -25,12 +29,26 @@ func startForeground(cmd *exec.Cmd) (bg func() error, err error) { tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) if err != nil { debug.Log("unable to open tty: %v", err) - bg = func() error { - return nil - } - return bg, cmd.Start() + return startFallback(cmd) } + // only move child process to foreground if restic is in the foreground + prev, err := tcgetpgrp(int(tty.Fd())) + if err != nil { + _ = tty.Close() + return nil, err + } + + self := unix.Getpgrp() + if prev != self { + debug.Log("restic is not controlling the tty") + if err := tty.Close(); err != nil { + return nil, err + } + return startFallback(cmd) + } + + // Prevent getting suspended when interacting with the tty signal.Ignore(unix.SIGTTIN) signal.Ignore(unix.SIGTTOU) @@ -47,7 +65,6 @@ func startForeground(cmd *exec.Cmd) (bg func() error, err error) { } // move the command's process group into the foreground - prev := unix.Getpgrp() err = tcsetpgrp(int(tty.Fd()), cmd.Process.Pid) if err != nil { _ = tty.Close() @@ -70,3 +87,10 @@ func startForeground(cmd *exec.Cmd) (bg func() error, err error) { return bg, nil } + +func startFallback(cmd *exec.Cmd) (bg func() error, err error) { + bg = func() error { + return nil + } + return bg, cmd.Start() +} From 914bd699be2d050da7acb3dd3fb42a7478b20c16 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Mon, 14 Apr 2025 20:18:58 +0200 Subject: [PATCH 2/3] backend: always start backend process in separate process group The process group is necessary to properly handle ctrl-c. --- internal/backend/util/foreground_unix.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/internal/backend/util/foreground_unix.go b/internal/backend/util/foreground_unix.go index b60a19c44..cba22ab26 100644 --- a/internal/backend/util/foreground_unix.go +++ b/internal/backend/util/foreground_unix.go @@ -25,6 +25,12 @@ func tcsetpgrp(fd int, pid int) error { } func startForeground(cmd *exec.Cmd) (bg func() error, err error) { + // run the command in its own process group + // this ensures that sending ctrl-c to restic will not immediately stop the backend process. + cmd.SysProcAttr = &unix.SysProcAttr{ + Setpgid: true, + } + // open the TTY, we need the file descriptor tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) if err != nil { @@ -52,11 +58,6 @@ func startForeground(cmd *exec.Cmd) (bg func() error, err error) { signal.Ignore(unix.SIGTTIN) signal.Ignore(unix.SIGTTOU) - // run the command in its own process group - cmd.SysProcAttr = &unix.SysProcAttr{ - Setpgid: true, - } - // start the process err = cmd.Start() if err != nil { @@ -92,5 +93,6 @@ func startFallback(cmd *exec.Cmd) (bg func() error, err error) { bg = func() error { return nil } + return bg, cmd.Start() } From 42f690dbab75ec7c3d7196d37cb31325706192a9 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 6 Sep 2025 19:51:05 +0200 Subject: [PATCH 3/3] add changelog --- changelog/unreleased/issue-5354 | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 changelog/unreleased/issue-5354 diff --git a/changelog/unreleased/issue-5354 b/changelog/unreleased/issue-5354 new file mode 100644 index 000000000..1fbda9077 --- /dev/null +++ b/changelog/unreleased/issue-5354 @@ -0,0 +1,12 @@ +Bugfix: Allow use of rclone/sftp backend when running restic in background + +When starting restic in the background, this could result in unexpected behavior +when using the rclone or sftp backend. + +For example running `restic -r rclone:./example --insecure-no-password init &` +could cause the calling `bash` shell to exit unexpectedly. + +This has been fixed. + +https://github.com/restic/restic/issues/5354 +https://github.com/restic/restic/pull/5358