diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-04-26 09:55:32 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-04-26 09:55:32 +0200 |
commit | 7b15ed9ef455b6b66c6b376898a88aef5d6a9970 (patch) | |
tree | 3ef530baa80cdf29436ba981f5783be6b4d2202b /src/pkg/os/exec_posix.go | |
parent | 50104cc32a498f7517a51c8dc93106c51c7a54b4 (diff) | |
download | golang-7b15ed9ef455b6b66c6b376898a88aef5d6a9970.tar.gz |
Imported Upstream version 2011.04.13upstream/2011.04.13
Diffstat (limited to 'src/pkg/os/exec_posix.go')
-rw-r--r-- | src/pkg/os/exec_posix.go | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go new file mode 100644 index 000000000..9102dc0a4 --- /dev/null +++ b/src/pkg/os/exec_posix.go @@ -0,0 +1,127 @@ +// 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. + +package os + +import "syscall" + +// StartProcess starts a new process with the program, arguments and attributes +// specified by name, argv and attr. +func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) { + sysattr := &syscall.ProcAttr{ + Dir: attr.Dir, + Env: attr.Env, + } + if sysattr.Env == nil { + sysattr.Env = Environ() + } + // Create array of integer (system) fds. + intfd := make([]int, len(attr.Files)) + for i, f := range attr.Files { + if f == nil { + intfd[i] = -1 + } else { + intfd[i] = f.Fd() + } + } + sysattr.Files = intfd + + pid, h, e := syscall.StartProcess(name, argv, sysattr) + if iserror(e) { + return nil, &PathError{"fork/exec", name, Errno(e)} + } + return newProcess(pid, h), nil +} + +// Exec replaces the current process with an execution of the +// named binary, with arguments argv and environment envv. +// If successful, Exec never returns. If it fails, it returns an Error. +// StartProcess is almost always a better way to execute a program. +func Exec(name string, argv []string, envv []string) Error { + if envv == nil { + envv = Environ() + } + e := syscall.Exec(name, argv, envv) + if iserror(e) { + return &PathError{"exec", name, Errno(e)} + } + return nil +} + +// TODO(rsc): Should os implement its own syscall.WaitStatus +// wrapper with the methods, or is exposing the underlying one enough? +// +// TODO(rsc): Certainly need to have Rusage struct, +// since syscall one might have different field types across +// different OS. + +// Waitmsg stores the information about an exited process as reported by Wait. +type Waitmsg struct { + Pid int // The process's id. + syscall.WaitStatus // System-dependent status info. + Rusage *syscall.Rusage // System-dependent resource usage info. +} + +// Wait waits for process pid to exit or stop, and then returns a +// Waitmsg describing its status and an Error, if any. The options +// (WNOHANG etc.) affect the behavior of the Wait call. +// Wait is equivalent to calling FindProcess and then Wait +// and Release on the result. +func Wait(pid int, options int) (w *Waitmsg, err Error) { + p, e := FindProcess(pid) + if e != nil { + return nil, e + } + defer p.Release() + return p.Wait(options) +} + +// 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 (w Waitmsg) String() string { + // TODO(austin) Use signal names when possible? + res := "" + switch { + case w.Exited(): + res = "exit status " + itod(w.ExitStatus()) + case w.Signaled(): + res = "signal " + itod(w.Signal()) + case w.Stopped(): + res = "stop signal " + itod(w.StopSignal()) + if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 { + res += " (trap " + itod(w.TrapCause()) + ")" + } + case w.Continued(): + res = "continued" + } + if w.CoreDump() { + res += " (core dumped)" + } + return res +} |