From 4c19d6410fb024c0bf0bc3be46ad6774aaa0810b Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 11 Apr 2025 23:54:02 +0200 Subject: [PATCH] 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() +}