...

Source file src/github.com/shirou/gopsutil/process/process_posix.go

Documentation: github.com/shirou/gopsutil/process

     1  // +build linux freebsd openbsd darwin solaris
     2  
     3  package process
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"os"
     9  	"os/user"
    10  	"path/filepath"
    11  	"strconv"
    12  	"strings"
    13  	"syscall"
    14  
    15  	"github.com/shirou/gopsutil/internal/common"
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  // POSIX
    20  func getTerminalMap() (map[uint64]string, error) {
    21  	ret := make(map[uint64]string)
    22  	var termfiles []string
    23  
    24  	d, err := os.Open("/dev")
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	defer d.Close()
    29  
    30  	devnames, err := d.Readdirnames(-1)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	for _, devname := range devnames {
    35  		if strings.HasPrefix(devname, "/dev/tty") {
    36  			termfiles = append(termfiles, "/dev/tty/"+devname)
    37  		}
    38  	}
    39  
    40  	var ptsnames []string
    41  	ptsd, err := os.Open("/dev/pts")
    42  	if err != nil {
    43  		ptsnames, _ = filepath.Glob("/dev/ttyp*")
    44  		if ptsnames == nil {
    45  			return nil, err
    46  		}
    47  	}
    48  	defer ptsd.Close()
    49  
    50  	if ptsnames == nil {
    51  		defer ptsd.Close()
    52  		ptsnames, err = ptsd.Readdirnames(-1)
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  		for _, ptsname := range ptsnames {
    57  			termfiles = append(termfiles, "/dev/pts/"+ptsname)
    58  		}
    59  	} else {
    60  		termfiles = ptsnames
    61  	}
    62  
    63  	for _, name := range termfiles {
    64  		stat := unix.Stat_t{}
    65  		if err = unix.Stat(name, &stat); err != nil {
    66  			return nil, err
    67  		}
    68  		rdev := uint64(stat.Rdev)
    69  		ret[rdev] = strings.Replace(name, "/dev", "", -1)
    70  	}
    71  	return ret, nil
    72  }
    73  
    74  // isMount is a port of python's os.path.ismount()
    75  // https://github.com/python/cpython/blob/08ff4369afca84587b1c82034af4e9f64caddbf2/Lib/posixpath.py#L186-L216
    76  // https://docs.python.org/3/library/os.path.html#os.path.ismount
    77  func isMount(path string) bool {
    78  	// Check symlinkness with os.Lstat; unix.DT_LNK is not portable
    79  	fileInfo, err := os.Lstat(path)
    80  	if err != nil {
    81  		return false
    82  	}
    83  	if fileInfo.Mode() & os.ModeSymlink != 0 {
    84  		return false
    85  	}
    86  	var stat1 unix.Stat_t
    87  	if err := unix.Lstat(path, &stat1); err != nil {
    88  		return false
    89  	}
    90  	parent := filepath.Join(path, "..")
    91  	var stat2 unix.Stat_t
    92  	if err := unix.Lstat(parent, &stat2); err != nil {
    93  		return false
    94  	}
    95  	return stat1.Dev != stat2.Dev || stat1.Ino == stat2.Ino
    96  }
    97  
    98  func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
    99  	if pid <= 0 {
   100  		return false, fmt.Errorf("invalid pid %v", pid)
   101  	}
   102  	proc, err := os.FindProcess(int(pid))
   103  	if err != nil {
   104  		return false, err
   105  	}
   106  
   107  	if isMount(common.HostProc()) { // if /<HOST_PROC>/proc exists and is mounted, check if /<HOST_PROC>/proc/<PID> folder exists
   108  		_, err := os.Stat(common.HostProc(strconv.Itoa(int(pid))))
   109  		if os.IsNotExist(err) {
   110  			return false, nil
   111  		}
   112  		return err == nil, err
   113  	}
   114  
   115  	// procfs does not exist or is not mounted, check PID existence by signalling the pid
   116  	err = proc.Signal(syscall.Signal(0))
   117  	if err == nil {
   118  		return true, nil
   119  	}
   120  	if err.Error() == "os: process already finished" {
   121  		return false, nil
   122  	}
   123  	errno, ok := err.(syscall.Errno)
   124  	if !ok {
   125  		return false, err
   126  	}
   127  	switch errno {
   128  	case syscall.ESRCH:
   129  		return false, nil
   130  	case syscall.EPERM:
   131  		return true, nil
   132  	}
   133  
   134  	return false, err
   135  }
   136  
   137  func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
   138  	process, err := os.FindProcess(int(p.Pid))
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	err = process.Signal(sig)
   144  	if err != nil {
   145  		return err
   146  	}
   147  
   148  	return nil
   149  }
   150  
   151  func (p *Process) SuspendWithContext(ctx context.Context) error {
   152  	return p.SendSignalWithContext(ctx, unix.SIGSTOP)
   153  }
   154  
   155  func (p *Process) ResumeWithContext(ctx context.Context) error {
   156  	return p.SendSignalWithContext(ctx, unix.SIGCONT)
   157  }
   158  
   159  func (p *Process) TerminateWithContext(ctx context.Context) error {
   160  	return p.SendSignalWithContext(ctx, unix.SIGTERM)
   161  }
   162  
   163  func (p *Process) KillWithContext(ctx context.Context) error {
   164  	return p.SendSignalWithContext(ctx, unix.SIGKILL)
   165  }
   166  
   167  func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
   168  	uids, err := p.UidsWithContext(ctx)
   169  	if err != nil {
   170  		return "", err
   171  	}
   172  	if len(uids) > 0 {
   173  		u, err := user.LookupId(strconv.Itoa(int(uids[0])))
   174  		if err != nil {
   175  			return "", err
   176  		}
   177  		return u.Username, nil
   178  	}
   179  	return "", nil
   180  }
   181  

View as plain text