OSDN Git Service

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