mirror of
https://github.com/golang/sys.git
synced 2026-02-08 03:36:03 +03:00
windows/svc: make IsWindowsService handle parent exit
IsWindowsService fails when parent process has exited. This change makes IsWindowsService return false instead. Added a test to verify the change. Change-Id: Ibb2aa9478e8afd9e35011bbdc0985bdf8f0af9cc Reviewed-on: https://go-review.googlesource.com/c/sys/+/294729 TryBot-Result: Go Bot <gobot@golang.org> Run-TryBot: Alex Brainman <alex.brainman@gmail.com> Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com> Trust: Jason A. Donenfeld <Jason@zx2c4.com> Trust: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
@@ -96,6 +96,13 @@ func IsWindowsService() (bool, error) {
|
||||
var psid uint32
|
||||
err := windows.ProcessIdToSessionId(uint32(pbi[5]), &psid)
|
||||
if err != nil {
|
||||
if err == windows.ERROR_INVALID_PARAMETER {
|
||||
// This error happens when Windows cannot find process parent.
|
||||
// Perhaps process parent exited.
|
||||
// Assume we are not running in a service, because service
|
||||
// parent process (services.exe) cannot exit.
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
if psid != 0 {
|
||||
|
||||
@@ -171,3 +171,74 @@ func TestIsWindowsService(t *testing.T) {
|
||||
t.Error("IsWindowsService retuns true when not running in a service.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsWindowsServiceWhenParentExits(t *testing.T) {
|
||||
if os.Getenv("GO_WANT_HELPER_PROCESS") == "parent" {
|
||||
// in parent process
|
||||
|
||||
// Start the child and exit quickly.
|
||||
child := exec.Command(os.Args[0], "-test.run=TestIsWindowsServiceWhenParentExits")
|
||||
child.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=child")
|
||||
err := child.Start()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, fmt.Sprintf("child start failed: %v", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if os.Getenv("GO_WANT_HELPER_PROCESS") == "child" {
|
||||
// in child process
|
||||
dumpPath := os.Getenv("GO_WANT_HELPER_PROCESS_FILE")
|
||||
if dumpPath == "" {
|
||||
// We cannot report this error. But main test will notice
|
||||
// that we did not create dump file.
|
||||
os.Exit(1)
|
||||
}
|
||||
var msg string
|
||||
isSvc, err := svc.IsWindowsService()
|
||||
if err != nil {
|
||||
msg = err.Error()
|
||||
}
|
||||
if isSvc {
|
||||
msg = "IsWindowsService retuns true when not running in a service."
|
||||
}
|
||||
err = os.WriteFile(dumpPath, []byte(msg), 0644)
|
||||
if err != nil {
|
||||
// We cannot report this error. But main test will notice
|
||||
// that we did not create dump file.
|
||||
os.Exit(2)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Run in a loop until it fails.
|
||||
for i := 0; i < 10; i++ {
|
||||
childDumpPath := filepath.Join(t.TempDir(), "issvc.txt")
|
||||
|
||||
parent := exec.Command(os.Args[0], "-test.run=TestIsWindowsServiceWhenParentExits")
|
||||
parent.Env = append(os.Environ(),
|
||||
"GO_WANT_HELPER_PROCESS=parent",
|
||||
"GO_WANT_HELPER_PROCESS_FILE="+childDumpPath)
|
||||
parentOutput, err := parent.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("parent failed: %v: %v", err, string(parentOutput))
|
||||
}
|
||||
for i := 0; ; i++ {
|
||||
if _, err := os.Stat(childDumpPath); err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if i > 10 {
|
||||
t.Fatal("timed out waiting for child ouput file to be created.")
|
||||
}
|
||||
}
|
||||
childOutput, err := ioutil.ReadFile(childDumpPath)
|
||||
if err != nil {
|
||||
t.Fatalf("reading child ouput failed: %v", err)
|
||||
}
|
||||
if got, want := string(childOutput), ""; got != want {
|
||||
t.Fatalf("child output: want %q, got %q", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user