Source file src/pkg/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 }