Update Go library to last weekly.
[platform/upstream/gcc.git] / libgo / go / exec / exec.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 // Package exec runs external commands. It wraps os.StartProcess to make it
6 // easier to remap stdin and stdout, connect I/O with pipes, and do other
7 // adjustments.
8 package exec
9
10 import (
11         "bytes"
12         "io"
13         "os"
14         "strconv"
15         "syscall"
16 )
17
18 // Error records the name of a binary that failed to be be executed
19 // and the reason it failed.
20 type Error struct {
21         Name  string
22         Error os.Error
23 }
24
25 func (e *Error) String() string {
26         return "exec: " + strconv.Quote(e.Name) + ": " + e.Error.String()
27 }
28
29 // Cmd represents an external command being prepared or run.
30 type Cmd struct {
31         // Path is the path of the command to run.
32         //
33         // This is the only field that must be set to a non-zero
34         // value.
35         Path string
36
37         // Args holds command line arguments, including the command as Args[0].
38         // If the Args field is empty or nil, Run uses {Path}.
39         // 
40         // In typical use, both Path and Args are set by calling Command.
41         Args []string
42
43         // Env specifies the environment of the process.
44         // If Env is nil, Run uses the current process's environment.
45         Env []string
46
47         // Dir specifies the working directory of the command.
48         // If Dir is the empty string, Run runs the command in the
49         // calling process's current directory.
50         Dir string
51
52         // Stdin specifies the process's standard input.
53         // If Stdin is nil, the process reads from DevNull.
54         Stdin io.Reader
55
56         // Stdout and Stderr specify the process's standard output and error.
57         //
58         // If either is nil, Run connects the
59         // corresponding file descriptor to /dev/null.
60         //
61         // If Stdout and Stderr are are the same writer, at most one
62         // goroutine at a time will call Write.
63         Stdout io.Writer
64         Stderr io.Writer
65
66         // ExtraFiles specifies additional open files to be inherited by the
67         // new process. It does not include standard input, standard output, or
68         // standard error. If non-nil, entry i becomes file descriptor 3+i.
69         ExtraFiles []*os.File
70
71         // SysProcAttr holds optional, operating system-specific attributes.
72         // Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
73         SysProcAttr *syscall.SysProcAttr
74
75         // Process is the underlying process, once started.
76         Process *os.Process
77
78         err             os.Error // last error (from LookPath, stdin, stdout, stderr)
79         finished        bool     // when Wait was called
80         childFiles      []*os.File
81         closeAfterStart []io.Closer
82         closeAfterWait  []io.Closer
83         goroutine       []func() os.Error
84         errch           chan os.Error // one send per goroutine
85 }
86
87 // Command returns the Cmd struct to execute the named program with
88 // the given arguments.
89 //
90 // It sets Path and Args in the returned structure and zeroes the
91 // other fields.
92 //
93 // If name contains no path separators, Command uses LookPath to
94 // resolve the path to a complete name if possible. Otherwise it uses
95 // name directly.
96 //
97 // The returned Cmd's Args field is constructed from the command name
98 // followed by the elements of arg, so arg should not include the
99 // command name itself. For example, Command("echo", "hello")
100 func Command(name string, arg ...string) *Cmd {
101         aname, err := LookPath(name)
102         if err != nil {
103                 aname = name
104         }
105         return &Cmd{
106                 Path: aname,
107                 Args: append([]string{name}, arg...),
108                 err:  err,
109         }
110 }
111
112 // interfaceEqual protects against panics from doing equality tests on
113 // two interfaces with non-comparable underlying types
114 func interfaceEqual(a, b interface{}) bool {
115         defer func() {
116                 recover()
117         }()
118         return a == b
119 }
120
121 func (c *Cmd) envv() []string {
122         if c.Env != nil {
123                 return c.Env
124         }
125         return os.Environ()
126 }
127
128 func (c *Cmd) argv() []string {
129         if len(c.Args) > 0 {
130                 return c.Args
131         }
132         return []string{c.Path}
133 }
134
135 func (c *Cmd) stdin() (f *os.File, err os.Error) {
136         if c.Stdin == nil {
137                 f, err = os.Open(os.DevNull)
138                 c.closeAfterStart = append(c.closeAfterStart, f)
139                 return
140         }
141
142         if f, ok := c.Stdin.(*os.File); ok {
143                 return f, nil
144         }
145
146         pr, pw, err := os.Pipe()
147         if err != nil {
148                 return
149         }
150
151         c.closeAfterStart = append(c.closeAfterStart, pr)
152         c.closeAfterWait = append(c.closeAfterWait, pw)
153         c.goroutine = append(c.goroutine, func() os.Error {
154                 _, err := io.Copy(pw, c.Stdin)
155                 if err1 := pw.Close(); err == nil {
156                         err = err1
157                 }
158                 return err
159         })
160         return pr, nil
161 }
162
163 func (c *Cmd) stdout() (f *os.File, err os.Error) {
164         return c.writerDescriptor(c.Stdout)
165 }
166
167 func (c *Cmd) stderr() (f *os.File, err os.Error) {
168         if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
169                 return c.childFiles[1], nil
170         }
171         return c.writerDescriptor(c.Stderr)
172 }
173
174 func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) {
175         if w == nil {
176                 f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
177                 c.closeAfterStart = append(c.closeAfterStart, f)
178                 return
179         }
180
181         if f, ok := w.(*os.File); ok {
182                 return f, nil
183         }
184
185         pr, pw, err := os.Pipe()
186         if err != nil {
187                 return
188         }
189
190         c.closeAfterStart = append(c.closeAfterStart, pw)
191         c.closeAfterWait = append(c.closeAfterWait, pr)
192         c.goroutine = append(c.goroutine, func() os.Error {
193                 _, err := io.Copy(w, pr)
194                 return err
195         })
196         return pw, nil
197 }
198
199 // Run starts the specified command and waits for it to complete.
200 //
201 // The returned error is nil if the command runs, has no problems
202 // copying stdin, stdout, and stderr, and exits with a zero exit
203 // status.
204 //
205 // If the command fails to run or doesn't complete successfully, the
206 // error is of type *os.Waitmsg. Other error types may be
207 // returned for I/O problems.
208 func (c *Cmd) Run() os.Error {
209         if err := c.Start(); err != nil {
210                 return err
211         }
212         return c.Wait()
213 }
214
215 // Start starts the specified command but does not wait for it to complete.
216 func (c *Cmd) Start() os.Error {
217         if c.err != nil {
218                 return c.err
219         }
220         if c.Process != nil {
221                 return os.NewError("exec: already started")
222         }
223
224         type F func(*Cmd) (*os.File, os.Error)
225         for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
226                 fd, err := setupFd(c)
227                 if err != nil {
228                         return err
229                 }
230                 c.childFiles = append(c.childFiles, fd)
231         }
232         c.childFiles = append(c.childFiles, c.ExtraFiles...)
233
234         var err os.Error
235         c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
236                 Dir:   c.Dir,
237                 Files: c.childFiles,
238                 Env:   c.envv(),
239                 Sys:   c.SysProcAttr,
240         })
241         if err != nil {
242                 return err
243         }
244
245         for _, fd := range c.closeAfterStart {
246                 fd.Close()
247         }
248
249         c.errch = make(chan os.Error, len(c.goroutine))
250         for _, fn := range c.goroutine {
251                 go func(fn func() os.Error) {
252                         c.errch <- fn()
253                 }(fn)
254         }
255
256         return nil
257 }
258
259 // Wait waits for the command to exit.
260 // It must have been started by Start.
261 //
262 // The returned error is nil if the command runs, has no problems
263 // copying stdin, stdout, and stderr, and exits with a zero exit
264 // status.
265 //
266 // If the command fails to run or doesn't complete successfully, the
267 // error is of type *os.Waitmsg. Other error types may be
268 // returned for I/O problems.
269 func (c *Cmd) Wait() os.Error {
270         if c.Process == nil {
271                 return os.NewError("exec: not started")
272         }
273         if c.finished {
274                 return os.NewError("exec: Wait was already called")
275         }
276         c.finished = true
277         msg, err := c.Process.Wait(0)
278
279         var copyError os.Error
280         for _ = range c.goroutine {
281                 if err := <-c.errch; err != nil && copyError == nil {
282                         copyError = err
283                 }
284         }
285
286         for _, fd := range c.closeAfterWait {
287                 fd.Close()
288         }
289
290         if err != nil {
291                 return err
292         } else if !msg.Exited() || msg.ExitStatus() != 0 {
293                 return msg
294         }
295
296         return copyError
297 }
298
299 // Output runs the command and returns its standard output.
300 func (c *Cmd) Output() ([]byte, os.Error) {
301         if c.Stdout != nil {
302                 return nil, os.NewError("exec: Stdout already set")
303         }
304         var b bytes.Buffer
305         c.Stdout = &b
306         err := c.Run()
307         return b.Bytes(), err
308 }
309
310 // CombinedOutput runs the command and returns its combined standard
311 // output and standard error.
312 func (c *Cmd) CombinedOutput() ([]byte, os.Error) {
313         if c.Stdout != nil {
314                 return nil, os.NewError("exec: Stdout already set")
315         }
316         if c.Stderr != nil {
317                 return nil, os.NewError("exec: Stderr already set")
318         }
319         var b bytes.Buffer
320         c.Stdout = &b
321         c.Stderr = &b
322         err := c.Run()
323         return b.Bytes(), err
324 }
325
326 // StdinPipe returns a pipe that will be connected to the command's
327 // standard input when the command starts.
328 func (c *Cmd) StdinPipe() (io.WriteCloser, os.Error) {
329         if c.Stdin != nil {
330                 return nil, os.NewError("exec: Stdin already set")
331         }
332         if c.Process != nil {
333                 return nil, os.NewError("exec: StdinPipe after process started")
334         }
335         pr, pw, err := os.Pipe()
336         if err != nil {
337                 return nil, err
338         }
339         c.Stdin = pr
340         c.closeAfterStart = append(c.closeAfterStart, pr)
341         c.closeAfterWait = append(c.closeAfterWait, pw)
342         return pw, nil
343 }
344
345 // StdoutPipe returns a pipe that will be connected to the command's
346 // standard output when the command starts.
347 // The pipe will be closed automatically after Wait sees the command exit.
348 func (c *Cmd) StdoutPipe() (io.ReadCloser, os.Error) {
349         if c.Stdout != nil {
350                 return nil, os.NewError("exec: Stdout already set")
351         }
352         if c.Process != nil {
353                 return nil, os.NewError("exec: StdoutPipe after process started")
354         }
355         pr, pw, err := os.Pipe()
356         if err != nil {
357                 return nil, err
358         }
359         c.Stdout = pw
360         c.closeAfterStart = append(c.closeAfterStart, pw)
361         c.closeAfterWait = append(c.closeAfterWait, pr)
362         return pr, nil
363 }
364
365 // StderrPipe returns a pipe that will be connected to the command's
366 // standard error when the command starts.
367 // The pipe will be closed automatically after Wait sees the command exit.
368 func (c *Cmd) StderrPipe() (io.ReadCloser, os.Error) {
369         if c.Stderr != nil {
370                 return nil, os.NewError("exec: Stderr already set")
371         }
372         if c.Process != nil {
373                 return nil, os.NewError("exec: StderrPipe after process started")
374         }
375         pr, pw, err := os.Pipe()
376         if err != nil {
377                 return nil, err
378         }
379         c.Stderr = pw
380         c.closeAfterStart = append(c.closeAfterStart, pw)
381         c.closeAfterWait = append(c.closeAfterWait, pr)
382         return pr, nil
383 }