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.
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
18 // Error records the name of a binary that failed to be be executed
19 // and the reason it failed.
25 func (e *Error) String() string {
26 return "exec: " + strconv.Quote(e.Name) + ": " + e.Error.String()
29 // Cmd represents an external command being prepared or run.
31 // Path is the path of the command to run.
33 // This is the only field that must be set to a non-zero
37 // Args holds command line arguments, including the command as Args[0].
38 // If the Args field is empty or nil, Run uses {Path}.
40 // In typical use, both Path and Args are set by calling Command.
43 // Env specifies the environment of the process.
44 // If Env is nil, Run uses the current process's environment.
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.
52 // Stdin specifies the process's standard input.
53 // If Stdin is nil, the process reads from DevNull.
56 // Stdout and Stderr specify the process's standard output and error.
58 // If either is nil, Run connects the
59 // corresponding file descriptor to /dev/null.
61 // If Stdout and Stderr are are the same writer, at most one
62 // goroutine at a time will call Write.
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.
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
75 // Process is the underlying process, once started.
78 err os.Error // last error (from LookPath, stdin, stdout, stderr)
79 finished bool // when Wait was called
81 closeAfterStart []io.Closer
82 closeAfterWait []io.Closer
83 goroutine []func() os.Error
84 errch chan os.Error // one send per goroutine
87 // Command returns the Cmd struct to execute the named program with
88 // the given arguments.
90 // It sets Path and Args in the returned structure and zeroes the
93 // If name contains no path separators, Command uses LookPath to
94 // resolve the path to a complete name if possible. Otherwise it uses
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)
107 Args: append([]string{name}, arg...),
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 {
121 func (c *Cmd) envv() []string {
128 func (c *Cmd) argv() []string {
132 return []string{c.Path}
135 func (c *Cmd) stdin() (f *os.File, err os.Error) {
137 f, err = os.Open(os.DevNull)
138 c.closeAfterStart = append(c.closeAfterStart, f)
142 if f, ok := c.Stdin.(*os.File); ok {
146 pr, pw, err := os.Pipe()
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 {
163 func (c *Cmd) stdout() (f *os.File, err os.Error) {
164 return c.writerDescriptor(c.Stdout)
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
171 return c.writerDescriptor(c.Stderr)
174 func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) {
176 f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
177 c.closeAfterStart = append(c.closeAfterStart, f)
181 if f, ok := w.(*os.File); ok {
185 pr, pw, err := os.Pipe()
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)
199 // Run starts the specified command and waits for it to complete.
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
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 {
215 // Start starts the specified command but does not wait for it to complete.
216 func (c *Cmd) Start() os.Error {
220 if c.Process != nil {
221 return os.NewError("exec: already started")
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)
230 c.childFiles = append(c.childFiles, fd)
232 c.childFiles = append(c.childFiles, c.ExtraFiles...)
235 c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
245 for _, fd := range c.closeAfterStart {
249 c.errch = make(chan os.Error, len(c.goroutine))
250 for _, fn := range c.goroutine {
251 go func(fn func() os.Error) {
259 // Wait waits for the command to exit.
260 // It must have been started by Start.
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
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")
274 return os.NewError("exec: Wait was already called")
277 msg, err := c.Process.Wait(0)
279 var copyError os.Error
280 for _ = range c.goroutine {
281 if err := <-c.errch; err != nil && copyError == nil {
286 for _, fd := range c.closeAfterWait {
292 } else if !msg.Exited() || msg.ExitStatus() != 0 {
299 // Output runs the command and returns its standard output.
300 func (c *Cmd) Output() ([]byte, os.Error) {
302 return nil, os.NewError("exec: Stdout already set")
307 return b.Bytes(), err
310 // CombinedOutput runs the command and returns its combined standard
311 // output and standard error.
312 func (c *Cmd) CombinedOutput() ([]byte, os.Error) {
314 return nil, os.NewError("exec: Stdout already set")
317 return nil, os.NewError("exec: Stderr already set")
323 return b.Bytes(), err
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) {
330 return nil, os.NewError("exec: Stdin already set")
332 if c.Process != nil {
333 return nil, os.NewError("exec: StdinPipe after process started")
335 pr, pw, err := os.Pipe()
340 c.closeAfterStart = append(c.closeAfterStart, pr)
341 c.closeAfterWait = append(c.closeAfterWait, pw)
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) {
350 return nil, os.NewError("exec: Stdout already set")
352 if c.Process != nil {
353 return nil, os.NewError("exec: StdoutPipe after process started")
355 pr, pw, err := os.Pipe()
360 c.closeAfterStart = append(c.closeAfterStart, pw)
361 c.closeAfterWait = append(c.closeAfterWait, pr)
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) {
370 return nil, os.NewError("exec: Stderr already set")
372 if c.Process != nil {
373 return nil, os.NewError("exec: StderrPipe after process started")
375 pr, pw, err := os.Pipe()
380 c.closeAfterStart = append(c.closeAfterStart, pw)
381 c.closeAfterWait = append(c.closeAfterWait, pr)