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