Source file src/pkg/os/exec_posix.go
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 darwin freebsd linux netbsd openbsd windows
6
7 package os
8
9 import (
10 "syscall"
11 )
12
13 func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
14 // Double-check existence of the directory we want
15 // to chdir into. We can make the error clearer this way.
16 if attr != nil && attr.Dir != "" {
17 if _, err := Stat(attr.Dir); err != nil {
18 pe := err.(*PathError)
19 pe.Op = "chdir"
20 return nil, pe
21 }
22 }
23
24 sysattr := &syscall.ProcAttr{
25 Dir: attr.Dir,
26 Env: attr.Env,
27 Sys: attr.Sys,
28 }
29 if sysattr.Env == nil {
30 sysattr.Env = Environ()
31 }
32 for _, f := range attr.Files {
33 sysattr.Files = append(sysattr.Files, f.Fd())
34 }
35
36 pid, h, e := syscall.StartProcess(name, argv, sysattr)
37 if e != nil {
38 return nil, &PathError{"fork/exec", name, e}
39 }
40 return newProcess(pid, h), nil
41 }
42
43 func (p *Process) kill() error {
44 return p.Signal(Kill)
45 }
46
47 // ProcessState stores information about a process, as reported by Wait.
48 type ProcessState struct {
49 pid int // The process's id.
50 status syscall.WaitStatus // System-dependent status info.
51 rusage *syscall.Rusage
52 }
53
54 // Pid returns the process id of the exited process.
55 func (p *ProcessState) Pid() int {
56 return p.pid
57 }
58
59 func (p *ProcessState) exited() bool {
60 return p.status.Exited()
61 }
62
63 func (p *ProcessState) success() bool {
64 return p.status.ExitStatus() == 0
65 }
66
67 func (p *ProcessState) sys() interface{} {
68 return p.status
69 }
70
71 func (p *ProcessState) sysUsage() interface{} {
72 return p.rusage
73 }
74
75 // Convert i to decimal string.
76 func itod(i int) string {
77 if i == 0 {
78 return "0"
79 }
80
81 u := uint64(i)
82 if i < 0 {
83 u = -u
84 }
85
86 // Assemble decimal in reverse order.
87 var b [32]byte
88 bp := len(b)
89 for ; u > 0; u /= 10 {
90 bp--
91 b[bp] = byte(u%10) + '0'
92 }
93
94 if i < 0 {
95 bp--
96 b[bp] = '-'
97 }
98
99 return string(b[bp:])
100 }
101
102 func (p *ProcessState) String() string {
103 if p == nil {
104 return "<nil>"
105 }
106 status := p.Sys().(syscall.WaitStatus)
107 res := ""
108 switch {
109 case status.Exited():
110 res = "exit status " + itod(status.ExitStatus())
111 case status.Signaled():
112 res = "signal " + itod(int(status.Signal()))
113 case status.Stopped():
114 res = "stop signal " + itod(int(status.StopSignal()))
115 if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 {
116 res += " (trap " + itod(status.TrapCause()) + ")"
117 }
118 case status.Continued():
119 res = "continued"
120 }
121 if status.CoreDump() {
122 res += " (core dumped)"
123 }
124 return res
125 }