mirror of
https://github.com/octoleo/restic.git
synced 2024-11-29 00:06:32 +00:00
Fix shutdown hang when restic is started as background job
restic uses a cleanup hook to ensure that it restores the terminal configuration to a sane state, when restic is interrupted while reading a password from the terminal. However, this causes a problem, when restic runs in a background job, as reconfiguring a terminal will cause a SIGTTOU to be sent to restic pausing it. Therefore, restic seems to hang on shutdown when it was running in the background. This commit changes the behavior to only restore the terminal configuration if restic was interrupted while reading a password from the terminal. As reading a password from the terminal requires that restic is in the foreground, this should avoid restic getting stopped. Fixes #2298 Issue introduced in #402
This commit is contained in:
parent
5a7c27ddb6
commit
1a1c572bac
@ -85,6 +85,8 @@ var globalOptions = GlobalOptions{
|
|||||||
stderr: os.Stderr,
|
stderr: os.Stderr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isReadingPassword bool
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
globalOptions.ctx, cancel = context.WithCancel(context.Background())
|
globalOptions.ctx, cancel = context.WithCancel(context.Background())
|
||||||
@ -146,7 +148,10 @@ func stdoutTerminalWidth() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// restoreTerminal installs a cleanup handler that restores the previous
|
// restoreTerminal installs a cleanup handler that restores the previous
|
||||||
// terminal state on exit.
|
// terminal state on exit. This handler is only intended to restore the
|
||||||
|
// terminal configuration if restic exits after receiving a signal. A regular
|
||||||
|
// program execution must revert changes to the terminal configuration itself.
|
||||||
|
// The terminal configuration is only restored while reading a password.
|
||||||
func restoreTerminal() {
|
func restoreTerminal() {
|
||||||
if !stdoutIsTerminal() {
|
if !stdoutIsTerminal() {
|
||||||
return
|
return
|
||||||
@ -160,9 +165,17 @@ func restoreTerminal() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AddCleanupHandler(func() error {
|
AddCleanupHandler(func() error {
|
||||||
|
// Restoring the terminal configuration while restic runs in the
|
||||||
|
// background, causes restic to get stopped on unix systems with
|
||||||
|
// a SIGTTOU signal. Thus only restore the terminal settings if
|
||||||
|
// they might have been modified, which is the case while reading
|
||||||
|
// a password.
|
||||||
|
if !isReadingPassword {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
err := checkErrno(terminal.Restore(fd, state))
|
err := checkErrno(terminal.Restore(fd, state))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "unable to get restore terminal state: %#+v\n", err)
|
fmt.Fprintf(os.Stderr, "unable to restore terminal state: %v\n", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
@ -302,7 +315,9 @@ func readPassword(in io.Reader) (password string, err error) {
|
|||||||
// password.
|
// password.
|
||||||
func readPasswordTerminal(in *os.File, out io.Writer, prompt string) (password string, err error) {
|
func readPasswordTerminal(in *os.File, out io.Writer, prompt string) (password string, err error) {
|
||||||
fmt.Fprint(out, prompt)
|
fmt.Fprint(out, prompt)
|
||||||
|
isReadingPassword = true
|
||||||
buf, err := terminal.ReadPassword(int(in.Fd()))
|
buf, err := terminal.ReadPassword(int(in.Fd()))
|
||||||
|
isReadingPassword = false
|
||||||
fmt.Fprintln(out)
|
fmt.Fprintln(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "ReadPassword")
|
return "", errors.Wrap(err, "ReadPassword")
|
||||||
|
Loading…
Reference in New Issue
Block a user