diff options
Diffstat (limited to 'src/os/exec_posix.go')
-rw-r--r-- | src/os/exec_posix.go | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/os/exec_posix.go b/src/os/exec_posix.go new file mode 100644 index 000000000..fb9d291e6 --- /dev/null +++ b/src/os/exec_posix.go @@ -0,0 +1,134 @@ +// 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 dragonfly freebsd linux nacl netbsd openbsd solaris windows + +package os + +import ( + "syscall" +) + +// The only signal values guaranteed to be present on all systems +// are Interrupt (send the process an interrupt) and Kill (force +// the process to exit). +var ( + Interrupt Signal = syscall.SIGINT + Kill Signal = syscall.SIGKILL +) + +func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { + // If there is no SysProcAttr (ie. no Chroot or changed + // UID/GID), double-check existence of the directory we want + // to chdir into. We can make the error clearer this way. + if attr != nil && attr.Sys == nil && attr.Dir != "" { + if _, err := Stat(attr.Dir); err != nil { + pe := err.(*PathError) + pe.Op = "chdir" + return nil, pe + } + } + + 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 +} + +func (p *Process) kill() error { + return p.Signal(Kill) +} + +// ProcessState stores information about a 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 +} + +func (p *ProcessState) exited() bool { + return p.status.Exited() +} + +func (p *ProcessState) success() bool { + return p.status.ExitStatus() == 0 +} + +func (p *ProcessState) sys() interface{} { + return p.status +} + +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: " + status.Signal().String() + case status.Stopped(): + res = "stop signal: " + status.StopSignal().String() + 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 +} |