1
2
3 package process
4
5 import (
6 "bytes"
7 "context"
8 "os/exec"
9 "path/filepath"
10 "strconv"
11 "strings"
12
13 cpu "github.com/shirou/gopsutil/cpu"
14 "github.com/shirou/gopsutil/internal/common"
15 net "github.com/shirou/gopsutil/net"
16 "golang.org/x/sys/unix"
17 )
18
19 func pidsWithContext(ctx context.Context) ([]int32, error) {
20 var ret []int32
21 procs, err := ProcessesWithContext(ctx)
22 if err != nil {
23 return ret, nil
24 }
25
26 for _, p := range procs {
27 ret = append(ret, p.Pid)
28 }
29
30 return ret, nil
31 }
32
33 func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
34 k, err := p.getKProc()
35 if err != nil {
36 return 0, err
37 }
38
39 return k.Ppid, nil
40 }
41
42 func (p *Process) NameWithContext(ctx context.Context) (string, error) {
43 k, err := p.getKProc()
44 if err != nil {
45 return "", err
46 }
47 name := common.IntToString(k.Comm[:])
48
49 if len(name) >= 15 {
50 cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
51 if err != nil {
52 return "", err
53 }
54 if len(cmdlineSlice) > 0 {
55 extendedName := filepath.Base(cmdlineSlice[0])
56 if strings.HasPrefix(extendedName, p.name) {
57 name = extendedName
58 } else {
59 name = cmdlineSlice[0]
60 }
61 }
62 }
63
64 return name, nil
65 }
66
67 func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
68 return "", common.ErrNotImplementedError
69 }
70
71 func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
72 mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
73 buf, _, err := common.CallSyscall(mib)
74 if err != nil {
75 return "", err
76 }
77 ret := strings.FieldsFunc(string(buf), func(r rune) bool {
78 if r == '\u0000' {
79 return true
80 }
81 return false
82 })
83
84 return strings.Join(ret, " "), nil
85 }
86
87 func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
88 mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
89 buf, _, err := common.CallSyscall(mib)
90 if err != nil {
91 return nil, err
92 }
93 if len(buf) == 0 {
94 return nil, nil
95 }
96 if buf[len(buf)-1] == 0 {
97 buf = buf[:len(buf)-1]
98 }
99 parts := bytes.Split(buf, []byte{0})
100 var strParts []string
101 for _, p := range parts {
102 strParts = append(strParts, string(p))
103 }
104
105 return strParts, nil
106 }
107
108 func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
109 return 0, common.ErrNotImplementedError
110 }
111
112 func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
113 return nil, common.ErrNotImplementedError
114 }
115
116 func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
117 k, err := p.getKProc()
118 if err != nil {
119 return "", err
120 }
121 var s string
122 switch k.Stat {
123 case SIDL:
124 s = "I"
125 case SRUN:
126 s = "R"
127 case SSLEEP:
128 s = "S"
129 case SSTOP:
130 s = "T"
131 case SZOMB:
132 s = "Z"
133 case SWAIT:
134 s = "W"
135 case SLOCK:
136 s = "L"
137 }
138
139 return s, nil
140 }
141
142 func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
143
144 pid := p.Pid
145 ps, err := exec.LookPath("ps")
146 if err != nil {
147 return false, err
148 }
149 out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", strconv.Itoa(int(pid)))
150 if err != nil {
151 return false, err
152 }
153 return strings.IndexByte(string(out), '+') != -1, nil
154 }
155
156 func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
157 k, err := p.getKProc()
158 if err != nil {
159 return nil, err
160 }
161
162 uids := make([]int32, 0, 3)
163
164 uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid))
165
166 return uids, nil
167 }
168
169 func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
170 k, err := p.getKProc()
171 if err != nil {
172 return nil, err
173 }
174
175 gids := make([]int32, 0, 3)
176 gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid))
177
178 return gids, nil
179 }
180
181 func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) {
182 k, err := p.getKProc()
183 if err != nil {
184 return nil, err
185 }
186
187 groups := make([]int32, k.Ngroups)
188 for i := int16(0); i < k.Ngroups; i++ {
189 groups[i] = int32(k.Groups[i])
190 }
191
192 return groups, nil
193 }
194
195 func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
196 k, err := p.getKProc()
197 if err != nil {
198 return "", err
199 }
200
201 ttyNr := uint64(k.Tdev)
202
203 termmap, err := getTerminalMap()
204 if err != nil {
205 return "", err
206 }
207
208 return termmap[ttyNr], nil
209 }
210
211 func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
212 k, err := p.getKProc()
213 if err != nil {
214 return 0, err
215 }
216 return int32(k.Nice), nil
217 }
218
219 func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
220 k, err := p.getKProc()
221 if err != nil {
222 return nil, err
223 }
224 return &IOCountersStat{
225 ReadCount: uint64(k.Rusage.Inblock),
226 WriteCount: uint64(k.Rusage.Oublock),
227 }, nil
228 }
229
230 func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
231 k, err := p.getKProc()
232 if err != nil {
233 return 0, err
234 }
235
236 return k.Numthreads, nil
237 }
238
239 func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
240 k, err := p.getKProc()
241 if err != nil {
242 return nil, err
243 }
244 return &cpu.TimesStat{
245 CPU: "cpu",
246 User: float64(k.Rusage.Utime.Sec) + float64(k.Rusage.Utime.Usec)/1000000,
247 System: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000,
248 }, nil
249 }
250
251 func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
252 k, err := p.getKProc()
253 if err != nil {
254 return nil, err
255 }
256 v, err := unix.Sysctl("vm.stats.vm.v_page_size")
257 if err != nil {
258 return nil, err
259 }
260 pageSize := common.LittleEndian.Uint16([]byte(v))
261
262 return &MemoryInfoStat{
263 RSS: uint64(k.Rssize) * uint64(pageSize),
264 VMS: uint64(k.Size),
265 }, nil
266 }
267
268 func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
269 pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
270 if err != nil {
271 return nil, err
272 }
273 ret := make([]*Process, 0, len(pids))
274 for _, pid := range pids {
275 np, err := NewProcessWithContext(ctx, pid)
276 if err != nil {
277 return nil, err
278 }
279 ret = append(ret, np)
280 }
281 return ret, nil
282 }
283
284 func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
285 return nil, common.ErrNotImplementedError
286 }
287
288 func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) {
289 return nil, common.ErrNotImplementedError
290 }
291
292 func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
293 results := []*Process{}
294
295 mib := []int32{CTLKern, KernProc, KernProcProc, 0}
296 buf, length, err := common.CallSyscall(mib)
297 if err != nil {
298 return results, err
299 }
300
301
302 count := int(length / uint64(sizeOfKinfoProc))
303
304
305 for i := 0; i < count; i++ {
306 b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
307 k, err := parseKinfoProc(b)
308 if err != nil {
309 continue
310 }
311 p, err := NewProcessWithContext(ctx, int32(k.Pid))
312 if err != nil {
313 continue
314 }
315
316 results = append(results, p)
317 }
318
319 return results, nil
320 }
321
322 func (p *Process) getKProc() (*KinfoProc, error) {
323 mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
324
325 buf, length, err := common.CallSyscall(mib)
326 if err != nil {
327 return nil, err
328 }
329 if length != sizeOfKinfoProc {
330 return nil, err
331 }
332
333 k, err := parseKinfoProc(buf)
334 if err != nil {
335 return nil, err
336 }
337 return &k, nil
338 }
339
View as plain text