diff --git a/cli/connhelper/commandconn/commandconn_unix_test.go b/cli/connhelper/commandconn/commandconn_unix_test.go index 6c1219f4386e..b68ebe7bf4bb 100644 --- a/cli/connhelper/commandconn/commandconn_unix_test.go +++ b/cli/connhelper/commandconn/commandconn_unix_test.go @@ -4,12 +4,17 @@ package commandconn import ( "context" + "errors" "io" "io/fs" + "os" + "path/filepath" + "runtime" + "strconv" + "syscall" "testing" "time" - "github.com/docker/docker/pkg/process" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) @@ -51,16 +56,16 @@ func TestCloseRunningCommand(t *testing.T) { c, err := New(ctx, "sh", "-c", "while true; do sleep 1; done") assert.NilError(t, err) cmdConn := c.(*commandConn) - assert.Check(t, process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, processAlive(cmdConn.cmd.Process.Pid)) n, err := c.Write([]byte("hello")) assert.Check(t, is.Equal(len("hello"), n)) assert.NilError(t, err) - assert.Check(t, process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, processAlive(cmdConn.cmd.Process.Pid)) err = cmdConn.Close() assert.NilError(t, err) - assert.Check(t, !process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, !processAlive(cmdConn.cmd.Process.Pid)) done <- struct{}{} }() @@ -79,7 +84,7 @@ func TestCloseTwice(t *testing.T) { c, err := New(ctx, "sh", "-c", "echo hello; sleep 1; exit 0") assert.NilError(t, err) cmdConn := c.(*commandConn) - assert.Check(t, process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, processAlive(cmdConn.cmd.Process.Pid)) b := make([]byte, 32) n, err := c.Read(b) @@ -88,11 +93,11 @@ func TestCloseTwice(t *testing.T) { err = cmdConn.Close() assert.NilError(t, err) - assert.Check(t, !process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, !processAlive(cmdConn.cmd.Process.Pid)) err = cmdConn.Close() assert.NilError(t, err) - assert.Check(t, !process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, !processAlive(cmdConn.cmd.Process.Pid)) done <- struct{}{} }() @@ -111,7 +116,7 @@ func TestEOFTimeout(t *testing.T) { c, err := New(ctx, "sh", "-c", "sleep 20") assert.NilError(t, err) cmdConn := c.(*commandConn) - assert.Check(t, process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, processAlive(cmdConn.cmd.Process.Pid)) cmdConn.stdout = mockStdoutEOF{} @@ -148,7 +153,7 @@ func TestCloseWhileWriting(t *testing.T) { c, err := New(ctx, "sh", "-c", "while true; do sleep 1; done") assert.NilError(t, err) cmdConn := c.(*commandConn) - assert.Check(t, process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, processAlive(cmdConn.cmd.Process.Pid)) writeErrC := make(chan error) go func() { @@ -164,7 +169,7 @@ func TestCloseWhileWriting(t *testing.T) { err = c.Close() assert.NilError(t, err) - assert.Check(t, !process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, !processAlive(cmdConn.cmd.Process.Pid)) writeErr := <-writeErrC assert.ErrorContains(t, writeErr, "file already closed") @@ -176,7 +181,7 @@ func TestCloseWhileReading(t *testing.T) { c, err := New(ctx, "sh", "-c", "while true; do sleep 1; done") assert.NilError(t, err) cmdConn := c.(*commandConn) - assert.Check(t, process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, processAlive(cmdConn.cmd.Process.Pid)) readErrC := make(chan error) go func() { @@ -193,8 +198,37 @@ func TestCloseWhileReading(t *testing.T) { err = cmdConn.Close() assert.NilError(t, err) - assert.Check(t, !process.Alive(cmdConn.cmd.Process.Pid)) + assert.Check(t, !processAlive(cmdConn.cmd.Process.Pid)) readErr := <-readErrC assert.Check(t, is.ErrorIs(readErr, fs.ErrClosed)) } + +// processAlive returns true if a process with a given pid is running. It only considers +// positive PIDs; 0 (all processes in the current process group), -1 (all processes +// with a PID larger than 1), and negative (-n, all processes in process group +// "n") values for pid are never considered to be alive. +// +// It was forked from https://github.com/moby/moby/blob/v28.3.3/pkg/process/process_unix.go#L17-L42 +func processAlive(pid int) bool { + if pid < 1 { + return false + } + switch runtime.GOOS { + case "darwin": + // OS X does not have a proc filesystem. Use kill -0 pid to judge if the + // process exists. From KILL(2): https://www.freebsd.org/cgi/man.cgi?query=kill&sektion=2&manpath=OpenDarwin+7.2.1 + // + // Sig may be one of the signals specified in sigaction(2) or it may + // be 0, in which case error checking is performed but no signal is + // actually sent. This can be used to check the validity of pid. + err := syscall.Kill(pid, 0) + + // Either the PID was found (no error), or we get an EPERM, which means + // the PID exists, but we don't have permissions to signal it. + return err == nil || errors.Is(err, syscall.EPERM) + default: + _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))) + return err == nil + } +} diff --git a/vendor/github.com/docker/docker/pkg/process/doc.go b/vendor/github.com/docker/docker/pkg/process/doc.go deleted file mode 100644 index dae536d7dbb0..000000000000 --- a/vendor/github.com/docker/docker/pkg/process/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -// Package process provides a set of basic functions to manage individual -// processes. -package process diff --git a/vendor/github.com/docker/docker/pkg/process/process_unix.go b/vendor/github.com/docker/docker/pkg/process/process_unix.go deleted file mode 100644 index 13298bbdccb7..000000000000 --- a/vendor/github.com/docker/docker/pkg/process/process_unix.go +++ /dev/null @@ -1,82 +0,0 @@ -//go:build !windows - -package process - -import ( - "bytes" - "errors" - "fmt" - "os" - "path/filepath" - "runtime" - "strconv" - - "golang.org/x/sys/unix" -) - -// Alive returns true if process with a given pid is running. It only considers -// positive PIDs; 0 (all processes in the current process group), -1 (all processes -// with a PID larger than 1), and negative (-n, all processes in process group -// "n") values for pid are never considered to be alive. -func Alive(pid int) bool { - if pid < 1 { - return false - } - switch runtime.GOOS { - case "darwin": - // OS X does not have a proc filesystem. Use kill -0 pid to judge if the - // process exists. From KILL(2): https://www.freebsd.org/cgi/man.cgi?query=kill&sektion=2&manpath=OpenDarwin+7.2.1 - // - // Sig may be one of the signals specified in sigaction(2) or it may - // be 0, in which case error checking is performed but no signal is - // actually sent. This can be used to check the validity of pid. - err := unix.Kill(pid, 0) - - // Either the PID was found (no error) or we get an EPERM, which means - // the PID exists, but we don't have permissions to signal it. - return err == nil || errors.Is(err, unix.EPERM) - default: - _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))) - return err == nil - } -} - -// Kill force-stops a process. It only considers positive PIDs; 0 (all processes -// in the current process group), -1 (all processes with a PID larger than 1), -// and negative (-n, all processes in process group "n") values for pid are -// ignored. Refer to [KILL(2)] for details. -// -// [KILL(2)]: https://man7.org/linux/man-pages/man2/kill.2.html -func Kill(pid int) error { - if pid < 1 { - return fmt.Errorf("invalid PID (%d): only positive PIDs are allowed", pid) - } - err := unix.Kill(pid, unix.SIGKILL) - if err != nil && !errors.Is(err, unix.ESRCH) { - return err - } - return nil -} - -// Zombie return true if process has a state with "Z". It only considers positive -// PIDs; 0 (all processes in the current process group), -1 (all processes with -// a PID larger than 1), and negative (-n, all processes in process group "n") -// values for pid are ignored. Refer to [PROC(5)] for details. -// -// [PROC(5)]: https://man7.org/linux/man-pages/man5/proc.5.html -func Zombie(pid int) (bool, error) { - if pid < 1 { - return false, nil - } - data, err := os.ReadFile(fmt.Sprintf("/proc/%d/stat", pid)) - if err != nil { - if os.IsNotExist(err) { - return false, nil - } - return false, err - } - if cols := bytes.SplitN(data, []byte(" "), 4); len(cols) >= 3 && string(cols[2]) == "Z" { - return true, nil - } - return false, nil -} diff --git a/vendor/github.com/docker/docker/pkg/process/process_windows.go b/vendor/github.com/docker/docker/pkg/process/process_windows.go deleted file mode 100644 index 2dd57e825452..000000000000 --- a/vendor/github.com/docker/docker/pkg/process/process_windows.go +++ /dev/null @@ -1,45 +0,0 @@ -package process - -import ( - "os" - - "golang.org/x/sys/windows" -) - -// Alive returns true if process with a given pid is running. -func Alive(pid int) bool { - h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid)) - if err != nil { - return false - } - var c uint32 - err = windows.GetExitCodeProcess(h, &c) - _ = windows.CloseHandle(h) - if err != nil { - // From the GetExitCodeProcess function (processthreadsapi.h) API docs: - // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess - // - // The GetExitCodeProcess function returns a valid error code defined by the - // application only after the thread terminates. Therefore, an application should - // not use STILL_ACTIVE (259) as an error code (STILL_ACTIVE is a macro for - // STATUS_PENDING (minwinbase.h)). If a thread returns STILL_ACTIVE (259) as - // an error code, then applications that test for that value could interpret it - // to mean that the thread is still running, and continue to test for the - // completion of the thread after the thread has terminated, which could put - // the application into an infinite loop. - return c == uint32(windows.STATUS_PENDING) - } - return true -} - -// Kill force-stops a process. -func Kill(pid int) error { - p, err := os.FindProcess(pid) - if err == nil { - err = p.Kill() - if err != nil && err != os.ErrProcessDone { - return err - } - } - return nil -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 037c93d3bec6..d80b643dc479 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -96,7 +96,6 @@ github.com/docker/docker/internal/lazyregexp github.com/docker/docker/internal/multierror github.com/docker/docker/pkg/homedir github.com/docker/docker/pkg/jsonmessage -github.com/docker/docker/pkg/process github.com/docker/docker/pkg/progress github.com/docker/docker/pkg/stdcopy github.com/docker/docker/pkg/streamformatter