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 // The exec package runs external commands.
21 // A Cmd represents a running command.
22 // Stdin, Stdout, and Stderr are Files representing pipes
23 // connected to the running command's standard input, output, and error,
24 // or else nil, depending on the arguments to Run.
25 // Process represents the underlying operating system process.
33 // PathError records the name of a binary that was not
34 // found on the current $PATH.
35 type PathError struct {
39 func (e *PathError) String() string {
40 return "command " + strconv.Quote(e.Name) + " not found in $PATH"
43 // Given mode (DevNull, etc), return file for child
44 // and file to record in Cmd structure.
45 func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
52 f, err := os.Open(os.DevNull, rw, 0)
57 return os.Stdin, nil, nil
59 return os.Stdout, nil, nil
61 return os.Stderr, nil, nil
64 r, w, err := os.Pipe()
73 return nil, nil, os.EINVAL
76 // Run starts the named binary running with
77 // arguments argv and environment envv.
78 // It returns a pointer to a new Cmd representing
79 // the command or an error.
81 // The parameters stdin, stdout, and stderr
82 // specify how to handle standard input, output, and error.
83 // The choices are DevNull (connect to /dev/null),
84 // PassThrough (connect to the current process's standard stream),
85 // Pipe (connect to an operating system pipe), and
86 // MergeWithStdout (only for standard error; use the same
87 // file descriptor as was used for standard output).
88 // If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
89 // of the returned Cmd is the other end of the pipe.
90 // Otherwise the field in Cmd is nil.
91 func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (c *Cmd, err os.Error) {
95 if fd[0], c.Stdin, err = modeToFiles(stdin, 0); err != nil {
98 if fd[1], c.Stdout, err = modeToFiles(stdout, 1); err != nil {
101 if stderr == MergeWithStdout {
103 } else if fd[2], c.Stderr, err = modeToFiles(stderr, 2); err != nil {
108 c.Process, err = os.StartProcess(name, argv, envv, dir, fd[0:])
112 if fd[0] != os.Stdin {
115 if fd[1] != os.Stdout {
118 if fd[2] != os.Stderr && fd[2] != fd[1] {
124 if fd[0] != os.Stdin && fd[0] != nil {
127 if fd[1] != os.Stdout && fd[1] != nil {
130 if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] {
142 if c.Process != nil {
148 // Wait waits for the running command c,
149 // returning the Waitmsg returned when the process exits.
150 // The options are passed to the process's Wait method.
151 // Setting options to 0 waits for c to exit;
152 // other options cause Wait to return for other
153 // process events; see package os for details.
154 func (c *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
155 if c.Process == nil {
156 return nil, os.ErrorString("exec: invalid use of Cmd.Wait")
158 w, err := c.Process.Wait(options)
159 if w != nil && (w.Exited() || w.Signaled()) {
166 // Close waits for the running command c to exit,
167 // if it hasn't already, and then closes the non-nil file descriptors
168 // c.Stdin, c.Stdout, and c.Stderr.
169 func (c *Cmd) Close() os.Error {
170 if c.Process != nil {
171 // Loop on interrupt, but
172 // ignore other errors -- maybe
173 // caller has already waited for pid.
175 for err == os.EINTR {
180 // Close the FDs that are still open.
182 if c.Stdin != nil && c.Stdin.Fd() >= 0 {
183 if err1 := c.Stdin.Close(); err1 != nil {
187 if c.Stdout != nil && c.Stdout.Fd() >= 0 {
188 if err1 := c.Stdout.Close(); err1 != nil && err != nil {
192 if c.Stderr != nil && c.Stderr != c.Stdout && c.Stderr.Fd() >= 0 {
193 if err1 := c.Stderr.Close(); err1 != nil && err != nil {