2021-05-04 04:24:50 +08:00
|
|
|
// +build linux freebsd openbsd darwin solaris
|
2014-04-24 17:28:45 +08:00
|
|
|
|
2014-12-30 21:09:05 +08:00
|
|
|
package process
|
2014-04-24 17:28:45 +08:00
|
|
|
|
|
|
|
import (
|
2017-12-31 14:25:49 +08:00
|
|
|
"context"
|
2019-07-07 02:42:36 +08:00
|
|
|
"fmt"
|
2014-04-24 17:28:45 +08:00
|
|
|
"os"
|
2014-09-19 21:41:29 +08:00
|
|
|
"os/user"
|
2016-11-22 06:18:52 +08:00
|
|
|
"path/filepath"
|
2014-04-25 17:05:02 +08:00
|
|
|
"strconv"
|
2014-04-24 17:28:45 +08:00
|
|
|
"strings"
|
|
|
|
"syscall"
|
2017-06-03 04:51:00 +08:00
|
|
|
|
2020-01-17 19:06:07 +08:00
|
|
|
"github.com/shirou/gopsutil/internal/common"
|
2017-06-03 04:51:00 +08:00
|
|
|
"golang.org/x/sys/unix"
|
2014-04-24 17:28:45 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// POSIX
|
|
|
|
func getTerminalMap() (map[uint64]string, error) {
|
|
|
|
ret := make(map[uint64]string)
|
2014-04-30 15:16:07 +08:00
|
|
|
var termfiles []string
|
2014-04-24 17:28:45 +08:00
|
|
|
|
|
|
|
d, err := os.Open("/dev")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer d.Close()
|
|
|
|
|
|
|
|
devnames, err := d.Readdirnames(-1)
|
2018-06-21 22:53:53 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2014-04-24 17:28:45 +08:00
|
|
|
for _, devname := range devnames {
|
|
|
|
if strings.HasPrefix(devname, "/dev/tty") {
|
|
|
|
termfiles = append(termfiles, "/dev/tty/"+devname)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-22 06:18:52 +08:00
|
|
|
var ptsnames []string
|
2014-04-24 17:28:45 +08:00
|
|
|
ptsd, err := os.Open("/dev/pts")
|
|
|
|
if err != nil {
|
2016-11-22 06:18:52 +08:00
|
|
|
ptsnames, _ = filepath.Glob("/dev/ttyp*")
|
|
|
|
if ptsnames == nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2014-04-24 17:28:45 +08:00
|
|
|
}
|
2017-02-22 21:46:23 +08:00
|
|
|
defer ptsd.Close()
|
|
|
|
|
2016-11-22 06:18:52 +08:00
|
|
|
if ptsnames == nil {
|
|
|
|
defer ptsd.Close()
|
|
|
|
ptsnames, err = ptsd.Readdirnames(-1)
|
2018-06-21 22:53:53 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-11-22 06:18:52 +08:00
|
|
|
for _, ptsname := range ptsnames {
|
|
|
|
termfiles = append(termfiles, "/dev/pts/"+ptsname)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
termfiles = ptsnames
|
2014-04-24 17:28:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, name := range termfiles {
|
2017-06-03 04:51:00 +08:00
|
|
|
stat := unix.Stat_t{}
|
|
|
|
if err = unix.Stat(name, &stat); err != nil {
|
2014-08-16 01:09:43 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
2014-04-24 18:14:00 +08:00
|
|
|
rdev := uint64(stat.Rdev)
|
2014-04-24 17:28:45 +08:00
|
|
|
ret[rdev] = strings.Replace(name, "/dev", "", -1)
|
|
|
|
}
|
|
|
|
return ret, nil
|
|
|
|
}
|
2014-04-25 17:05:02 +08:00
|
|
|
|
2021-03-19 06:32:09 +08:00
|
|
|
// 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 {
|
2021-05-04 04:20:56 +08:00
|
|
|
// 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 {
|
2021-03-19 06:32:09 +08:00
|
|
|
return false
|
|
|
|
}
|
2021-05-04 04:20:56 +08:00
|
|
|
var stat1 unix.Stat_t
|
|
|
|
if err := unix.Lstat(path, &stat1); err != nil {
|
2021-03-19 06:32:09 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-07-07 02:42:36 +08:00
|
|
|
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
|
|
|
|
}
|
2021-05-04 04:20:56 +08:00
|
|
|
|
2021-03-19 06:32:09 +08:00
|
|
|
if isMount(common.HostProc()) { // if /<HOST_PROC>/proc exists and is mounted, check if /<HOST_PROC>/proc/<PID> folder exists
|
2020-01-17 19:06:07 +08:00
|
|
|
_, err := os.Stat(common.HostProc(strconv.Itoa(int(pid))))
|
2020-02-14 22:44:43 +08:00
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return false, nil
|
|
|
|
}
|
2020-01-17 19:06:07 +08:00
|
|
|
return err == nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-19 06:32:09 +08:00
|
|
|
// procfs does not exist or is not mounted, check PID existence by signalling the pid
|
2019-07-07 02:42:36 +08:00
|
|
|
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
|
|
|
|
}
|
2020-01-17 19:06:07 +08:00
|
|
|
|
2019-07-07 02:42:36 +08:00
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
2017-12-31 14:25:49 +08:00
|
|
|
func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
|
2017-04-28 05:11:25 +08:00
|
|
|
process, err := os.FindProcess(int(p.Pid))
|
2016-04-01 21:13:05 +08:00
|
|
|
if err != nil {
|
2016-04-01 21:22:03 +08:00
|
|
|
return err
|
2016-04-01 21:13:05 +08:00
|
|
|
}
|
2017-04-28 05:11:25 +08:00
|
|
|
|
|
|
|
err = process.Signal(sig)
|
2014-04-25 17:05:02 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-12-31 14:25:49 +08:00
|
|
|
func (p *Process) SuspendWithContext(ctx context.Context) error {
|
2020-10-10 19:18:22 +08:00
|
|
|
return p.SendSignalWithContext(ctx, unix.SIGSTOP)
|
2017-12-31 14:25:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Process) ResumeWithContext(ctx context.Context) error {
|
2020-10-10 19:18:22 +08:00
|
|
|
return p.SendSignalWithContext(ctx, unix.SIGCONT)
|
2017-12-31 14:25:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Process) TerminateWithContext(ctx context.Context) error {
|
2020-10-10 19:18:22 +08:00
|
|
|
return p.SendSignalWithContext(ctx, unix.SIGTERM)
|
2017-12-31 14:25:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Process) KillWithContext(ctx context.Context) error {
|
2020-10-10 19:18:22 +08:00
|
|
|
return p.SendSignalWithContext(ctx, unix.SIGKILL)
|
2017-12-31 14:25:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
|
2020-10-10 19:18:22 +08:00
|
|
|
uids, err := p.UidsWithContext(ctx)
|
2014-08-29 20:38:01 +08:00
|
|
|
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
|
|
|
|
}
|