mirror of
https://github.com/status-im/consul.git
synced 2025-01-15 16:26:06 +00:00
95c027a3ea
https://github.com/shirou/gopsutil/pull/895 is merged and fixes our problem. Time to update. Since there is no new version just yet, updating to the sha.
192 lines
4.2 KiB
Go
192 lines
4.2 KiB
Go
// +build linux freebsd openbsd darwin
|
|
|
|
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
|
|
}
|
|
|
|
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 _, err := os.Stat(common.HostProc()); err == nil { //Means that proc filesystem exist
|
|
// Checking PID existence based on existence of /<HOST_PROC>/proc/<PID> folder
|
|
// This covers the case when running inside container with a different process namespace (by default)
|
|
|
|
_, err := os.Stat(common.HostProc(strconv.Itoa(int(pid))))
|
|
if os.IsNotExist(err) {
|
|
return false, nil
|
|
}
|
|
return err == nil, err
|
|
}
|
|
|
|
//'/proc' filesystem is not exist, checking of PID existence is done via signalling the process
|
|
//Make sense only if we run in the same process namespace
|
|
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
|
|
}
|
|
|
|
// SendSignal sends a unix.Signal to the process.
|
|
// Currently, SIGSTOP, SIGCONT, SIGTERM and SIGKILL are supported.
|
|
func (p *Process) SendSignal(sig syscall.Signal) error {
|
|
return p.SendSignalWithContext(context.Background(), sig)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// Suspend sends SIGSTOP to the process.
|
|
func (p *Process) Suspend() error {
|
|
return p.SuspendWithContext(context.Background())
|
|
}
|
|
|
|
func (p *Process) SuspendWithContext(ctx context.Context) error {
|
|
return p.SendSignal(unix.SIGSTOP)
|
|
}
|
|
|
|
// Resume sends SIGCONT to the process.
|
|
func (p *Process) Resume() error {
|
|
return p.ResumeWithContext(context.Background())
|
|
}
|
|
|
|
func (p *Process) ResumeWithContext(ctx context.Context) error {
|
|
return p.SendSignal(unix.SIGCONT)
|
|
}
|
|
|
|
// Terminate sends SIGTERM to the process.
|
|
func (p *Process) Terminate() error {
|
|
return p.TerminateWithContext(context.Background())
|
|
}
|
|
|
|
func (p *Process) TerminateWithContext(ctx context.Context) error {
|
|
return p.SendSignal(unix.SIGTERM)
|
|
}
|
|
|
|
// Kill sends SIGKILL to the process.
|
|
func (p *Process) Kill() error {
|
|
return p.KillWithContext(context.Background())
|
|
}
|
|
|
|
func (p *Process) KillWithContext(ctx context.Context) error {
|
|
return p.SendSignal(unix.SIGKILL)
|
|
}
|
|
|
|
// Username returns a username of the process.
|
|
func (p *Process) Username() (string, error) {
|
|
return p.UsernameWithContext(context.Background())
|
|
}
|
|
|
|
func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
|
|
uids, err := p.Uids()
|
|
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
|
|
}
|