| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- // +build linux freebsd openbsd darwin solaris
- package process
- import (
- "context"
- "fmt"
- "os"
- "os/user"
- "path/filepath"
- "strconv"
- "strings"
- "syscall"
- "github.com/shirou/gopsutil/internal/common"
- "golang.org/x/sys/unix"
- )
- // POSIX
- func getTerminalMap() (map[uint64]string, error) {
- ret := make(map[uint64]string)
- var termfiles []string
- d, err := os.Open("/dev")
- if err != nil {
- return nil, err
- }
- defer d.Close()
- devnames, err := d.Readdirnames(-1)
- if err != nil {
- return nil, err
- }
- for _, devname := range devnames {
- if strings.HasPrefix(devname, "/dev/tty") {
- termfiles = append(termfiles, "/dev/tty/"+devname)
- }
- }
- var ptsnames []string
- ptsd, err := os.Open("/dev/pts")
- if err != nil {
- ptsnames, _ = filepath.Glob("/dev/ttyp*")
- if ptsnames == nil {
- return nil, err
- }
- }
- defer ptsd.Close()
- if ptsnames == nil {
- defer ptsd.Close()
- ptsnames, err = ptsd.Readdirnames(-1)
- if err != nil {
- return nil, err
- }
- for _, ptsname := range ptsnames {
- termfiles = append(termfiles, "/dev/pts/"+ptsname)
- }
- } else {
- termfiles = ptsnames
- }
- for _, name := range termfiles {
- stat := unix.Stat_t{}
- if err = unix.Stat(name, &stat); err != nil {
- return nil, err
- }
- rdev := uint64(stat.Rdev)
- ret[rdev] = strings.Replace(name, "/dev", "", -1)
- }
- return ret, nil
- }
- // isMount is a port of python's os.path.ismount()
- // https://github.com/python/cpython/blob/08ff4369afca84587b1c82034af4e9f64caddbf2/Lib/posixpath.py#L186-L216
- // https://docs.python.org/3/library/os.path.html#os.path.ismount
- func isMount(path string) bool {
- // Check symlinkness with os.Lstat; unix.DT_LNK is not portable
- fileInfo, err := os.Lstat(path)
- if err != nil {
- return false
- }
- if fileInfo.Mode() & os.ModeSymlink != 0 {
- return false
- }
- var stat1 unix.Stat_t
- if err := unix.Lstat(path, &stat1); err != nil {
- return false
- }
- parent := filepath.Join(path, "..")
- var stat2 unix.Stat_t
- if err := unix.Lstat(parent, &stat2); err != nil {
- return false
- }
- return stat1.Dev != stat2.Dev || stat1.Ino == stat2.Ino
- }
- func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
- if pid <= 0 {
- return false, fmt.Errorf("invalid pid %v", pid)
- }
- proc, err := os.FindProcess(int(pid))
- if err != nil {
- return false, err
- }
- if isMount(common.HostProc()) { // if /<HOST_PROC>/proc exists and is mounted, check if /<HOST_PROC>/proc/<PID> folder exists
- _, err := os.Stat(common.HostProc(strconv.Itoa(int(pid))))
- if os.IsNotExist(err) {
- return false, nil
- }
- return err == nil, err
- }
- // procfs does not exist or is not mounted, check PID existence by signalling the pid
- err = proc.Signal(syscall.Signal(0))
- if err == nil {
- return true, nil
- }
- if err.Error() == "os: process already finished" {
- return false, nil
- }
- errno, ok := err.(syscall.Errno)
- if !ok {
- return false, err
- }
- switch errno {
- case syscall.ESRCH:
- return false, nil
- case syscall.EPERM:
- return true, nil
- }
- return false, err
- }
- func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
- process, err := os.FindProcess(int(p.Pid))
- if err != nil {
- return err
- }
- err = process.Signal(sig)
- if err != nil {
- return err
- }
- return nil
- }
- func (p *Process) SuspendWithContext(ctx context.Context) error {
- return p.SendSignalWithContext(ctx, unix.SIGSTOP)
- }
- func (p *Process) ResumeWithContext(ctx context.Context) error {
- return p.SendSignalWithContext(ctx, unix.SIGCONT)
- }
- func (p *Process) TerminateWithContext(ctx context.Context) error {
- return p.SendSignalWithContext(ctx, unix.SIGTERM)
- }
- func (p *Process) KillWithContext(ctx context.Context) error {
- return p.SendSignalWithContext(ctx, unix.SIGKILL)
- }
- func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
- uids, err := p.UidsWithContext(ctx)
- if err != nil {
- return "", err
- }
- if len(uids) > 0 {
- u, err := user.LookupId(strconv.Itoa(int(uids[0])))
- if err != nil {
- return "", err
- }
- return u.Username, nil
- }
- return "", nil
- }
|