1
2
3 package process
4
5 import (
6 "context"
7 "fmt"
8 "os"
9 "os/user"
10 "path/filepath"
11 "strconv"
12 "strings"
13 "syscall"
14
15 "github.com/shirou/gopsutil/internal/common"
16 "golang.org/x/sys/unix"
17 )
18
19
20 func getTerminalMap() (map[uint64]string, error) {
21 ret := make(map[uint64]string)
22 var termfiles []string
23
24 d, err := os.Open("/dev")
25 if err != nil {
26 return nil, err
27 }
28 defer d.Close()
29
30 devnames, err := d.Readdirnames(-1)
31 if err != nil {
32 return nil, err
33 }
34 for _, devname := range devnames {
35 if strings.HasPrefix(devname, "/dev/tty") {
36 termfiles = append(termfiles, "/dev/tty/"+devname)
37 }
38 }
39
40 var ptsnames []string
41 ptsd, err := os.Open("/dev/pts")
42 if err != nil {
43 ptsnames, _ = filepath.Glob("/dev/ttyp*")
44 if ptsnames == nil {
45 return nil, err
46 }
47 }
48 defer ptsd.Close()
49
50 if ptsnames == nil {
51 defer ptsd.Close()
52 ptsnames, err = ptsd.Readdirnames(-1)
53 if err != nil {
54 return nil, err
55 }
56 for _, ptsname := range ptsnames {
57 termfiles = append(termfiles, "/dev/pts/"+ptsname)
58 }
59 } else {
60 termfiles = ptsnames
61 }
62
63 for _, name := range termfiles {
64 stat := unix.Stat_t{}
65 if err = unix.Stat(name, &stat); err != nil {
66 return nil, err
67 }
68 rdev := uint64(stat.Rdev)
69 ret[rdev] = strings.Replace(name, "/dev", "", -1)
70 }
71 return ret, nil
72 }
73
74
75
76
77 func isMount(path string) bool {
78
79 fileInfo, err := os.Lstat(path)
80 if err != nil {
81 return false
82 }
83 if fileInfo.Mode() & os.ModeSymlink != 0 {
84 return false
85 }
86 var stat1 unix.Stat_t
87 if err := unix.Lstat(path, &stat1); err != nil {
88 return false
89 }
90 parent := filepath.Join(path, "..")
91 var stat2 unix.Stat_t
92 if err := unix.Lstat(parent, &stat2); err != nil {
93 return false
94 }
95 return stat1.Dev != stat2.Dev || stat1.Ino == stat2.Ino
96 }
97
98 func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
99 if pid <= 0 {
100 return false, fmt.Errorf("invalid pid %v", pid)
101 }
102 proc, err := os.FindProcess(int(pid))
103 if err != nil {
104 return false, err
105 }
106
107 if isMount(common.HostProc()) {
108 _, err := os.Stat(common.HostProc(strconv.Itoa(int(pid))))
109 if os.IsNotExist(err) {
110 return false, nil
111 }
112 return err == nil, err
113 }
114
115
116 err = proc.Signal(syscall.Signal(0))
117 if err == nil {
118 return true, nil
119 }
120 if err.Error() == "os: process already finished" {
121 return false, nil
122 }
123 errno, ok := err.(syscall.Errno)
124 if !ok {
125 return false, err
126 }
127 switch errno {
128 case syscall.ESRCH:
129 return false, nil
130 case syscall.EPERM:
131 return true, nil
132 }
133
134 return false, err
135 }
136
137 func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
138 process, err := os.FindProcess(int(p.Pid))
139 if err != nil {
140 return err
141 }
142
143 err = process.Signal(sig)
144 if err != nil {
145 return err
146 }
147
148 return nil
149 }
150
151 func (p *Process) SuspendWithContext(ctx context.Context) error {
152 return p.SendSignalWithContext(ctx, unix.SIGSTOP)
153 }
154
155 func (p *Process) ResumeWithContext(ctx context.Context) error {
156 return p.SendSignalWithContext(ctx, unix.SIGCONT)
157 }
158
159 func (p *Process) TerminateWithContext(ctx context.Context) error {
160 return p.SendSignalWithContext(ctx, unix.SIGTERM)
161 }
162
163 func (p *Process) KillWithContext(ctx context.Context) error {
164 return p.SendSignalWithContext(ctx, unix.SIGKILL)
165 }
166
167 func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
168 uids, err := p.UidsWithContext(ctx)
169 if err != nil {
170 return "", err
171 }
172 if len(uids) > 0 {
173 u, err := user.LookupId(strconv.Itoa(int(uids[0])))
174 if err != nil {
175 return "", err
176 }
177 return u.Username, nil
178 }
179 return "", nil
180 }
181
View as plain text