1/* See LICENSE file for copyright and license details. */
2
3#include <dirent.h>
4#include <limits.h>
5#include <signal.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10
11#include "proc.h"
12#include "queue.h"
13#include "util.h"
14
15struct {
16 const char *name;
17 int sig;
18} sigs[] = {
19#define SIG(n) {#n, SIG##n}
20 SIG(ABRT), SIG(ALRM), SIG(BUS), SIG(CHLD), SIG(CONT), SIG(FPE), SIG(HUP),
21 SIG(ILL), SIG(INT), SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
22 SIG(TERM), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2), SIG(URG),
23#undef SIG
24};
25
26struct pidentry {
27 pid_t pid;
28 SLIST_ENTRY(pidentry) entry;
29};
30
31static SLIST_HEAD(, pidentry) omitpid_head;
32
33static void
34usage(void)
35{
36 eprintf("usage: %s [-o pid1,pid2,..,pidN] [-s signal]\n", argv0);
37}
38
39// ?man killall5: send signal to all processes
40// ?man arguments: -o pid1
41// ?man send a signal to all processes except kernel threads
42int
43main(int argc, char *argv[])
44{
45 struct pidentry *pe;
46 struct dirent *entry;
47 DIR *dp;
48 char *p, *arg = NULL;
49 char *end, *v;
50 int oflag = 0;
51 int sig = SIGTERM;
52 pid_t pid;
53 size_t i;
54
55 ARGBEGIN
56 {
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 }
80 ARGEND;
81
82 SLIST_INIT(&omitpid_head);
83
84 if (oflag) {
85 for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) {
86 pe = emalloc(sizeof(*pe));
87 pe->pid = estrtol(p, 10);
88 SLIST_INSERT_HEAD(&omitpid_head, pe, entry);
89 }
90 }
91
92 if (sig != SIGSTOP && sig != SIGCONT)
93 kill(-1, SIGSTOP);
94
95 if (!(dp = opendir("/proc")))
96 eprintf("opendir /proc:");
97 while ((entry = readdir(dp))) {
98 if (pidfile(entry->d_name) == 0)
99 continue;
100 pid = estrtol(entry->d_name, 10);
101 if (pid == 1 || pid == getpid() || 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}