Home | History | Annotate | Download | only in exec
      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 	"path/filepath"
     16 	"runtime"
     17 	"strconv"
     18 	"strings"
     19 	"sync"
     20 	"syscall"
     21 )
     22 
     23 // Error records the name of a binary that failed to be executed
     24 // and the reason it failed.
     25 type Error struct {
     26 	Name string
     27 	Err  error
     28 }
     29 
     30 func (e *Error) Error() string {
     31 	return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error()
     32 }
     33 
     34 // Cmd represents an external command being prepared or run.
     35 //
     36 // A Cmd cannot be reused after calling its Run, Output or CombinedOutput
     37 // methods.
     38 type Cmd struct {
     39 	// Path is the path of the command to run.
     40 	//
     41 	// This is the only field that must be set to a non-zero
     42 	// value. If Path is relative, it is evaluated relative
     43 	// to Dir.
     44 	Path string
     45 
     46 	// Args holds command line arguments, including the command as Args[0].
     47 	// If the Args field is empty or nil, Run uses {Path}.
     48 	//
     49 	// In typical use, both Path and Args are set by calling Command.
     50 	Args []string
     51 
     52 	// Env specifies the environment of the process.
     53 	// If Env is nil, Run uses the current process's environment.
     54 	Env []string
     55 
     56 	// Dir specifies the working directory of the command.
     57 	// If Dir is the empty string, Run runs the command in the
     58 	// calling process's current directory.
     59 	Dir string
     60 
     61 	// Stdin specifies the process's standard input.
     62 	// If Stdin is nil, the process reads from the null device (os.DevNull).
     63 	// If Stdin is an *os.File, the process's standard input is connected
     64 	// directly to that file.
     65 	// Otherwise, during the execution of the command a separate
     66 	// goroutine reads from Stdin and delivers that data to the command
     67 	// over a pipe. In this case, Wait does not complete until the goroutine
     68 	// stops copying, either because it has reached the end of Stdin
     69 	// (EOF or a read error) or because writing to the pipe returned an error.
     70 	Stdin io.Reader
     71 
     72 	// Stdout and Stderr specify the process's standard output and error.
     73 	//
     74 	// If either is nil, Run connects the corresponding file descriptor
     75 	// to the null device (os.DevNull).
     76 	//
     77 	// If Stdout and Stderr are the same writer, at most one
     78 	// goroutine at a time will call Write.
     79 	Stdout io.Writer
     80 	Stderr io.Writer
     81 
     82 	// ExtraFiles specifies additional open files to be inherited by the
     83 	// new process. It does not include standard input, standard output, or
     84 	// standard error. If non-nil, entry i becomes file descriptor 3+i.
     85 	//
     86 	// BUG(rsc): On OS X 10.6, child processes may sometimes inherit unwanted fds.
     87 	// https://golang.org/issue/2603
     88 	ExtraFiles []*os.File
     89 
     90 	// SysProcAttr holds optional, operating system-specific attributes.
     91 	// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
     92 	SysProcAttr *syscall.SysProcAttr
     93 
     94 	// Process is the underlying process, once started.
     95 	Process *os.Process
     96 
     97 	// ProcessState contains information about an exited process,
     98 	// available after a call to Wait or Run.
     99 	ProcessState *os.ProcessState
    100 
    101 	lookPathErr     error // LookPath error, if any.
    102 	finished        bool  // when Wait was called
    103 	childFiles      []*os.File
    104 	closeAfterStart []io.Closer
    105 	closeAfterWait  []io.Closer
    106 	goroutine       []func() error
    107 	errch           chan error // one send per goroutine
    108 }
    109 
    110 // Command returns the Cmd struct to execute the named program with
    111 // the given arguments.
    112 //
    113 // It sets only the Path and Args in the returned structure.
    114 //
    115 // If name contains no path separators, Command uses LookPath to
    116 // resolve the path to a complete name if possible. Otherwise it uses
    117 // name directly.
    118 //
    119 // The returned Cmd's Args field is constructed from the command name
    120 // followed by the elements of arg, so arg should not include the
    121 // command name itself. For example, Command("echo", "hello")
    122 func Command(name string, arg ...string) *Cmd {
    123 	cmd := &Cmd{
    124 		Path: name,
    125 		Args: append([]string{name}, arg...),
    126 	}
    127 	if filepath.Base(name) == name {
    128 		if lp, err := LookPath(name); err != nil {
    129 			cmd.lookPathErr = err
    130 		} else {
    131 			cmd.Path = lp
    132 		}
    133 	}
    134 	return cmd
    135 }
    136 
    137 // interfaceEqual protects against panics from doing equality tests on
    138 // two interfaces with non-comparable underlying types.
    139 func interfaceEqual(a, b interface{}) bool {
    140 	defer func() {
    141 		recover()
    142 	}()
    143 	return a == b
    144 }
    145 
    146 func (c *Cmd) envv() []string {
    147 	if c.Env != nil {
    148 		return c.Env
    149 	}
    150 	return os.Environ()
    151 }
    152 
    153 func (c *Cmd) argv() []string {
    154 	if len(c.Args) > 0 {
    155 		return c.Args
    156 	}
    157 	return []string{c.Path}
    158 }
    159 
    160 // skipStdinCopyError optionally specifies a function which reports
    161 // whether the provided the stdin copy error should be ignored.
    162 // It is non-nil everywhere but Plan 9, which lacks EPIPE. See exec_posix.go.
    163 var skipStdinCopyError func(error) bool
    164 
    165 func (c *Cmd) stdin() (f *os.File, err error) {
    166 	if c.Stdin == nil {
    167 		f, err = os.Open(os.DevNull)
    168 		if err != nil {
    169 			return
    170 		}
    171 		c.closeAfterStart = append(c.closeAfterStart, f)
    172 		return
    173 	}
    174 
    175 	if f, ok := c.Stdin.(*os.File); ok {
    176 		return f, nil
    177 	}
    178 
    179 	pr, pw, err := os.Pipe()
    180 	if err != nil {
    181 		return
    182 	}
    183 
    184 	c.closeAfterStart = append(c.closeAfterStart, pr)
    185 	c.closeAfterWait = append(c.closeAfterWait, pw)
    186 	c.goroutine = append(c.goroutine, func() error {
    187 		_, err := io.Copy(pw, c.Stdin)
    188 		if skip := skipStdinCopyError; skip != nil && skip(err) {
    189 			err = nil
    190 		}
    191 		if err1 := pw.Close(); err == nil {
    192 			err = err1
    193 		}
    194 		return err
    195 	})
    196 	return pr, nil
    197 }
    198 
    199 func (c *Cmd) stdout() (f *os.File, err error) {
    200 	return c.writerDescriptor(c.Stdout)
    201 }
    202 
    203 func (c *Cmd) stderr() (f *os.File, err error) {
    204 	if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
    205 		return c.childFiles[1], nil
    206 	}
    207 	return c.writerDescriptor(c.Stderr)
    208 }
    209 
    210 func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
    211 	if w == nil {
    212 		f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
    213 		if err != nil {
    214 			return
    215 		}
    216 		c.closeAfterStart = append(c.closeAfterStart, f)
    217 		return
    218 	}
    219 
    220 	if f, ok := w.(*os.File); ok {
    221 		return f, nil
    222 	}
    223 
    224 	pr, pw, err := os.Pipe()
    225 	if err != nil {
    226 		return
    227 	}
    228 
    229 	c.closeAfterStart = append(c.closeAfterStart, pw)
    230 	c.closeAfterWait = append(c.closeAfterWait, pr)
    231 	c.goroutine = append(c.goroutine, func() error {
    232 		_, err := io.Copy(w, pr)
    233 		pr.Close() // in case io.Copy stopped due to write error
    234 		return err
    235 	})
    236 	return pw, nil
    237 }
    238 
    239 func (c *Cmd) closeDescriptors(closers []io.Closer) {
    240 	for _, fd := range closers {
    241 		fd.Close()
    242 	}
    243 }
    244 
    245 // Run starts the specified command and waits for it to complete.
    246 //
    247 // The returned error is nil if the command runs, has no problems
    248 // copying stdin, stdout, and stderr, and exits with a zero exit
    249 // status.
    250 //
    251 // If the command fails to run or doesn't complete successfully, the
    252 // error is of type *ExitError. Other error types may be
    253 // returned for I/O problems.
    254 func (c *Cmd) Run() error {
    255 	if err := c.Start(); err != nil {
    256 		return err
    257 	}
    258 	return c.Wait()
    259 }
    260 
    261 // lookExtensions finds windows executable by its dir and path.
    262 // It uses LookPath to try appropriate extensions.
    263 // lookExtensions does not search PATH, instead it converts `prog` into `.\prog`.
    264 func lookExtensions(path, dir string) (string, error) {
    265 	if filepath.Base(path) == path {
    266 		path = filepath.Join(".", path)
    267 	}
    268 	if dir == "" {
    269 		return LookPath(path)
    270 	}
    271 	if filepath.VolumeName(path) != "" {
    272 		return LookPath(path)
    273 	}
    274 	if len(path) > 1 && os.IsPathSeparator(path[0]) {
    275 		return LookPath(path)
    276 	}
    277 	dirandpath := filepath.Join(dir, path)
    278 	// We assume that LookPath will only add file extension.
    279 	lp, err := LookPath(dirandpath)
    280 	if err != nil {
    281 		return "", err
    282 	}
    283 	ext := strings.TrimPrefix(lp, dirandpath)
    284 	return path + ext, nil
    285 }
    286 
    287 // Start starts the specified command but does not wait for it to complete.
    288 //
    289 // The Wait method will return the exit code and release associated resources
    290 // once the command exits.
    291 func (c *Cmd) Start() error {
    292 	if c.lookPathErr != nil {
    293 		c.closeDescriptors(c.closeAfterStart)
    294 		c.closeDescriptors(c.closeAfterWait)
    295 		return c.lookPathErr
    296 	}
    297 	if runtime.GOOS == "windows" {
    298 		lp, err := lookExtensions(c.Path, c.Dir)
    299 		if err != nil {
    300 			c.closeDescriptors(c.closeAfterStart)
    301 			c.closeDescriptors(c.closeAfterWait)
    302 			return err
    303 		}
    304 		c.Path = lp
    305 	}
    306 	if c.Process != nil {
    307 		return errors.New("exec: already started")
    308 	}
    309 
    310 	type F func(*Cmd) (*os.File, error)
    311 	for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
    312 		fd, err := setupFd(c)
    313 		if err != nil {
    314 			c.closeDescriptors(c.closeAfterStart)
    315 			c.closeDescriptors(c.closeAfterWait)
    316 			return err
    317 		}
    318 		c.childFiles = append(c.childFiles, fd)
    319 	}
    320 	c.childFiles = append(c.childFiles, c.ExtraFiles...)
    321 
    322 	var err error
    323 	c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
    324 		Dir:   c.Dir,
    325 		Files: c.childFiles,
    326 		Env:   c.envv(),
    327 		Sys:   c.SysProcAttr,
    328 	})
    329 	if err != nil {
    330 		c.closeDescriptors(c.closeAfterStart)
    331 		c.closeDescriptors(c.closeAfterWait)
    332 		return err
    333 	}
    334 
    335 	c.closeDescriptors(c.closeAfterStart)
    336 
    337 	c.errch = make(chan error, len(c.goroutine))
    338 	for _, fn := range c.goroutine {
    339 		go func(fn func() error) {
    340 			c.errch <- fn()
    341 		}(fn)
    342 	}
    343 
    344 	return nil
    345 }
    346 
    347 // An ExitError reports an unsuccessful exit by a command.
    348 type ExitError struct {
    349 	*os.ProcessState
    350 }
    351 
    352 func (e *ExitError) Error() string {
    353 	return e.ProcessState.String()
    354 }
    355 
    356 // Wait waits for the command to exit.
    357 // It must have been started by Start.
    358 //
    359 // The returned error is nil if the command runs, has no problems
    360 // copying stdin, stdout, and stderr, and exits with a zero exit
    361 // status.
    362 //
    363 // If the command fails to run or doesn't complete successfully, the
    364 // error is of type *ExitError. Other error types may be
    365 // returned for I/O problems.
    366 //
    367 // If c.Stdin is not an *os.File, Wait also waits for the I/O loop
    368 // copying from c.Stdin into the process's standard input
    369 // to complete.
    370 //
    371 // Wait releases any resources associated with the Cmd.
    372 func (c *Cmd) Wait() error {
    373 	if c.Process == nil {
    374 		return errors.New("exec: not started")
    375 	}
    376 	if c.finished {
    377 		return errors.New("exec: Wait was already called")
    378 	}
    379 	c.finished = true
    380 	state, err := c.Process.Wait()
    381 	c.ProcessState = state
    382 
    383 	var copyError error
    384 	for range c.goroutine {
    385 		if err := <-c.errch; err != nil && copyError == nil {
    386 			copyError = err
    387 		}
    388 	}
    389 
    390 	c.closeDescriptors(c.closeAfterWait)
    391 
    392 	if err != nil {
    393 		return err
    394 	} else if !state.Success() {
    395 		return &ExitError{state}
    396 	}
    397 
    398 	return copyError
    399 }
    400 
    401 // Output runs the command and returns its standard output.
    402 func (c *Cmd) Output() ([]byte, error) {
    403 	if c.Stdout != nil {
    404 		return nil, errors.New("exec: Stdout already set")
    405 	}
    406 	var b bytes.Buffer
    407 	c.Stdout = &b
    408 	err := c.Run()
    409 	return b.Bytes(), err
    410 }
    411 
    412 // CombinedOutput runs the command and returns its combined standard
    413 // output and standard error.
    414 func (c *Cmd) CombinedOutput() ([]byte, error) {
    415 	if c.Stdout != nil {
    416 		return nil, errors.New("exec: Stdout already set")
    417 	}
    418 	if c.Stderr != nil {
    419 		return nil, errors.New("exec: Stderr already set")
    420 	}
    421 	var b bytes.Buffer
    422 	c.Stdout = &b
    423 	c.Stderr = &b
    424 	err := c.Run()
    425 	return b.Bytes(), err
    426 }
    427 
    428 // StdinPipe returns a pipe that will be connected to the command's
    429 // standard input when the command starts.
    430 // The pipe will be closed automatically after Wait sees the command exit.
    431 // A caller need only call Close to force the pipe to close sooner.
    432 // For example, if the command being run will not exit until standard input
    433 // is closed, the caller must close the pipe.
    434 func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
    435 	if c.Stdin != nil {
    436 		return nil, errors.New("exec: Stdin already set")
    437 	}
    438 	if c.Process != nil {
    439 		return nil, errors.New("exec: StdinPipe after process started")
    440 	}
    441 	pr, pw, err := os.Pipe()
    442 	if err != nil {
    443 		return nil, err
    444 	}
    445 	c.Stdin = pr
    446 	c.closeAfterStart = append(c.closeAfterStart, pr)
    447 	wc := &closeOnce{File: pw}
    448 	c.closeAfterWait = append(c.closeAfterWait, wc)
    449 	return wc, nil
    450 }
    451 
    452 type closeOnce struct {
    453 	*os.File
    454 
    455 	once sync.Once
    456 	err  error
    457 }
    458 
    459 func (c *closeOnce) Close() error {
    460 	c.once.Do(c.close)
    461 	return c.err
    462 }
    463 
    464 func (c *closeOnce) close() {
    465 	c.err = c.File.Close()
    466 }
    467 
    468 // StdoutPipe returns a pipe that will be connected to the command's
    469 // standard output when the command starts.
    470 //
    471 // Wait will close the pipe after seeing the command exit, so most callers
    472 // need not close the pipe themselves; however, an implication is that
    473 // it is incorrect to call Wait before all reads from the pipe have completed.
    474 // For the same reason, it is incorrect to call Run when using StdoutPipe.
    475 // See the example for idiomatic usage.
    476 func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
    477 	if c.Stdout != nil {
    478 		return nil, errors.New("exec: Stdout already set")
    479 	}
    480 	if c.Process != nil {
    481 		return nil, errors.New("exec: StdoutPipe after process started")
    482 	}
    483 	pr, pw, err := os.Pipe()
    484 	if err != nil {
    485 		return nil, err
    486 	}
    487 	c.Stdout = pw
    488 	c.closeAfterStart = append(c.closeAfterStart, pw)
    489 	c.closeAfterWait = append(c.closeAfterWait, pr)
    490 	return pr, nil
    491 }
    492 
    493 // StderrPipe returns a pipe that will be connected to the command's
    494 // standard error when the command starts.
    495 //
    496 // Wait will close the pipe after seeing the command exit, so most callers
    497 // need not close the pipe themselves; however, an implication is that
    498 // it is incorrect to call Wait before all reads from the pipe have completed.
    499 // For the same reason, it is incorrect to use Run when using StderrPipe.
    500 // See the StdoutPipe example for idiomatic usage.
    501 func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
    502 	if c.Stderr != nil {
    503 		return nil, errors.New("exec: Stderr already set")
    504 	}
    505 	if c.Process != nil {
    506 		return nil, errors.New("exec: StderrPipe after process started")
    507 	}
    508 	pr, pw, err := os.Pipe()
    509 	if err != nil {
    510 		return nil, err
    511 	}
    512 	c.Stderr = pw
    513 	c.closeAfterStart = append(c.closeAfterStart, pw)
    514 	c.closeAfterWait = append(c.closeAfterWait, pr)
    515 	return pr, nil
    516 }
    517