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