go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/procfs/processes.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package procfs
     5  
     6  import (
     7  	"bufio"
     8  	"bytes"
     9  	"io"
    10  	"regexp"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/rs/zerolog/log"
    15  )
    16  
    17  type LinuxProcess struct {
    18  	Pid     int64               `json:"pid"`
    19  	Cmdline string              `json:"cmdline"`
    20  	Status  *LinuxProcessStatus `json:"status"`
    21  }
    22  
    23  type LinuxProcessStatus struct {
    24  	// lets assume pids are always unsigned, linux returns -1 on unsuccessful forks but that
    25  	// is never becoming a real process
    26  	Pid        int64  `json:"pid"`        // process id
    27  	PPid       int64  `json:"ppid"`       // process id of the parent process
    28  	Executable string `json:"executable"` // filename of the executable
    29  	State      string `json:"state"`
    30  	Tgid       int64  `json:"tgid"` // thread group ID
    31  	Ngid       int64  `json:"ngid"` // NUMA group ID (0 if none)
    32  }
    33  
    34  var LINUX_PROCES_STATUS_REGEX = regexp.MustCompile(`^(.*):\s*(.*)$`)
    35  
    36  func ParseProcessStatus(input io.Reader) (*LinuxProcessStatus, error) {
    37  	lps := &LinuxProcessStatus{}
    38  	var err error
    39  	scanner := bufio.NewScanner(input)
    40  	for scanner.Scan() {
    41  		line := scanner.Text()
    42  		m := LINUX_PROCES_STATUS_REGEX.FindStringSubmatch(line)
    43  
    44  		if m == nil {
    45  			log.Warn().Str("entry", line).Msg("ignore process status entry")
    46  			continue
    47  		}
    48  
    49  		key := m[1]
    50  		value := m[2]
    51  		switch key {
    52  		case "Name":
    53  			lps.Executable = value
    54  		case "State": // state (R is running, S is sleeping, D is sleeping
    55  			// in an uninterruptible wait, Z is zombie, T is traced or stopped)
    56  			lps.State = value
    57  		case "Pid":
    58  			if lps.Pid, err = strconv.ParseInt(value, 10, 64); err != nil {
    59  				log.Warn().Err(err).Str("key", key).Msg("process> could not parse value")
    60  				continue
    61  			}
    62  		case "PPid":
    63  			if lps.Pid, err = strconv.ParseInt(value, 10, 64); err != nil {
    64  				log.Warn().Err(err).Str("key", key).Msg("process> could not parse value")
    65  				continue
    66  			}
    67  		case "Tgid":
    68  			if lps.Tgid, err = strconv.ParseInt(value, 10, 64); err != nil {
    69  				log.Warn().Err(err).Str("key", key).Msg("process> could not parse value")
    70  				continue
    71  			}
    72  		case "Ngid":
    73  			if lps.Ngid, err = strconv.ParseInt(value, 10, 64); err != nil {
    74  				log.Warn().Err(err).Str("key", key).Msg("process> could not parse value")
    75  				continue
    76  			}
    77  		case "Uid": // Real, effective, saved set, and  file system UIDs
    78  
    79  		case "Gid": // Real, effective, saved set, and  file system GIDs
    80  
    81  		case "Umask", "TracerPid", "FDSize", "Groups", "VmPeak", "VmSize", "VmLck", "VmPin",
    82  			"VmHWM", "VmRSS", "RssAnon", "RssFile", "RssShmem", "VmData", "VmStk", "VmExe", "VmLib",
    83  			"VmPTE", "VmSwap", "Threads", "SigQ", "SigPnd", "ShdPnd", "SigBlk", "SigIgn", "SigCgt",
    84  			"CapInh", "CapPrm", "CapEff", "CapBnd", "CapAmb", "Seccomp", "Cpus_allowed", "Cpus_allowed_list",
    85  			"Mems_allowed", "Mems_allowed_list", "voluntary_ctxt_switches", "nonvoluntary_ctxt_switches":
    86  			// known, nothing to do yet
    87  		default:
    88  			log.Debug().Str("key", key).Msg("process status key is not handled")
    89  		}
    90  	}
    91  
    92  	// parse status via
    93  	return lps, nil
    94  }
    95  
    96  func ParseProcessCmdline(content io.Reader) (string, error) {
    97  	data, err := io.ReadAll(content)
    98  	if err != nil {
    99  		return "", err
   100  	}
   101  
   102  	parts := bytes.Split(data, []byte{0})
   103  	var strParts []string
   104  	for _, p := range parts {
   105  		strParts = append(strParts, strings.TrimSpace(string(p)))
   106  	}
   107  
   108  	return strings.Join(strParts, " "), nil
   109  }