github.com/haraldrudell/parl@v0.4.176/pexec/exit-error.go (about) 1 /* 2 © 2021–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package pexec 7 8 import ( 9 "errors" 10 "os/exec" 11 "syscall" 12 13 "golang.org/x/sys/unix" 14 ) 15 16 const ( 17 TerminatedBySignal = -1 18 ) 19 20 var _ = unix.SIGKILL + unix.SIGINT + unix.SIGTERM 21 22 // ExitError returns information on why the exec.Cmd.Start process terminated 23 // - if hasStatusCode is true, the process terminated with a status code 24 // - if hasStatusCode is false, exec.Cmd.Start failed prior to launch 25 // - if StatusCode has value -1 or pexec.TerminatedBySignal, the process terminated due to 26 // the signal signal. Common signals are: 27 // - — unix.SIGINT from ^C 28 // - — unix.SIGKILL from context termination 29 // - — unix.SIGTERM from operating-system process-termination 30 func ExitError(err error) (hasStatusCode bool, statusCode int, signal unix.Signal, stderr []byte) { 31 32 // determine if err contains an ExitError 33 // - ExitError is the error returned when a child process 34 // for executing a command was created and failed 35 var exitError *exec.ExitError 36 if hasStatusCode = errors.As(err, &exitError); !hasStatusCode { 37 return // not an ExitError return 38 } 39 40 // obtain possibly cached standard error output 41 // - if the Stderr field was not assigned and the process 42 // echoes to standard error and fails, then that output may have been 43 // cached in the ExitError 44 if len(exitError.Stderr) > 0 { 45 stderr = exitError.Stderr 46 } 47 48 // obtain the status code returned by the command 49 if statusCode = exitError.ExitCode(); statusCode != TerminatedBySignal { 50 return // is not terminated by signal 51 } 52 53 // handle terminated by signal 54 if waitStatus, ok := exitError.ProcessState.Sys().(syscall.WaitStatus); ok { 55 signal = waitStatus.Signal() 56 } 57 58 return 59 }