| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build darwin freebsd linux netbsd openbsd windows |
| |
| package os |
| |
| import ( |
| "syscall" |
| ) |
| |
| // StartProcess starts a new process with the program, arguments and attributes |
| // specified by name, argv and attr. |
| // |
| // StartProcess is a low-level interface. The os/exec package provides |
| // higher-level interfaces. |
| // |
| // If there is an error, it will be of type *PathError. |
| func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { |
| sysattr := &syscall.ProcAttr{ |
| Dir: attr.Dir, |
| Env: attr.Env, |
| Sys: attr.Sys, |
| } |
| if sysattr.Env == nil { |
| sysattr.Env = Environ() |
| } |
| for _, f := range attr.Files { |
| sysattr.Files = append(sysattr.Files, f.Fd()) |
| } |
| |
| pid, h, e := syscall.StartProcess(name, argv, sysattr) |
| if e != nil { |
| return nil, &PathError{"fork/exec", name, e} |
| } |
| return newProcess(pid, h), nil |
| } |
| |
| // Kill causes the Process to exit immediately. |
| func (p *Process) Kill() error { |
| return p.Signal(Kill) |
| } |
| |
| // ProcessState stores information about process as reported by Wait. |
| type ProcessState struct { |
| pid int // The process's id. |
| status syscall.WaitStatus // System-dependent status info. |
| rusage *syscall.Rusage |
| } |
| |
| // Pid returns the process id of the exited process. |
| func (p *ProcessState) Pid() int { |
| return p.pid |
| } |
| |
| // Exited returns whether the program has exited. |
| func (p *ProcessState) Exited() bool { |
| return p.status.Exited() |
| } |
| |
| // Success reports whether the program exited successfully, |
| // such as with exit status 0 on Unix. |
| func (p *ProcessState) Success() bool { |
| return p.status.ExitStatus() == 0 |
| } |
| |
| // Sys returns system-dependent exit information about |
| // the process. Convert it to the appropriate underlying |
| // type, such as syscall.WaitStatus on Unix, to access its contents. |
| func (p *ProcessState) Sys() interface{} { |
| return p.status |
| } |
| |
| // SysUsage returns system-dependent resource usage information about |
| // the exited process. Convert it to the appropriate underlying |
| // type, such as *syscall.Rusage on Unix, to access its contents. |
| func (p *ProcessState) SysUsage() interface{} { |
| return p.rusage |
| } |
| |
| // Convert i to decimal string. |
| func itod(i int) string { |
| if i == 0 { |
| return "0" |
| } |
| |
| u := uint64(i) |
| if i < 0 { |
| u = -u |
| } |
| |
| // Assemble decimal in reverse order. |
| var b [32]byte |
| bp := len(b) |
| for ; u > 0; u /= 10 { |
| bp-- |
| b[bp] = byte(u%10) + '0' |
| } |
| |
| if i < 0 { |
| bp-- |
| b[bp] = '-' |
| } |
| |
| return string(b[bp:]) |
| } |
| |
| func (p *ProcessState) String() string { |
| if p == nil { |
| return "<nil>" |
| } |
| status := p.Sys().(syscall.WaitStatus) |
| res := "" |
| switch { |
| case status.Exited(): |
| res = "exit status " + itod(status.ExitStatus()) |
| case status.Signaled(): |
| res = "signal " + itod(int(status.Signal())) |
| case status.Stopped(): |
| res = "stop signal " + itod(int(status.StopSignal())) |
| if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 { |
| res += " (trap " + itod(status.TrapCause()) + ")" |
| } |
| case status.Continued(): |
| res = "continued" |
| } |
| if status.CoreDump() { |
| res += " (core dumped)" |
| } |
| return res |
| } |