mirror of
https://github.com/restic/restic.git
synced 2025-12-11 18:47:50 +00:00
backend,termstatus: Unify foreground/background detection
PR #5358 reintroduced a version of the TIOCGPGRP ioctl call that works on all Unix platforms except Linux, due to a bug/inconsistency in x/sys/unix. This commit fixes that by introducing termstatus.Tcgetpgrp. It also introduces termstatus.Getpgrp and termstatus.Tcsetpgrp to deal with the different signature of unix.Getpgrp in Solaris vs. all other Unix platforms and an int-overflowing constant on AIX, so that some AIX/Solaris-specific code can be removed elsewhere and foreground/background detection is done the same everywhere except on Windows.
This commit is contained in:
@@ -1,27 +0,0 @@
|
||||
package termstatus
|
||||
|
||||
import (
|
||||
"github.com/restic/restic/internal/debug"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// IsProcessBackground reports whether the current process is running in the
|
||||
// background. fd must be a file descriptor for the terminal.
|
||||
func IsProcessBackground(fd uintptr) bool {
|
||||
bg, err := isProcessBackground(fd)
|
||||
if err != nil {
|
||||
debug.Log("Can't check if we are in the background. Using default behaviour. Error: %s\n", err.Error())
|
||||
return false
|
||||
}
|
||||
return bg
|
||||
}
|
||||
|
||||
func isProcessBackground(fd uintptr) (bool, error) {
|
||||
// We need to use IoctlGetUint32 here, because pid_t is 32-bit even on
|
||||
// 64-bit Linux. IoctlGetInt doesn't work on big-endian platforms:
|
||||
// https://github.com/golang/go/issues/45585
|
||||
// https://github.com/golang/go/issues/60429
|
||||
pid, err := unix.IoctlGetUint32(int(fd), unix.TIOCGPGRP)
|
||||
return int(pid) != unix.Getpgrp(), err
|
||||
}
|
||||
24
internal/ui/termstatus/background_unix.go
Normal file
24
internal/ui/termstatus/background_unix.go
Normal file
@@ -0,0 +1,24 @@
|
||||
//go:build unix
|
||||
|
||||
package termstatus
|
||||
|
||||
import "github.com/restic/restic/internal/debug"
|
||||
|
||||
// IsProcessBackground reports whether the current process is running in the
|
||||
// background. fd must be a file descriptor for the terminal.
|
||||
func IsProcessBackground(fd uintptr) bool {
|
||||
bg, err := isProcessBackground(int(fd))
|
||||
if err != nil {
|
||||
debug.Log("Can't check if we are in the background. Using default behaviour. Error: %s\n", err.Error())
|
||||
return false
|
||||
}
|
||||
return bg
|
||||
}
|
||||
|
||||
func isProcessBackground(fd int) (bg bool, err error) {
|
||||
pgid, err := Tcgetpgrp(fd)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return pgid != Getpgrp(), nil
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build unix
|
||||
|
||||
package termstatus
|
||||
|
||||
import (
|
||||
@@ -13,7 +15,7 @@ func TestIsProcessBackground(t *testing.T) {
|
||||
t.Skipf("can't open terminal: %v", err)
|
||||
}
|
||||
|
||||
_, err = isProcessBackground(tty.Fd())
|
||||
_, err = isProcessBackground(int(tty.Fd()))
|
||||
rtest.OK(t, err)
|
||||
|
||||
_ = tty.Close()
|
||||
@@ -1,6 +1,3 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package termstatus
|
||||
|
||||
// IsProcessBackground reports whether the current process is running in the
|
||||
8
internal/ui/termstatus/getpgrp_solaris.go
Normal file
8
internal/ui/termstatus/getpgrp_solaris.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package termstatus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func Getpgrp() int {
|
||||
pid, _ := unix.Getpgrp()
|
||||
return pid
|
||||
}
|
||||
7
internal/ui/termstatus/getpgrp_unix.go
Normal file
7
internal/ui/termstatus/getpgrp_unix.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build unix && !solaris
|
||||
|
||||
package termstatus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func Getpgrp() int { return unix.Getpgrp() }
|
||||
12
internal/ui/termstatus/tcgetpgrp_linux.go
Normal file
12
internal/ui/termstatus/tcgetpgrp_linux.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package termstatus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func Tcgetpgrp(ttyfd int) (int, error) {
|
||||
// We need to use IoctlGetUint32 here, because pid_t is 32-bit even on
|
||||
// 64-bit Linux. IoctlGetInt doesn't work on big-endian platforms:
|
||||
// https://github.com/golang/go/issues/45585
|
||||
// https://github.com/golang/go/issues/60429
|
||||
pid, err := unix.IoctlGetUint32(ttyfd, unix.TIOCGPGRP)
|
||||
return int(pid), err
|
||||
}
|
||||
9
internal/ui/termstatus/tcgetpgrp_unix.go
Normal file
9
internal/ui/termstatus/tcgetpgrp_unix.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build unix && !linux
|
||||
|
||||
package termstatus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func Tcgetpgrp(ttyfd int) (int, error) {
|
||||
return unix.IoctlGetInt(ttyfd, unix.TIOCGPGRP)
|
||||
}
|
||||
10
internal/ui/termstatus/tcsetpgrp_aix.go
Normal file
10
internal/ui/termstatus/tcsetpgrp_aix.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package termstatus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func Tcsetpgrp(fd int, pid int) error {
|
||||
// The second argument to IoctlSetPointerInt has type int on AIX,
|
||||
// but the constant overflows 64-bit int, hence the two-step cast.
|
||||
req := uint(unix.TIOCSPGRP)
|
||||
return unix.IoctlSetPointerInt(fd, int(req), pid)
|
||||
}
|
||||
9
internal/ui/termstatus/tcsetpgrp_unix.go
Normal file
9
internal/ui/termstatus/tcsetpgrp_unix.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build unix && !aix
|
||||
|
||||
package termstatus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func Tcsetpgrp(fd int, pid int) error {
|
||||
return unix.IoctlSetPointerInt(fd, unix.TIOCSPGRP, pid)
|
||||
}
|
||||
Reference in New Issue
Block a user