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