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