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  }