github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/process/process_posix.go (about) 1 //go:build linux || freebsd || openbsd || darwin 2 // +build linux freebsd openbsd darwin 3 4 package process 5 6 import ( 7 "context" 8 "fmt" 9 "os" 10 "os/user" 11 "path/filepath" 12 "strconv" 13 "strings" 14 "syscall" 15 16 "github.com/gofiber/fiber/v2/internal/gopsutil/common" 17 "golang.org/x/sys/unix" 18 ) 19 20 // POSIX 21 func getTerminalMap() (map[uint64]string, error) { 22 ret := make(map[uint64]string) 23 var termfiles []string 24 25 d, err := os.Open("/dev") 26 if err != nil { 27 return nil, err 28 } 29 defer d.Close() 30 31 devnames, err := d.Readdirnames(-1) 32 if err != nil { 33 return nil, err 34 } 35 for _, devname := range devnames { 36 if strings.HasPrefix(devname, "/dev/tty") { 37 termfiles = append(termfiles, "/dev/tty/"+devname) 38 } 39 } 40 41 var ptsnames []string 42 ptsd, err := os.Open("/dev/pts") 43 if err != nil { 44 ptsnames, _ = filepath.Glob("/dev/ttyp*") 45 if ptsnames == nil { 46 return nil, err 47 } 48 } 49 defer ptsd.Close() 50 51 if ptsnames == nil { 52 defer ptsd.Close() 53 ptsnames, err = ptsd.Readdirnames(-1) 54 if err != nil { 55 return nil, err 56 } 57 for _, ptsname := range ptsnames { 58 termfiles = append(termfiles, "/dev/pts/"+ptsname) 59 } 60 } else { 61 termfiles = ptsnames 62 } 63 64 for _, name := range termfiles { 65 stat := unix.Stat_t{} 66 if err = unix.Stat(name, &stat); err != nil { 67 return nil, err 68 } 69 rdev := uint64(stat.Rdev) 70 ret[rdev] = strings.Replace(name, "/dev", "", -1) 71 } 72 return ret, nil 73 } 74 75 func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { 76 if pid <= 0 { 77 return false, fmt.Errorf("invalid pid %v", pid) 78 } 79 proc, err := os.FindProcess(int(pid)) 80 if err != nil { 81 return false, err 82 } 83 84 if _, err := os.Stat(common.HostProc()); err == nil { //Means that proc filesystem exist 85 // Checking PID existence based on existence of /<HOST_PROC>/proc/<PID> folder 86 // This covers the case when running inside container with a different process namespace (by default) 87 88 _, err := os.Stat(common.HostProc(strconv.Itoa(int(pid)))) 89 if os.IsNotExist(err) { 90 return false, nil 91 } 92 return err == nil, err 93 } 94 95 //'/proc' filesystem is not exist, checking of PID existence is done via signalling the process 96 //Make sense only if we run in the same process namespace 97 err = proc.Signal(syscall.Signal(0)) 98 if err == nil { 99 return true, nil 100 } 101 if err.Error() == "os: process already finished" { 102 return false, nil 103 } 104 errno, ok := err.(syscall.Errno) 105 if !ok { 106 return false, err 107 } 108 switch errno { 109 case syscall.ESRCH: 110 return false, nil 111 case syscall.EPERM: 112 return true, nil 113 } 114 115 return false, err 116 } 117 118 // SendSignal sends a unix.Signal to the process. 119 // Currently, SIGSTOP, SIGCONT, SIGTERM and SIGKILL are supported. 120 func (p *Process) SendSignal(sig syscall.Signal) error { 121 return p.SendSignalWithContext(context.Background(), sig) 122 } 123 124 func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error { 125 process, err := os.FindProcess(int(p.Pid)) 126 if err != nil { 127 return err 128 } 129 130 err = process.Signal(sig) 131 if err != nil { 132 return err 133 } 134 135 return nil 136 } 137 138 // Suspend sends SIGSTOP to the process. 139 func (p *Process) Suspend() error { 140 return p.SuspendWithContext(context.Background()) 141 } 142 143 func (p *Process) SuspendWithContext(ctx context.Context) error { 144 return p.SendSignal(unix.SIGSTOP) 145 } 146 147 // Resume sends SIGCONT to the process. 148 func (p *Process) Resume() error { 149 return p.ResumeWithContext(context.Background()) 150 } 151 152 func (p *Process) ResumeWithContext(ctx context.Context) error { 153 return p.SendSignal(unix.SIGCONT) 154 } 155 156 // Terminate sends SIGTERM to the process. 157 func (p *Process) Terminate() error { 158 return p.TerminateWithContext(context.Background()) 159 } 160 161 func (p *Process) TerminateWithContext(ctx context.Context) error { 162 return p.SendSignal(unix.SIGTERM) 163 } 164 165 // Kill sends SIGKILL to the process. 166 func (p *Process) Kill() error { 167 return p.KillWithContext(context.Background()) 168 } 169 170 func (p *Process) KillWithContext(ctx context.Context) error { 171 return p.SendSignal(unix.SIGKILL) 172 } 173 174 // Username returns a username of the process. 175 func (p *Process) Username() (string, error) { 176 return p.UsernameWithContext(context.Background()) 177 } 178 179 func (p *Process) UsernameWithContext(ctx context.Context) (string, error) { 180 uids, err := p.Uids() 181 if err != nil { 182 return "", err 183 } 184 if len(uids) > 0 { 185 u, err := user.LookupId(strconv.Itoa(int(uids[0]))) 186 if err != nil { 187 return "", err 188 } 189 return u.Username, nil 190 } 191 return "", nil 192 }