Source file
src/os/exec/exec.go
Documentation: os/exec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
38
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
49
50
51
52 type Cmd struct {
53
54
55
56
57
58 Path string
59
60
61
62
63
64 Args []string
65
66
67
68
69
70
71
72 Env []string
73
74
75
76
77 Dir string
78
79
80
81
82
83
84
85
86
87
88
89
90
91 Stdin io.Reader
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 Stdout io.Writer
109 Stderr io.Writer
110
111
112
113
114 ExtraFiles []*os.File
115
116
117
118 SysProcAttr *syscall.SysProcAttr
119
120
121 Process *os.Process
122
123
124
125 ProcessState *os.ProcessState
126
127 ctx context.Context
128 lookPathErr error
129 finished bool
130 childFiles []*os.File
131 closeAfterStart []io.Closer
132 closeAfterWait []io.Closer
133 goroutine []func() error
134 errch chan error
135 waitDone chan struct{}
136 }
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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
167
168
169
170
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
181
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
204
205
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()
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
289
290
291
292
293
294
295
296
297
298
299
300
301 func (c *Cmd) Run() error {
302 if err := c.Start(); err != nil {
303 return err
304 }
305 return c.Wait()
306 }
307
308
309
310
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
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
335
336
337
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
415 type ExitError struct {
416 *os.ProcessState
417
418
419
420
421
422
423
424
425
426
427
428 Stderr []byte
429 }
430
431 func (e *ExitError) Error() string {
432 return e.ProcessState.String()
433 }
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
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
486
487
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
510
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
526
527
528
529
530
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
566
567
568
569
570
571
572
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
591
592
593
594
595
596
597
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
616
617
618 type prefixSuffixSaver struct {
619 N int
620 prefix []byte
621 suffix []byte
622 suffixOff int
623 skipped int64
624
625
626
627
628
629
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
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
644 for len(p) > 0 {
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
657
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
693
694
695 func dedupEnv(env []string) []string {
696 return dedupEnvCase(runtime.GOOS == "windows", env)
697 }
698
699
700
701 func dedupEnvCase(caseInsensitive bool, env []string) []string {
702 out := make([]string, 0, len(env))
703 saw := map[string]int{}
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
View as plain text