github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/abi/linux/wait.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package linux
    16  
    17  import (
    18  	"fmt"
    19  )
    20  
    21  // Options for waitpid(2), wait4(2), and/or waitid(2), from
    22  // include/uapi/linux/wait.h.
    23  const (
    24  	WNOHANG    = 0x00000001
    25  	WUNTRACED  = 0x00000002
    26  	WSTOPPED   = WUNTRACED
    27  	WEXITED    = 0x00000004
    28  	WCONTINUED = 0x00000008
    29  	WNOWAIT    = 0x01000000
    30  	WNOTHREAD  = 0x20000000
    31  	WALL       = 0x40000000
    32  	WCLONE     = 0x80000000
    33  )
    34  
    35  // ID types for waitid(2), from include/uapi/linux/wait.h.
    36  const (
    37  	P_ALL  = 0x0
    38  	P_PID  = 0x1
    39  	P_PGID = 0x2
    40  )
    41  
    42  // WaitStatus represents a thread status, as returned by the wait* family of
    43  // syscalls.
    44  type WaitStatus uint32
    45  
    46  // WaitStatusExit returns a WaitStatus representing the given exit status.
    47  func WaitStatusExit(status int32) WaitStatus {
    48  	return WaitStatus(uint32(status) << 8)
    49  }
    50  
    51  // WaitStatusTerminationSignal returns a WaitStatus representing termination by
    52  // the given signal.
    53  func WaitStatusTerminationSignal(sig Signal) WaitStatus {
    54  	return WaitStatus(uint32(sig))
    55  }
    56  
    57  // WaitStatusStopped returns a WaitStatus representing stoppage by the given
    58  // signal or ptrace trap code.
    59  func WaitStatusStopped(code uint32) WaitStatus {
    60  	return WaitStatus(code<<8 | 0x7f)
    61  }
    62  
    63  // WaitStatusContinued returns a WaitStatus representing continuation by
    64  // SIGCONT.
    65  func WaitStatusContinued() WaitStatus {
    66  	return WaitStatus(0xffff)
    67  }
    68  
    69  // WithCoreDump returns a copy of ws that indicates that a core dump was
    70  // generated.
    71  //
    72  // Preconditions: ws.Signaled().
    73  func (ws WaitStatus) WithCoreDump() WaitStatus {
    74  	return ws | 0x80
    75  }
    76  
    77  // Exited returns true if ws represents an exit status, consistent with
    78  // WIFEXITED.
    79  func (ws WaitStatus) Exited() bool {
    80  	return ws&0x7f == 0
    81  }
    82  
    83  // Signaled returns true if ws represents a termination by signal, consistent
    84  // with WIFSIGNALED.
    85  func (ws WaitStatus) Signaled() bool {
    86  	// ws&0x7f != 0 (exited) and ws&0x7f != 0x7f (stopped or continued)
    87  	return ((ws&0x7f)+1)>>1 != 0
    88  }
    89  
    90  // CoreDumped returns true if ws indicates that a core dump was produced,
    91  // consistent with WCOREDUMP.
    92  //
    93  // Preconditions: ws.Signaled().
    94  func (ws WaitStatus) CoreDumped() bool {
    95  	return ws&0x80 != 0
    96  }
    97  
    98  // Stopped returns true if ws represents a stoppage, consistent with
    99  // WIFSTOPPED.
   100  func (ws WaitStatus) Stopped() bool {
   101  	return ws&0xff == 0x7f
   102  }
   103  
   104  // Continued returns true if ws represents a continuation by SIGCONT,
   105  // consistent with WIFCONTINUED.
   106  func (ws WaitStatus) Continued() bool {
   107  	return ws == 0xffff
   108  }
   109  
   110  // ExitStatus returns the lower 8 bits of the exit status represented by ws,
   111  // consistent with WEXITSTATUS.
   112  //
   113  // Preconditions: ws.Exited().
   114  func (ws WaitStatus) ExitStatus() uint32 {
   115  	return uint32((ws & 0xff00) >> 8)
   116  }
   117  
   118  // TerminationSignal returns the termination signal represented by ws,
   119  // consistent with WTERMSIG.
   120  //
   121  // Preconditions: ws.Signaled().
   122  func (ws WaitStatus) TerminationSignal() Signal {
   123  	return Signal(ws & 0x7f)
   124  }
   125  
   126  // StopSignal returns the stop signal represented by ws, consistent with
   127  // WSTOPSIG.
   128  //
   129  // Preconditions: ws.Stopped().
   130  func (ws WaitStatus) StopSignal() Signal {
   131  	return Signal((ws & 0xff00) >> 8)
   132  }
   133  
   134  // PtraceEvent returns the PTRACE_EVENT_* field in ws.
   135  //
   136  // Preconditions: ws.Stopped().
   137  func (ws WaitStatus) PtraceEvent() uint32 {
   138  	return uint32(ws >> 16)
   139  }
   140  
   141  // String implements fmt.Stringer.String.
   142  func (ws WaitStatus) String() string {
   143  	switch {
   144  	case ws.Exited():
   145  		return fmt.Sprintf("exit status %d", ws.ExitStatus())
   146  	case ws.Signaled():
   147  		if ws.CoreDumped() {
   148  			return fmt.Sprintf("killed by signal %d (core dumped)", ws.TerminationSignal())
   149  		}
   150  		return fmt.Sprintf("killed by signal %d", ws.TerminationSignal())
   151  	case ws.Stopped():
   152  		if ev := ws.PtraceEvent(); ev != 0 {
   153  			return fmt.Sprintf("stopped by signal %d (PTRACE_EVENT %d)", ws.StopSignal(), ev)
   154  		}
   155  		return fmt.Sprintf("stopped by signal %d", ws.StopSignal())
   156  	case ws.Continued():
   157  		return "continued"
   158  	default:
   159  		return fmt.Sprintf("unknown status %#x", uint32(ws))
   160  	}
   161  }