package process
import (
"context"
"errors"
"fmt"
"os"
"os/user"
"path/filepath"
"strconv"
"strings"
"syscall"
"golang.org/x/sys/unix"
"github.com/shirou/gopsutil/v3/internal/common"
)
type Signal = syscall .Signal
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 isMount(path string ) bool {
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 .HostProcWithContext (ctx )) {
_ , err := os .Stat (common .HostProcWithContext (ctx , strconv .Itoa (int (pid ))))
if os .IsNotExist (err ) {
return false , nil
}
return err == nil , err
}
err = proc .Signal (syscall .Signal (0 ))
if err == nil {
return true , nil
}
if errors .Is (err , os .ErrProcessDone ) {
return false , nil
}
var errno syscall .Errno
if !errors .As (err , &errno ) {
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
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .