diff --git a/pkg/pidfile/pidfile.go b/pkg/pidfile/pidfile.go index 14773b653f..09a415b11a 100644 --- a/pkg/pidfile/pidfile.go +++ b/pkg/pidfile/pidfile.go @@ -10,6 +10,7 @@ import ( "path/filepath" "strconv" + "github.com/docker/docker/pkg/process" "github.com/docker/docker/pkg/system" ) @@ -22,7 +23,7 @@ func checkPIDFileAlreadyExists(path string) error { return err } pid, err := strconv.Atoi(string(bytes.TrimSpace(pidByte))) - if err == nil && processExists(pid) { + if err == nil && process.Alive(pid) { return fmt.Errorf("pid file found, ensure docker is not running or delete %s", path) } return nil diff --git a/pkg/pidfile/pidfile_darwin.go b/pkg/pidfile/pidfile_darwin.go deleted file mode 100644 index 943183d682..0000000000 --- a/pkg/pidfile/pidfile_darwin.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build darwin -// +build darwin - -package pidfile // import "github.com/docker/docker/pkg/pidfile" - -import ( - "golang.org/x/sys/unix" -) - -func processExists(pid int) bool { - // OS X does not have a proc filesystem. - // Use kill -0 pid to judge if the process exists. - err := unix.Kill(pid, 0) - return err == nil -} diff --git a/pkg/pidfile/pidfile_unix.go b/pkg/pidfile/pidfile_unix.go deleted file mode 100644 index bcf9ebcac2..0000000000 --- a/pkg/pidfile/pidfile_unix.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build !windows && !darwin -// +build !windows,!darwin - -package pidfile // import "github.com/docker/docker/pkg/pidfile" - -import ( - "os" - "path/filepath" - "strconv" -) - -func processExists(pid int) bool { - if _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))); err == nil { - return true - } - return false -} diff --git a/pkg/pidfile/pidfile_windows.go b/pkg/pidfile/pidfile_windows.go deleted file mode 100644 index cc22ba4fd2..0000000000 --- a/pkg/pidfile/pidfile_windows.go +++ /dev/null @@ -1,30 +0,0 @@ -package pidfile // import "github.com/docker/docker/pkg/pidfile" - -import ( - "golang.org/x/sys/windows" -) - -func processExists(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 -} diff --git a/pkg/process/process_unix.go b/pkg/process/process_unix.go index 109b56f56c..6057434fa5 100644 --- a/pkg/process/process_unix.go +++ b/pkg/process/process_unix.go @@ -1,5 +1,5 @@ -//go:build linux || freebsd || darwin -// +build linux freebsd darwin +//go:build !windows +// +build !windows package process @@ -7,18 +7,32 @@ import ( "bytes" "fmt" "os" + "path/filepath" + "runtime" + "strconv" "golang.org/x/sys/unix" ) // Alive returns true if process with a given pid is running. func Alive(pid int) bool { - err := unix.Kill(pid, 0) - if err == nil || err == unix.EPERM { - return true - } + 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) - return false + // 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 || err == unix.EPERM + default: + _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))) + return err == nil + } } // Kill force-stops a process. diff --git a/pkg/process/process_windows.go b/pkg/process/process_windows.go index 8de3362c72..26158d09ec 100644 --- a/pkg/process/process_windows.go +++ b/pkg/process/process_windows.go @@ -1,12 +1,35 @@ package process -import "os" +import ( + "os" + + "golang.org/x/sys/windows" +) // Alive returns true if process with a given pid is running. func Alive(pid int) bool { - _, err := os.FindProcess(pid) - - return err == nil + 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.