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 //
      9 // Unlike the "system" library call from C and other languages, the
     10 // os/exec package intentionally does not invoke the system shell and
     11 // does not expand any glob patterns or handle other expansions,
     12 // pipelines, or redirections typically done by shells. The package
     13 // behaves more like C's "exec" family of functions. To expand glob
     14 // patterns, either call the shell directly, taking care to escape any
     15 // dangerous input, or use the path/filepath package's Glob function.
     16 // To expand environment variables, use package os's ExpandEnv.
     17 //
     18 // Note that the examples in this package assume a Unix system.
     19 // They may not run on Windows, and they do not run in the Go Playground
     20 // used by golang.org and godoc.org.
     21 package exec
     22 
     23 import (
     24 	"bytes"
     25 	"context"
     26 	"errors"
     27 	"io"
     28 	"os"
     29 	"path/filepath"
     30 	"runtime"
     31 	"strconv"
     32 	"strings"
     33 	"sync"
     34 	"syscall"
     35 )
     36 
     37 // Error records the name of a binary that failed to be executed
     38 // and the reason it failed.
     39 type Error struct {
     40 	Name string
     41 	Err  error
     42 }
     43 
     44 func (e *Error) Error() string {
     45 	return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error()
     46 }
     47 
     48 // Cmd represents an external command being prepared or run.
     49 //
     50 // A Cmd cannot be reused after calling its Run, Output or CombinedOutput
     51 // methods.
     52 type Cmd struct {
     53 	// Path is the path of the command to run.
     54 	//
     55 	// This is the only field that must be set to a non-zero
     56 	// value. If Path is relative, it is evaluated relative
     57 	// to Dir.
     58 	Path string
     59 
     60 	// Args holds command line arguments, including the command as Args[0].
     61 	// If the Args field is empty or nil, Run uses {Path}.
     62 	//
     63 	// In typical use, both Path and Args are set by calling Command.
     64 	Args []string
     65 
     66 	// Env specifies the environment of the process.
     67 	// Each entry is of the form "key=value".
     68 	// If Env is nil, the new process uses the current process's
     69 	// environment.
     70 	// If Env contains duplicate environment keys, only the last
     71 	// value in the slice for each duplicate key is used.
     72 	Env []string
     73 
     74 	// Dir specifies the working directory of the command.
     75 	// If Dir is the empty string, Run runs the command in the
     76 	// calling process's current directory.
     77 	Dir string
     78 
     79 	// Stdin specifies the process's standard input.
     80 	//
     81 	// If Stdin is nil, the process reads from the null device (os.DevNull).
     82 	//
     83 	// If Stdin is an *os.File, the process's standard input is connected
     84 	// directly to that file.
     85 	//
     86 	// Otherwise, during the execution of the command a separate
     87 	// goroutine reads from Stdin and delivers that data to the command
     88 	// over a pipe. In this case, Wait does not complete until the goroutine
     89 	// stops copying, either because it has reached the end of Stdin
     90 	// (EOF or a read error) or because writing to the pipe returned an error.
     91 	Stdin io.Reader
     92 
     93 	// Stdout and Stderr specify the process's standard output and error.
     94 	//
     95 	// If either is nil, Run connects the corresponding file descriptor
     96 	// to the null device (os.DevNull).
     97 	//
     98 	// If either is an *os.File, the corresponding output from the process
     99 	// is connected directly to that file.
    100 	//
    101 	// Otherwise, during the execution of the command a separate goroutine
    102 	// reads from the process over a pipe and delivers that data to the
    103 	// corresponding Writer. In this case, Wait does not complete until the
    104 	// goroutine reaches EOF or encounters an error.
    105 	//
    106 	// If Stdout and Stderr are the same writer, and have a type that can
    107 	// be compared with ==, at most one goroutine at a time will call Write.
    108 	Stdout io.Writer
    109 	Stderr io.Writer
    110 
    111 	// ExtraFiles specifies additional open files to be inherited by the
    112 	// new process. It does not include standard input, standard output, or
    113 	// standard error. If non-nil, entry i becomes file descriptor 3+i.
    114 	ExtraFiles []*os.File
    115 
    116 	// SysProcAttr holds optional, operating system-specific attributes.
    117 	// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
    118 	SysProcAttr *syscall.SysProcAttr
    119 
    120 	// Process is the underlying process, once started.
    121 	Process *os.Process
    122 
    123 	// ProcessState contains information about an exited process,
    124 	// available after a call to Wait or Run.
    125 	ProcessState *os.ProcessState
    126 
    127 	ctx             context.Context // nil means none
    128 	lookPathErr     error           // LookPath error, if any.
    129 	finished        bool            // when Wait was called
    130 	childFiles      []*os.File
    131 	closeAfterStart []io.Closer
    132 	closeAfterWait  []io.Closer
    133 	goroutine       []func() error
    134 	errch           chan error // one send per goroutine
    135 	waitDone        chan struct{}
    136 }
    137 
    138 // Command returns the Cmd struct to execute the named program with
    139 // the given arguments.
    140 //
    141 // It sets only the Path and Args in the returned structure.
    142 //
    143 // If name contains no path separators, Command uses LookPath to
    144 // resolve name to a complete path if possible. Otherwise it uses name
    145 // directly as Path.
    146 //
    147 // The returned Cmd's Args field is constructed from the command name
    148 // followed by the elements of arg, so arg should not include the
    149 // command name itself. For example, Command("echo", "hello").
    150 // Args[0] is always name, not the possibly resolved Path.
    151 func Command(name string, arg ...string) *Cmd {
    152 	cmd := &Cmd{
    153 		Path: name,
    154 		Args: append([]string{name}, arg...),
    155 	}
    156 	if filepath.Base(name) == name {
    157 		if lp, err := LookPath(name); err != nil {
    158 			cmd.lookPathErr = err
    159 		} else {
    160 			cmd.Path = lp
    161 		}
    162 	}
    163 	return cmd
    164 }
    165 
    166 // CommandContext is like Command but includes a context.
    167 //
    168 // The provided context is used to kill the process (by calling
    169 // os.Process.Kill) if the context becomes done before the command
    170 // completes on its own.
    171 func CommandContext(ctx context.Context, name string, arg ...string) *Cmd {
    172 	if ctx == nil {
    173 		panic("nil Context")
    174 	}
    175 	cmd := Command(name, arg...)
    176 	cmd.ctx = ctx
    177 	return cmd
    178 }
    179 
    180 // interfaceEqual protects against panics from doing equality tests on
    181 // two interfaces with non-comparable underlying types.
    182 func interfaceEqual(a, b interface{}) bool {
    183 	defer func() {
    184 		recover()
    185 	}()
    186 	return a == b
    187 }
    188 
    189 func (c *Cmd) envv() []string {
    190 	if c.Env != nil {
    191 		return c.Env
    192 	}
    193 	return os.Environ()
    194 }
    195 
    196 func (c *Cmd) argv() []string {
    197 	if len(c.Args) > 0 {
    198 		return c.Args
    199 	}
    200 	return []string{c.Path}
    201 }
    202 
    203 // skipStdinCopyError optionally specifies a function which reports
    204 // whether the provided stdin copy error should be ignored.
    205 // It is non-nil everywhere but Plan 9, which lacks EPIPE. See exec_posix.go.
    206 var skipStdinCopyError func(error) bool
    207 
    208 func (c *Cmd) stdin() (f *os.File, err error) {
    209 	if c.Stdin == nil {
    210 		f, err = os.Open(os.DevNull)
    211 		if err != nil {
    212 			return
    213 		}
    214 		c.closeAfterStart = append(c.closeAfterStart, f)
    215 		return
    216 	}
    217 
    218 	if f, ok := c.Stdin.(*os.File); ok {
    219 		return f, nil
    220 	}
    221 
    222 	pr, pw, err := os.Pipe()
    223 	if err != nil {
    224 		return
    225 	}
    226 
    227 	c.closeAfterStart = append(c.closeAfterStart, pr)
    228 	c.closeAfterWait = append(c.closeAfterWait, pw)
    229 	c.goroutine = append(c.goroutine, func() error {
    230 		_, err := io.Copy(pw, c.Stdin)
    231 		if skip := skipStdinCopyError; skip != nil && skip(err) {
    232 			err = nil
    233 		}
    234 		if err1 := pw.Close(); err == nil {
    235 			err = err1
    236 		}
    237 		return err
    238 	})
    239 	return pr, nil
    240 }
    241 
    242 func (c *Cmd) stdout() (f *os.File, err error) {
    243 	return c.writerDescriptor(c.Stdout)
    244 }
    245 
    246 func (c *Cmd) stderr() (f *os.File, err error) {
    247 	if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
    248 		return c.childFiles[1], nil
    249 	}
    250 	return c.writerDescriptor(c.Stderr)
    251 }
    252 
    253 func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
    254 	if w == nil {
    255 		f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
    256 		if err != nil {
    257 			return
    258 		}
    259 		c.closeAfterStart = append(c.closeAfterStart, f)
    260 		return
    261 	}
    262 
    263 	if f, ok := w.(*os.File); ok {
    264 		return f, nil
    265 	}
    266 
    267 	pr, pw, err := os.Pipe()
    268 	if err != nil {
    269 		return
    270 	}
    271 
    272 	c.closeAfterStart = append(c.closeAfterStart, pw)
    273 	c.closeAfterWait = append(c.closeAfterWait, pr)
    274 	c.goroutine = append(c.goroutine, func() error {
    275 		_, err := io.Copy(w, pr)
    276 		pr.Close() // in case io.Copy stopped due to write error
    277 		return err
    278 	})
    279 	return pw, nil
    280 }
    281 
    282 func (c *Cmd) closeDescriptors(closers []io.Closer) {
    283 	for _, fd := range closers {
    284 		fd.Close()
    285 	}
    286 }
    287 
    288 // Run starts the specified command and waits for it to complete.
    289 //
    290 // The returned error is nil if the command runs, has no problems
    291 // copying stdin, stdout, and stderr, and exits with a zero exit
    292 // status.
    293 //
    294 // If the command starts but does not complete successfully, the error is of
    295 // type *ExitError. Other error types may be returned for other situations.
    296 //
    297 // If the calling goroutine has locked the operating system thread
    298 // with runtime.LockOSThread and modified any inheritable OS-level
    299 // thread state (for example, Linux or Plan 9 name spaces), the new
    300 // process will inherit the caller's thread state.
    301 func (c *Cmd) Run() error {
    302 	if err := c.Start(); err != nil {
    303 		return err
    304 	}
    305 	return c.Wait()
    306 }
    307 
    308 // lookExtensions finds windows executable by its dir and path.
    309 // It uses LookPath to try appropriate extensions.
    310 // lookExtensions does not search PATH, instead it converts `prog` into `.\prog`.
    311 func lookExtensions(path, dir string) (string, error) {
    312 	if filepath.Base(path) == path {
    313 		path = filepath.Join(".", path)
    314 	}
    315 	if dir == "" {
    316 		return LookPath(path)
    317 	}
    318 	if filepath.VolumeName(path) != "" {
    319 		return LookPath(path)
    320 	}
    321 	if len(path) > 1 && os.IsPathSeparator(path[0]) {
    322 		return LookPath(path)
    323 	}
    324 	dirandpath := filepath.Join(dir, path)
    325 	// We assume that LookPath will only add file extension.
    326 	lp, err := LookPath(dirandpath)
    327 	if err != nil {
    328 		return "", err
    329 	}
    330 	ext := strings.TrimPrefix(lp, dirandpath)
    331 	return path + ext, nil
    332 }
    333 
    334 // Start starts the specified command but does not wait for it to complete.
    335 //
    336 // The Wait method will return the exit code and release associated resources
    337 // once the command exits.
    338 func (c *Cmd) Start() error {
    339 	if c.lookPathErr != nil {
    340 		c.closeDescriptors(c.closeAfterStart)
    341 		c.closeDescriptors(c.closeAfterWait)
    342 		return c.lookPathErr
    343 	}
    344 	if runtime.GOOS == "windows" {
    345 		lp, err := lookExtensions(c.Path, c.Dir)
    346 		if err != nil {
    347 			c.closeDescriptors(c.closeAfterStart)
    348 			c.closeDescriptors(c.closeAfterWait)
    349 			return err
    350 		}
    351 		c.Path = lp
    352 	}
    353 	if c.Process != nil {
    354 		return errors.New("exec: already started")
    355 	}
    356 	if c.ctx != nil {
    357 		select {
    358 		case <-c.ctx.Done():
    359 			c.closeDescriptors(c.closeAfterStart)
    360 			c.closeDescriptors(c.closeAfterWait)
    361 			return c.ctx.Err()
    362 		default:
    363 		}
    364 	}
    365 
    366 	type F func(*Cmd) (*os.File, error)
    367 	for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
    368 		fd, err := setupFd(c)
    369 		if err != nil {
    370 			c.closeDescriptors(c.closeAfterStart)
    371 			c.closeDescriptors(c.closeAfterWait)
    372 			return err
    373 		}
    374 		c.childFiles = append(c.childFiles, fd)
    375 	}
    376 	c.childFiles = append(c.childFiles, c.ExtraFiles...)
    377 
    378 	var err error
    379 	c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
    380 		Dir:   c.Dir,
    381 		Files: c.childFiles,
    382 		Env:   dedupEnv(c.envv()),
    383 		Sys:   c.SysProcAttr,
    384 	})
    385 	if err != nil {
    386 		c.closeDescriptors(c.closeAfterStart)
    387 		c.closeDescriptors(c.closeAfterWait)
    388 		return err
    389 	}
    390 
    391 	c.closeDescriptors(c.closeAfterStart)
    392 
    393 	c.errch = make(chan error, len(c.goroutine))
    394 	for _, fn := range c.goroutine {
    395 		go func(fn func() error) {
    396 			c.errch <- fn()
    397 		}(fn)
    398 	}
    399 
    400 	if c.ctx != nil {
    401 		c.waitDone = make(chan struct{})
    402 		go func() {
    403 			select {
    404 			case <-c.ctx.Done():
    405 				c.Process.Kill()
    406 			case <-c.waitDone:
    407 			}
    408 		}()
    409 	}
    410 
    411 	return nil
    412 }
    413 
    414 // An ExitError reports an unsuccessful exit by a command.
    415 type ExitError struct {
    416 	*os.ProcessState
    417 
    418 	// Stderr holds a subset of the standard error output from the
    419 	// Cmd.Output method if standard error was not otherwise being
    420 	// collected.
    421 	//
    422 	// If the error output is long, Stderr may contain only a prefix
    423 	// and suffix of the output, with the middle replaced with
    424 	// text about the number of omitted bytes.
    425 	//
    426 	// Stderr is provided for debugging, for inclusion in error messages.
    427 	// Users with other needs should redirect Cmd.Stderr as needed.
    428 	Stderr []byte
    429 }
    430 
    431 func (e *ExitError) Error() string {
    432 	return e.ProcessState.String()
    433 }
    434 
    435 // Wait waits for the command to exit and waits for any copying to
    436 // stdin or copying from stdout or stderr to complete.
    437 //
    438 // The command must have been started by Start.
    439 //
    440 // The returned error is nil if the command runs, has no problems
    441 // copying stdin, stdout, and stderr, and exits with a zero exit
    442 // status.
    443 //
    444 // If the command fails to run or doesn't complete successfully, the
    445 // error is of type *ExitError. Other error types may be
    446 // returned for I/O problems.
    447 //
    448 // If any of c.Stdin, c.Stdout or c.Stderr are not an *os.File, Wait also waits
    449 // for the respective I/O loop copying to or from the process to complete.
    450 //
    451 // Wait releases any resources associated with the Cmd.
    452 func (c *Cmd) Wait() error {
    453 	if c.Process == nil {
    454 		return errors.New("exec: not started")
    455 	}
    456 	if c.finished {
    457 		return errors.New("exec: Wait was already called")
    458 	}
    459 	c.finished = true
    460 
    461 	state, err := c.Process.Wait()
    462 	if c.waitDone != nil {
    463 		close(c.waitDone)
    464 	}
    465 	c.ProcessState = state
    466 
    467 	var copyError error
    468 	for range c.goroutine {
    469 		if err := <-c.errch; err != nil && copyError == nil {
    470 			copyError = err
    471 		}
    472 	}
    473 
    474 	c.closeDescriptors(c.closeAfterWait)
    475 
    476 	if err != nil {
    477 		return err
    478 	} else if !state.Success() {
    479 		return &ExitError{ProcessState: state}
    480 	}
    481 
    482 	return copyError
    483 }
    484 
    485 // Output runs the command and returns its standard output.
    486 // Any returned error will usually be of type *ExitError.
    487 // If c.Stderr was nil, Output populates ExitError.Stderr.
    488 func (c *Cmd) Output() ([]byte, error) {
    489 	if c.Stdout != nil {
    490 		return nil, errors.New("exec: Stdout already set")
    491 	}
    492 	var stdout bytes.Buffer
    493 	c.Stdout = &stdout
    494 
    495 	captureErr := c.Stderr == nil
    496 	if captureErr {
    497 		c.Stderr = &prefixSuffixSaver{N: 32 << 10}
    498 	}
    499 
    500 	err := c.Run()
    501 	if err != nil && captureErr {
    502 		if ee, ok := err.(*ExitError); ok {
    503 			ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes()
    504 		}
    505 	}
    506 	return stdout.Bytes(), err
    507 }
    508 
    509 // CombinedOutput runs the command and returns its combined standard
    510 // output and standard error.
    511 func (c *Cmd) CombinedOutput() ([]byte, error) {
    512 	if c.Stdout != nil {
    513 		return nil, errors.New("exec: Stdout already set")
    514 	}
    515 	if c.Stderr != nil {
    516 		return nil, errors.New("exec: Stderr already set")
    517 	}
    518 	var b bytes.Buffer
    519 	c.Stdout = &b
    520 	c.Stderr = &b
    521 	err := c.Run()
    522 	return b.Bytes(), err
    523 }
    524 
    525 // StdinPipe returns a pipe that will be connected to the command's
    526 // standard input when the command starts.
    527 // The pipe will be closed automatically after Wait sees the command exit.
    528 // A caller need only call Close to force the pipe to close sooner.
    529 // For example, if the command being run will not exit until standard input
    530 // is closed, the caller must close the pipe.
    531 func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
    532 	if c.Stdin != nil {
    533 		return nil, errors.New("exec: Stdin already set")
    534 	}
    535 	if c.Process != nil {
    536 		return nil, errors.New("exec: StdinPipe after process started")
    537 	}
    538 	pr, pw, err := os.Pipe()
    539 	if err != nil {
    540 		return nil, err
    541 	}
    542 	c.Stdin = pr
    543 	c.closeAfterStart = append(c.closeAfterStart, pr)
    544 	wc := &closeOnce{File: pw}
    545 	c.closeAfterWait = append(c.closeAfterWait, wc)
    546 	return wc, nil
    547 }
    548 
    549 type closeOnce struct {
    550 	*os.File
    551 
    552 	once sync.Once
    553 	err  error
    554 }
    555 
    556 func (c *closeOnce) Close() error {
    557 	c.once.Do(c.close)
    558 	return c.err
    559 }
    560 
    561 func (c *closeOnce) close() {
    562 	c.err = c.File.Close()
    563 }
    564 
    565 // StdoutPipe returns a pipe that will be connected to the command's
    566 // standard output when the command starts.
    567 //
    568 // Wait will close the pipe after seeing the command exit, so most callers
    569 // need not close the pipe themselves; however, an implication is that
    570 // it is incorrect to call Wait before all reads from the pipe have completed.
    571 // For the same reason, it is incorrect to call Run when using StdoutPipe.
    572 // See the example for idiomatic usage.
    573 func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
    574 	if c.Stdout != nil {
    575 		return nil, errors.New("exec: Stdout already set")
    576 	}
    577 	if c.Process != nil {
    578 		return nil, errors.New("exec: StdoutPipe after process started")
    579 	}
    580 	pr, pw, err := os.Pipe()
    581 	if err != nil {
    582 		return nil, err
    583 	}
    584 	c.Stdout = pw
    585 	c.closeAfterStart = append(c.closeAfterStart, pw)
    586 	c.closeAfterWait = append(c.closeAfterWait, pr)
    587 	return pr, nil
    588 }
    589 
    590 // StderrPipe returns a pipe that will be connected to the command's
    591 // standard error when the command starts.
    592 //
    593 // Wait will close the pipe after seeing the command exit, so most callers
    594 // need not close the pipe themselves; however, an implication is that
    595 // it is incorrect to call Wait before all reads from the pipe have completed.
    596 // For the same reason, it is incorrect to use Run when using StderrPipe.
    597 // See the StdoutPipe example for idiomatic usage.
    598 func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
    599 	if c.Stderr != nil {
    600 		return nil, errors.New("exec: Stderr already set")
    601 	}
    602 	if c.Process != nil {
    603 		return nil, errors.New("exec: StderrPipe after process started")
    604 	}
    605 	pr, pw, err := os.Pipe()
    606 	if err != nil {
    607 		return nil, err
    608 	}
    609 	c.Stderr = pw
    610 	c.closeAfterStart = append(c.closeAfterStart, pw)
    611 	c.closeAfterWait = append(c.closeAfterWait, pr)
    612 	return pr, nil
    613 }
    614 
    615 // prefixSuffixSaver is an io.Writer which retains the first N bytes
    616 // and the last N bytes written to it. The Bytes() methods reconstructs
    617 // it with a pretty error message.
    618 type prefixSuffixSaver struct {
    619 	N         int // max size of prefix or suffix
    620 	prefix    []byte
    621 	suffix    []byte // ring buffer once len(suffix) == N
    622 	suffixOff int    // offset to write into suffix
    623 	skipped   int64
    624 
    625 	// TODO(bradfitz): we could keep one large []byte and use part of it for
    626 	// the prefix, reserve space for the '... Omitting N bytes ...' message,
    627 	// then the ring buffer suffix, and just rearrange the ring buffer
    628 	// suffix when Bytes() is called, but it doesn't seem worth it for
    629 	// now just for error messages. It's only ~64KB anyway.
    630 }
    631 
    632 func (w *prefixSuffixSaver) Write(p []byte) (n int, err error) {
    633 	lenp := len(p)
    634 	p = w.fill(&w.prefix, p)
    635 
    636 	// Only keep the last w.N bytes of suffix data.
    637 	if overage := len(p) - w.N; overage > 0 {
    638 		p = p[overage:]
    639 		w.skipped += int64(overage)
    640 	}
    641 	p = w.fill(&w.suffix, p)
    642 
    643 	// w.suffix is full now if p is non-empty. Overwrite it in a circle.
    644 	for len(p) > 0 { // 0, 1, or 2 iterations.
    645 		n := copy(w.suffix[w.suffixOff:], p)
    646 		p = p[n:]
    647 		w.skipped += int64(n)
    648 		w.suffixOff += n
    649 		if w.suffixOff == w.N {
    650 			w.suffixOff = 0
    651 		}
    652 	}
    653 	return lenp, nil
    654 }
    655 
    656 // fill appends up to len(p) bytes of p to *dst, such that *dst does not
    657 // grow larger than w.N. It returns the un-appended suffix of p.
    658 func (w *prefixSuffixSaver) fill(dst *[]byte, p []byte) (pRemain []byte) {
    659 	if remain := w.N - len(*dst); remain > 0 {
    660 		add := minInt(len(p), remain)
    661 		*dst = append(*dst, p[:add]...)
    662 		p = p[add:]
    663 	}
    664 	return p
    665 }
    666 
    667 func (w *prefixSuffixSaver) Bytes() []byte {
    668 	if w.suffix == nil {
    669 		return w.prefix
    670 	}
    671 	if w.skipped == 0 {
    672 		return append(w.prefix, w.suffix...)
    673 	}
    674 	var buf bytes.Buffer
    675 	buf.Grow(len(w.prefix) + len(w.suffix) + 50)
    676 	buf.Write(w.prefix)
    677 	buf.WriteString("\n... omitting ")
    678 	buf.WriteString(strconv.FormatInt(w.skipped, 10))
    679 	buf.WriteString(" bytes ...\n")
    680 	buf.Write(w.suffix[w.suffixOff:])
    681 	buf.Write(w.suffix[:w.suffixOff])
    682 	return buf.Bytes()
    683 }
    684 
    685 func minInt(a, b int) int {
    686 	if a < b {
    687 		return a
    688 	}
    689 	return b
    690 }
    691 
    692 // dedupEnv returns a copy of env with any duplicates removed, in favor of
    693 // later values.
    694 // Items not of the normal environment "key=value" form are preserved unchanged.
    695 func dedupEnv(env []string) []string {
    696 	return dedupEnvCase(runtime.GOOS == "windows", env)
    697 }
    698 
    699 // dedupEnvCase is dedupEnv with a case option for testing.
    700 // If caseInsensitive is true, the case of keys is ignored.
    701 func dedupEnvCase(caseInsensitive bool, env []string) []string {
    702 	out := make([]string, 0, len(env))
    703 	saw := map[string]int{} // key => index into out
    704 	for _, kv := range env {
    705 		eq := strings.Index(kv, "=")
    706 		if eq < 0 {
    707 			out = append(out, kv)
    708 			continue
    709 		}
    710 		k := kv[:eq]
    711 		if caseInsensitive {
    712 			k = strings.ToLower(k)
    713 		}
    714 		if dupIdx, isDup := saw[k]; isDup {
    715 			out[dupIdx] = kv
    716 			continue
    717 		}
    718 		saw[k] = len(out)
    719 		out = append(out, kv)
    720 	}
    721 	return out
    722 }
    723