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