//go:build !windows package process import ( "errors" "os" "os/exec" "syscall" "golang.org/x/sys/unix" ) type scope struct { cmd *exec.Cmd terminal int foreground int } func newScope(cmd *exec.Cmd) (*scope, error) { if cmd.SysProcAttr == nil { cmd.SysProcAttr = &syscall.SysProcAttr{} } cmd.SysProcAttr.Setpgid = true cmd.SysProcAttr.Pgid = 0 s := &scope{cmd: cmd, terminal: -1} // A CLI tool that inherits our foreground terminal must be allowed to read // it (e.g. sudo). Web/TUI tools use null stdin and do not change the terminal. if input, ok := cmd.Stdin.(*os.File); ok { fd := int(input.Fd()) if group, err := unix.IoctlGetInt(fd, unix.TIOCGPGRP); err == nil && group == unix.Getpgrp() { s.terminal, s.foreground = fd, group cmd.SysProcAttr.Foreground = true cmd.SysProcAttr.Ctty = fd } } return s, nil } func (s *scope) attach() error { return nil } func (s *scope) resume() error { return nil } func (s *scope) kill() error { if s.cmd.Process == nil { return nil } err := unix.Kill(-s.cmd.Process.Pid, unix.SIGKILL) if errors.Is(err, unix.ESRCH) { return nil } return err } func (s *scope) close() { if s.terminal >= 0 { _ = unix.IoctlSetPointerInt(s.terminal, unix.TIOCSPGRP, s.foreground) } }