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