|
1 | | -import std/[os, posix, strformat, strutils, sets] |
| 1 | +import std/[os, posix, strformat, strutils, sets, tables] |
2 | 2 |
|
3 | | -proc killall*(processName: string, signal: cint, excludePid: int = -1): bool = |
4 | | - var killed = false |
5 | | - |
| 3 | +proc getParentPid(pid: int): int = |
| 4 | + try: |
| 5 | + let stat = readFile(&"/proc/{pid}/stat") |
| 6 | + let afterComm = stat.find(')') |
| 7 | + if afterComm < 0: |
| 8 | + return -1 |
| 9 | + let fields = stat[afterComm + 2 .. ^1].splitWhitespace() |
| 10 | + if fields.len >= 2: |
| 11 | + result = parseInt(fields[1]) |
| 12 | + else: |
| 13 | + result = -1 |
| 14 | + except CatchableError: |
| 15 | + result = -1 |
| 16 | + |
| 17 | +proc getProcessMap(): Table[string, seq[int]] = |
| 18 | + result = initTable[string, seq[int]]() |
6 | 19 | for kind, path in walkDir("/proc"): |
7 | | - if kind == pcDir: |
8 | | - let name = path.extractFilename() |
9 | | - try: |
10 | | - let pid = parseInt(name) |
11 | | - if pid == excludePid: |
12 | | - continue |
13 | | - |
14 | | - let commPath = path / "comm" |
15 | | - if fileExists(commPath): |
16 | | - let comm = readFile(commPath).strip() |
17 | | - |
18 | | - if comm == processName: |
19 | | - if kill(cint(pid), signal) == 0: |
20 | | - killed = true |
21 | | - except ValueError: |
22 | | - continue |
23 | | - |
24 | | - result = killed |
| 20 | + if kind != pcDir: |
| 21 | + continue |
| 22 | + let name = path.extractFilename() |
| 23 | + try: |
| 24 | + let pid = parseInt(name) |
| 25 | + let commPath = path / "comm" |
| 26 | + if fileExists(commPath): |
| 27 | + let comm = readFile(commPath).strip() |
| 28 | + if comm notin result: |
| 29 | + result[comm] = @[] |
| 30 | + result[comm].add(pid) |
| 31 | + except CatchableError: |
| 32 | + continue |
| 33 | + |
| 34 | +proc killall*(processName: string, signal: cint, excludePid: int = -1): bool = |
| 35 | + let processMap = getProcessMap() |
| 36 | + if processName notin processMap: |
| 37 | + return false |
| 38 | + |
| 39 | + for pid in processMap[processName]: |
| 40 | + if pid == excludePid: |
| 41 | + continue |
| 42 | + if kill(cint(pid), signal) == 0: |
| 43 | + result = true |
25 | 44 |
|
26 | 45 | proc getProcessChildren*(ppid: int, pids: var HashSet[int]) = |
27 | 46 | for kind, path in walkDir("/proc"): |
28 | | - if kind == pcDir: |
29 | | - let name = path.extractFilename() |
30 | | - if name.len > 0 and name[0].isDigit: |
31 | | - try: |
32 | | - let pid = parseInt(name) |
33 | | - let statPath = &"/proc/{pid}/stat" |
34 | | - if fileExists(statPath): |
35 | | - let stat = readFile(statPath) |
36 | | - var fields = 0 |
37 | | - var parentPid = 0 |
38 | | - var inParen = false |
39 | | - var field = "" |
40 | | - |
41 | | - for c in stat: |
42 | | - if c == '(': |
43 | | - inParen = true |
44 | | - elif c == ')': |
45 | | - inParen = false |
46 | | - elif c == ' ' and not inParen: |
47 | | - inc fields |
48 | | - if fields == 4: |
49 | | - try: |
50 | | - parentPid = parseInt(field) |
51 | | - except ValueError: |
52 | | - discard |
53 | | - break |
54 | | - field = "" |
55 | | - else: |
56 | | - if not inParen or fields > 0: |
57 | | - field.add(c) |
58 | | - |
59 | | - if parentPid == ppid: |
60 | | - pids.incl(pid) |
61 | | - getProcessChildren(pid, pids) |
62 | | - except: |
63 | | - discard |
| 47 | + if kind != pcDir: |
| 48 | + continue |
| 49 | + let name = path.extractFilename() |
| 50 | + if name.len == 0 or not name[0].isDigit: |
| 51 | + continue |
| 52 | + try: |
| 53 | + let pid = parseInt(name) |
| 54 | + if getParentPid(pid) == ppid: |
| 55 | + pids.incl(pid) |
| 56 | + getProcessChildren(pid, pids) |
| 57 | + except CatchableError: |
| 58 | + continue |
0 commit comments