]>
Commit | Line | Data |
---|---|---|
405ca104 ILT |
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 | ||
d8f41257 ILT |
5 | // +build darwin freebsd linux openbsd windows |
6 | ||
405ca104 ILT |
7 | package os |
8 | ||
adb0401d ILT |
9 | import ( |
10 | "runtime" | |
11 | "syscall" | |
12 | ) | |
13 | ||
14 | type UnixSignal int32 | |
15 | ||
16 | func (sig UnixSignal) String() string { | |
17 | s := runtime.Signame(int32(sig)) | |
18 | if len(s) > 0 { | |
19 | return s | |
20 | } | |
21 | return "UnixSignal" | |
22 | } | |
405ca104 ILT |
23 | |
24 | // StartProcess starts a new process with the program, arguments and attributes | |
25 | // specified by name, argv and attr. | |
adb0401d ILT |
26 | // |
27 | // StartProcess is a low-level interface. The exec package provides | |
28 | // higher-level interfaces. | |
2fd401c8 | 29 | func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { |
405ca104 ILT |
30 | sysattr := &syscall.ProcAttr{ |
31 | Dir: attr.Dir, | |
32 | Env: attr.Env, | |
adb0401d | 33 | Sys: attr.Sys, |
405ca104 ILT |
34 | } |
35 | if sysattr.Env == nil { | |
36 | sysattr.Env = Environ() | |
37 | } | |
adb0401d ILT |
38 | for _, f := range attr.Files { |
39 | sysattr.Files = append(sysattr.Files, f.Fd()) | |
405ca104 | 40 | } |
405ca104 ILT |
41 | |
42 | pid, h, e := syscall.StartProcess(name, argv, sysattr) | |
43 | if iserror(e) { | |
44 | return nil, &PathError{"fork/exec", name, Errno(e)} | |
45 | } | |
46 | return newProcess(pid, h), nil | |
47 | } | |
48 | ||
adb0401d | 49 | // Kill causes the Process to exit immediately. |
2fd401c8 | 50 | func (p *Process) Kill() error { |
adb0401d ILT |
51 | return p.Signal(SIGKILL) |
52 | } | |
53 | ||
405ca104 ILT |
54 | // Exec replaces the current process with an execution of the |
55 | // named binary, with arguments argv and environment envv. | |
2fd401c8 | 56 | // If successful, Exec never returns. If it fails, it returns an error. |
adb0401d ILT |
57 | // |
58 | // To run a child process, see StartProcess (for a low-level interface) | |
59 | // or the exec package (for higher-level interfaces). | |
2fd401c8 | 60 | func Exec(name string, argv []string, envv []string) error { |
405ca104 ILT |
61 | if envv == nil { |
62 | envv = Environ() | |
63 | } | |
64 | e := syscall.Exec(name, argv, envv) | |
65 | if iserror(e) { | |
66 | return &PathError{"exec", name, Errno(e)} | |
67 | } | |
68 | return nil | |
69 | } | |
70 | ||
71 | // TODO(rsc): Should os implement its own syscall.WaitStatus | |
72 | // wrapper with the methods, or is exposing the underlying one enough? | |
73 | // | |
74 | // TODO(rsc): Certainly need to have Rusage struct, | |
75 | // since syscall one might have different field types across | |
76 | // different OS. | |
77 | ||
78 | // Waitmsg stores the information about an exited process as reported by Wait. | |
79 | type Waitmsg struct { | |
80 | Pid int // The process's id. | |
81 | syscall.WaitStatus // System-dependent status info. | |
82 | Rusage *syscall.Rusage // System-dependent resource usage info. | |
83 | } | |
84 | ||
85 | // Wait waits for process pid to exit or stop, and then returns a | |
2fd401c8 | 86 | // Waitmsg describing its status and an error, if any. The options |
405ca104 ILT |
87 | // (WNOHANG etc.) affect the behavior of the Wait call. |
88 | // Wait is equivalent to calling FindProcess and then Wait | |
89 | // and Release on the result. | |
2fd401c8 | 90 | func Wait(pid int, options int) (w *Waitmsg, err error) { |
405ca104 ILT |
91 | p, e := FindProcess(pid) |
92 | if e != nil { | |
93 | return nil, e | |
94 | } | |
95 | defer p.Release() | |
96 | return p.Wait(options) | |
97 | } | |
98 | ||
99 | // Convert i to decimal string. | |
100 | func itod(i int) string { | |
101 | if i == 0 { | |
102 | return "0" | |
103 | } | |
104 | ||
105 | u := uint64(i) | |
106 | if i < 0 { | |
107 | u = -u | |
108 | } | |
109 | ||
110 | // Assemble decimal in reverse order. | |
111 | var b [32]byte | |
112 | bp := len(b) | |
113 | for ; u > 0; u /= 10 { | |
114 | bp-- | |
115 | b[bp] = byte(u%10) + '0' | |
116 | } | |
117 | ||
118 | if i < 0 { | |
119 | bp-- | |
120 | b[bp] = '-' | |
121 | } | |
122 | ||
123 | return string(b[bp:]) | |
124 | } | |
125 | ||
adb0401d ILT |
126 | func (w *Waitmsg) String() string { |
127 | if w == nil { | |
128 | return "<nil>" | |
129 | } | |
405ca104 ILT |
130 | // TODO(austin) Use signal names when possible? |
131 | res := "" | |
132 | switch { | |
133 | case w.Exited(): | |
134 | res = "exit status " + itod(w.ExitStatus()) | |
135 | case w.Signaled(): | |
136 | res = "signal " + itod(w.Signal()) | |
137 | case w.Stopped(): | |
138 | res = "stop signal " + itod(w.StopSignal()) | |
139 | if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 { | |
140 | res += " (trap " + itod(w.TrapCause()) + ")" | |
141 | } | |
142 | case w.Continued(): | |
143 | res = "continued" | |
144 | } | |
145 | if w.CoreDump() { | |
146 | res += " (core dumped)" | |
147 | } | |
148 | return res | |
149 | } |