1/* See LICENSE file for copyright and license details. */
2
3
4#include <dirent.h>
5#include <limits.h>
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11
12#include "proc.h"
13#include "queue.h"
14#include "util.h"
15
16struct {
17 const char *name;
18 int sig;
19} sigs[] = {
20#define SIG(n) { #n, SIG##n }
21 SIG(ABRT), SIG(ALRM), SIG(BUS), SIG(CHLD), SIG(CONT), SIG(FPE), SIG(HUP),
22 SIG(ILL), SIG(INT), SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
23 SIG(TERM), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2), SIG(URG),
24#undef SIG
25};
26
27struct pidentry {
28 pid_t pid;
29 SLIST_ENTRY(pidentry) entry;
30};
31
32static SLIST_HEAD(, pidentry) omitpid_head;
33
34static void
35usage(void)
36{
37 eprintf("usage: %s [-o pid1,pid2,..,pidN] [-s signal]\n", argv0);
38}
39
40// ?man killall5: send signal to all processes
41// ?man arguments: -o pid1
42// ?man send a signal to all processes except kernel threads
43int
44main(int argc, char *argv[])
45{
46 struct pidentry *pe;
47 struct dirent *entry;
48 DIR *dp;
49 char *p, *arg = NULL;
50 char *end, *v;
51 int oflag = 0;
52 int sig = SIGTERM;
53 pid_t pid;
54 size_t i;
55
56 ARGBEGIN {
57 // ?man -s:str: silent mode or print summary
58 case 's':
59 v = EARGF(usage());
60 sig = strtol(v, &end, 0);
61 if (*end == '\0')
62 break;
63 for (i = 0; i < LEN(sigs); i++) {
64 if (strcasecmp(v, sigs[i].name) == 0) {
65 sig = sigs[i].sig;
66 break;
67 }
68 }
69 if (i == LEN(sigs))
70 eprintf("%s: unknown signal\n", v);
71 break;
72 // ?man -o:str: specify output file
73 case 'o':
74 oflag = 1;
75 arg = EARGF(usage());
76 break;
77 default:
78 usage();
79 } ARGEND;
80
81 SLIST_INIT(&omitpid_head);
82
83 if (oflag) {
84 for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) {
85 pe = emalloc(sizeof(*pe));
86 pe->pid = estrtol(p, 10);
87 SLIST_INSERT_HEAD(&omitpid_head, pe, entry);
88 }
89 }
90
91 if (sig != SIGSTOP && sig != SIGCONT)
92 kill(-1, SIGSTOP);
93
94 if (!(dp = opendir("/proc")))
95 eprintf("opendir /proc:");
96 while ((entry = readdir(dp))) {
97 if (pidfile(entry->d_name) == 0)
98 continue;
99 pid = estrtol(entry->d_name, 10);
100 if (pid == 1 || pid == getpid() ||
101 getsid(pid) == getsid(0) || getsid(pid) == 0)
102 continue;
103 if (oflag == 1) {
104 SLIST_FOREACH(pe, &omitpid_head, entry)
105 if (pe->pid == pid)
106 break;
107 if (pe)
108 continue;
109 }
110 kill(pid, sig);
111 }
112 closedir(dp);
113
114 if (sig != SIGSTOP && sig != SIGCONT)
115 kill(-1, SIGCONT);
116
117 return 0;
118}