OSDN Git Service

libgo: Update to weekly.2012-03-13.
[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 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 unwanted 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         // ProcessState contains information about an exited process,
83         // available after a call to Wait or Run.
84         ProcessState *os.ProcessState
85
86         err             error // last error (from LookPath, stdin, stdout, stderr)
87         finished        bool  // when Wait was called
88         childFiles      []*os.File
89         closeAfterStart []io.Closer
90         closeAfterWait  []io.Closer
91         goroutine       []func() error
92         errch           chan error // one send per goroutine
93 }
94
95 // Command returns the Cmd struct to execute the named program with
96 // the given arguments.
97 //
98 // It sets Path and Args in the returned structure and zeroes the
99 // other fields.
100 //
101 // If name contains no path separators, Command uses LookPath to
102 // resolve the path to a complete name if possible. Otherwise it uses
103 // name directly.
104 //
105 // The returned Cmd's Args field is constructed from the command name
106 // followed by the elements of arg, so arg should not include the
107 // command name itself. For example, Command("echo", "hello")
108 func Command(name string, arg ...string) *Cmd {
109         aname, err := LookPath(name)
110         if err != nil {
111                 aname = name
112         }
113         return &Cmd{
114                 Path: aname,
115                 Args: append([]string{name}, arg...),
116                 err:  err,
117         }
118 }
119
120 // interfaceEqual protects against panics from doing equality tests on
121 // two interfaces with non-comparable underlying types
122 func interfaceEqual(a, b interface{}) bool {
123         defer func() {
124                 recover()
125         }()
126         return a == b
127 }
128
129 func (c *Cmd) envv() []string {
130         if c.Env != nil {
131                 return c.Env
132         }
133         return os.Environ()
134 }
135
136 func (c *Cmd) argv() []string {
137         if len(c.Args) > 0 {
138                 return c.Args
139         }
140         return []string{c.Path}
141 }
142
143 func (c *Cmd) stdin() (f *os.File, err error) {
144         if c.Stdin == nil {
145                 f, err = os.Open(os.DevNull)
146                 c.closeAfterStart = append(c.closeAfterStart, f)
147                 return
148         }
149
150         if f, ok := c.Stdin.(*os.File); ok {
151                 return f, nil
152         }
153
154         pr, pw, err := os.Pipe()
155         if err != nil {
156                 return
157         }
158
159         c.closeAfterStart = append(c.closeAfterStart, pr)
160         c.closeAfterWait = append(c.closeAfterWait, pw)
161         c.goroutine = append(c.goroutine, func() error {
162                 _, err := io.Copy(pw, c.Stdin)
163                 if err1 := pw.Close(); err == nil {
164                         err = err1
165                 }
166                 return err
167         })
168         return pr, nil
169 }
170
171 func (c *Cmd) stdout() (f *os.File, err error) {
172         return c.writerDescriptor(c.Stdout)
173 }
174
175 func (c *Cmd) stderr() (f *os.File, err error) {
176         if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
177                 return c.childFiles[1], nil
178         }
179         return c.writerDescriptor(c.Stderr)
180 }
181
182 func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
183         if w == nil {
184                 f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
185                 c.closeAfterStart = append(c.closeAfterStart, f)
186                 return
187         }
188
189         if f, ok := w.(*os.File); ok {
190                 return f, nil
191         }
192
193         pr, pw, err := os.Pipe()
194         if err != nil {
195                 return
196         }
197
198         c.closeAfterStart = append(c.closeAfterStart, pw)
199         c.closeAfterWait = append(c.closeAfterWait, pr)
200         c.goroutine = append(c.goroutine, func() error {
201                 _, err := io.Copy(w, pr)
202                 return err
203         })
204         return pw, nil
205 }
206
207 // Run starts the specified command and waits for it to complete.
208 //
209 // The returned error is nil if the command runs, has no problems
210 // copying stdin, stdout, and stderr, and exits with a zero exit
211 // status.
212 //
213 // If the command fails to run or doesn't complete successfully, the
214 // error is of type *ExitError. Other error types may be
215 // returned for I/O problems.
216 func (c *Cmd) Run() error {
217         if err := c.Start(); err != nil {
218                 return err
219         }
220         return c.Wait()
221 }
222
223 // Start starts the specified command but does not wait for it to complete.
224 func (c *Cmd) Start() error {
225         if c.err != nil {
226                 return c.err
227         }
228         if c.Process != nil {
229                 return errors.New("exec: already started")
230         }
231
232         type F func(*Cmd) (*os.File, error)
233         for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
234                 fd, err := setupFd(c)
235                 if err != nil {
236                         return err
237                 }
238                 c.childFiles = append(c.childFiles, fd)
239         }
240         c.childFiles = append(c.childFiles, c.ExtraFiles...)
241
242         var err error
243         c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
244                 Dir:   c.Dir,
245                 Files: c.childFiles,
246                 Env:   c.envv(),
247                 Sys:   c.SysProcAttr,
248         })
249         if err != nil {
250                 return err
251         }
252
253         for _, fd := range c.closeAfterStart {
254                 fd.Close()
255         }
256
257         c.errch = make(chan error, len(c.goroutine))
258         for _, fn := range c.goroutine {
259                 go func(fn func() error) {
260                         c.errch <- fn()
261                 }(fn)
262         }
263
264         return nil
265 }
266
267 // An ExitError reports an unsuccessful exit by a command.
268 type ExitError struct {
269         *os.ProcessState
270 }
271
272 func (e *ExitError) Error() string {
273         return e.ProcessState.String()
274 }
275
276 // Wait waits for the command to exit.
277 // It must have been started by Start.
278 //
279 // The returned error is nil if the command runs, has no problems
280 // copying stdin, stdout, and stderr, and exits with a zero exit
281 // status.
282 //
283 // If the command fails to run or doesn't complete successfully, the
284 // error is of type *ExitError. Other error types may be
285 // returned for I/O problems.
286 func (c *Cmd) Wait() error {
287         if c.Process == nil {
288                 return errors.New("exec: not started")
289         }
290         if c.finished {
291                 return errors.New("exec: Wait was already called")
292         }
293         c.finished = true
294         state, err := c.Process.Wait()
295         c.ProcessState = state
296
297         var copyError error
298         for _ = range c.goroutine {
299                 if err := <-c.errch; err != nil && copyError == nil {
300                         copyError = err
301                 }
302         }
303
304         for _, fd := range c.closeAfterWait {
305                 fd.Close()
306         }
307
308         if err != nil {
309                 return err
310         } else if !state.Success() {
311                 return &ExitError{state}
312         }
313
314         return copyError
315 }
316
317 // Output runs the command and returns its standard output.
318 func (c *Cmd) Output() ([]byte, error) {
319         if c.Stdout != nil {
320                 return nil, errors.New("exec: Stdout already set")
321         }
322         var b bytes.Buffer
323         c.Stdout = &b
324         err := c.Run()
325         return b.Bytes(), err
326 }
327
328 // CombinedOutput runs the command and returns its combined standard
329 // output and standard error.
330 func (c *Cmd) CombinedOutput() ([]byte, error) {
331         if c.Stdout != nil {
332                 return nil, errors.New("exec: Stdout already set")
333         }
334         if c.Stderr != nil {
335                 return nil, errors.New("exec: Stderr already set")
336         }
337         var b bytes.Buffer
338         c.Stdout = &b
339         c.Stderr = &b
340         err := c.Run()
341         return b.Bytes(), err
342 }
343
344 // StdinPipe returns a pipe that will be connected to the command's
345 // standard input when the command starts.
346 func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
347         if c.Stdin != nil {
348                 return nil, errors.New("exec: Stdin already set")
349         }
350         if c.Process != nil {
351                 return nil, errors.New("exec: StdinPipe after process started")
352         }
353         pr, pw, err := os.Pipe()
354         if err != nil {
355                 return nil, err
356         }
357         c.Stdin = pr
358         c.closeAfterStart = append(c.closeAfterStart, pr)
359         c.closeAfterWait = append(c.closeAfterWait, pw)
360         return pw, nil
361 }
362
363 // StdoutPipe returns a pipe that will be connected to the command's
364 // standard output when the command starts.
365 // The pipe will be closed automatically after Wait sees the command exit.
366 func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
367         if c.Stdout != nil {
368                 return nil, errors.New("exec: Stdout already set")
369         }
370         if c.Process != nil {
371                 return nil, errors.New("exec: StdoutPipe after process started")
372         }
373         pr, pw, err := os.Pipe()
374         if err != nil {
375                 return nil, err
376         }
377         c.Stdout = pw
378         c.closeAfterStart = append(c.closeAfterStart, pw)
379         c.closeAfterWait = append(c.closeAfterWait, pr)
380         return pr, nil
381 }
382
383 // StderrPipe returns a pipe that will be connected to the command's
384 // standard error when the command starts.
385 // The pipe will be closed automatically after Wait sees the command exit.
386 func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
387         if c.Stderr != nil {
388                 return nil, errors.New("exec: Stderr already set")
389         }
390         if c.Process != nil {
391                 return nil, errors.New("exec: StderrPipe after process started")
392         }
393         pr, pw, err := os.Pipe()
394         if err != nil {
395                 return nil, err
396         }
397         c.Stderr = pw
398         c.closeAfterStart = append(c.closeAfterStart, pw)
399         c.closeAfterWait = append(c.closeAfterWait, pr)
400         return pr, nil
401 }