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