github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/os/exec_posix.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build unix || (js && wasm) || wasip1 || windows 6 7 package os 8 9 import ( 10 "internal/itoa" 11 "internal/syscall/execenv" 12 "runtime" 13 "syscall" 14 ) 15 16 // The only signal values guaranteed to be present in the os package on all 17 // systems are os.Interrupt (send the process an interrupt) and os.Kill (force 18 // the process to exit). On Windows, sending os.Interrupt to a process with 19 // os.Process.Signal is not implemented; it will return an error instead of 20 // sending a signal. 21 var ( 22 Interrupt Signal = syscall.SIGINT 23 Kill Signal = syscall.SIGKILL 24 ) 25 26 func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { 27 // If there is no SysProcAttr (ie. no Chroot or changed 28 // UID/GID), double-check existence of the directory we want 29 // to chdir into. We can make the error clearer this way. 30 if attr != nil && attr.Sys == nil && attr.Dir != "" { 31 if _, err := Stat(attr.Dir); err != nil { 32 pe := err.(*PathError) 33 pe.Op = "chdir" 34 return nil, pe 35 } 36 } 37 38 sysattr := &syscall.ProcAttr{ 39 Dir: attr.Dir, 40 Env: attr.Env, 41 Sys: attr.Sys, 42 } 43 if sysattr.Env == nil { 44 sysattr.Env, err = execenv.Default(sysattr.Sys) 45 if err != nil { 46 return nil, err 47 } 48 } 49 sysattr.Files = make([]uintptr, 0, len(attr.Files)) 50 for _, f := range attr.Files { 51 sysattr.Files = append(sysattr.Files, f.Fd()) 52 } 53 54 pid, h, e := syscall.StartProcess(name, argv, sysattr) 55 56 // Make sure we don't run the finalizers of attr.Files. 57 runtime.KeepAlive(attr) 58 59 if e != nil { 60 return nil, &PathError{Op: "fork/exec", Path: name, Err: e} 61 } 62 63 return newProcess(pid, h), nil 64 } 65 66 func (p *Process) kill() error { 67 return p.Signal(Kill) 68 } 69 70 // ProcessState stores information about a process, as reported by Wait. 71 type ProcessState struct { 72 pid int // The process's id. 73 status syscall.WaitStatus // System-dependent status info. 74 rusage *syscall.Rusage 75 } 76 77 // Pid returns the process id of the exited process. 78 func (p *ProcessState) Pid() int { 79 return p.pid 80 } 81 82 func (p *ProcessState) exited() bool { 83 return p.status.Exited() 84 } 85 86 func (p *ProcessState) success() bool { 87 return p.status.ExitStatus() == 0 88 } 89 90 func (p *ProcessState) sys() any { 91 return p.status 92 } 93 94 func (p *ProcessState) sysUsage() any { 95 return p.rusage 96 } 97 98 func (p *ProcessState) String() string { 99 if p == nil { 100 return "<nil>" 101 } 102 status := p.Sys().(syscall.WaitStatus) 103 res := "" 104 switch { 105 case status.Exited(): 106 code := status.ExitStatus() 107 if runtime.GOOS == "windows" && uint(code) >= 1<<16 { // windows uses large hex numbers 108 res = "exit status " + uitox(uint(code)) 109 } else { // unix systems use small decimal integers 110 res = "exit status " + itoa.Itoa(code) // unix 111 } 112 case status.Signaled(): 113 res = "signal: " + status.Signal().String() 114 case status.Stopped(): 115 res = "stop signal: " + status.StopSignal().String() 116 if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 { 117 res += " (trap " + itoa.Itoa(status.TrapCause()) + ")" 118 } 119 case status.Continued(): 120 res = "continued" 121 } 122 if status.CoreDump() { 123 res += " (core dumped)" 124 } 125 return res 126 } 127 128 // ExitCode returns the exit code of the exited process, or -1 129 // if the process hasn't exited or was terminated by a signal. 130 func (p *ProcessState) ExitCode() int { 131 // return -1 if the process hasn't started. 132 if p == nil { 133 return -1 134 } 135 return p.status.ExitStatus() 136 }