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

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package processes
     5  
     6  import (
     7  	"path/filepath"
     8  	"strconv"
     9  
    10  	"github.com/cockroachdb/errors"
    11  	"github.com/rs/zerolog/log"
    12  	"github.com/spf13/afero"
    13  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    14  	"go.mondoo.com/cnquery/providers/os/resources/procfs"
    15  )
    16  
    17  type LinuxProcManager struct {
    18  	conn shared.Connection
    19  }
    20  
    21  func (lpm *LinuxProcManager) Name() string {
    22  	return "Linux Process Manager"
    23  }
    24  
    25  func (lpm *LinuxProcManager) List() ([]*OSProcess, error) {
    26  	// get all subdirectories of /proc, filter by numbers
    27  	f, err := lpm.conn.FileSystem().Open("/proc")
    28  	if err != nil {
    29  		return nil, errors.WithMessage(err, "failed to access /proc")
    30  	}
    31  
    32  	dirs, err := f.Readdirnames(-1)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  
    37  	res := []*OSProcess{}
    38  	for i := range dirs {
    39  		// we only parse directories that are numbers
    40  		pid, err := strconv.ParseInt(dirs[i], 10, 64)
    41  		if err != nil {
    42  			continue
    43  		}
    44  
    45  		// collect process info
    46  		proc, err := lpm.Process(pid)
    47  		if err != nil {
    48  			log.Warn().Err(err).Int64("pid", pid).Msg("mql[processes]> could not retrieve process information")
    49  			continue
    50  		}
    51  
    52  		res = append(res, proc)
    53  	}
    54  	return res, nil
    55  }
    56  
    57  // check that the pid directory exists
    58  func (lpm *LinuxProcManager) Exists(pid int64) (bool, error) {
    59  	pidPath := filepath.Join("/proc", strconv.FormatInt(pid, 10))
    60  	afutil := afero.Afero{Fs: lpm.conn.FileSystem()}
    61  	return afutil.Exists(pidPath)
    62  }
    63  
    64  func (lpm *LinuxProcManager) Process(pid int64) (*OSProcess, error) {
    65  	pidPath := filepath.Join("/proc", strconv.FormatInt(pid, 10))
    66  
    67  	exists, err := lpm.Exists(pid)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	if !exists {
    72  		return nil, errors.New("process " + strconv.FormatInt(pid, 10) + " does not exist: " + pidPath)
    73  	}
    74  
    75  	// parse the cmdline
    76  	cmdlinef, err := lpm.conn.FileSystem().Open(filepath.Join(pidPath, "cmdline"))
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	defer cmdlinef.Close()
    81  
    82  	cmdline, err := procfs.ParseProcessCmdline(cmdlinef)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	statusf, err := lpm.conn.FileSystem().Open(filepath.Join(pidPath, "status"))
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	defer statusf.Close()
    92  
    93  	status, err := procfs.ParseProcessStatus(statusf)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	socketInodes, socketInodesErr := lpm.procSocketInods(pid, pidPath)
    99  
   100  	process := &OSProcess{
   101  		Pid:               pid,
   102  		Executable:        status.Executable,
   103  		State:             status.State,
   104  		Command:           cmdline,
   105  		SocketInodes:      socketInodes,
   106  		SocketInodesError: socketInodesErr,
   107  	}
   108  
   109  	return process, nil
   110  }