1 /* kill.c - a program to send signals to processes
2 *
3 * Copyright 2012 Daniel Walter <[email protected]>
4 *
5 * See http://opengroup.org/onlinepubs/9699919799/utilities/kill.html
6 *
7 * killall5.c - Send signal to all processes outside current session.
8 *
9 * Copyright 2014 Ranjan Kumar <[email protected]>
10 * Copyright 2014 Kyungwan Han <[email protected]>
11 *
12 * No Standard
13 *
14 * TODO: toysh jobspec support, -n -L
15
16 USE_KILL(NEWTOY(kill, "?ls: ", TOYFLAG_BIN|TOYFLAG_MAYFORK))
17 USE_KILLALL5(NEWTOY(killall5, "?o*ls: [!lo][!ls]", TOYFLAG_SBIN))
18
19 config KILL
20 bool "kill"
21 default y
22 help
23 usage: kill [-l [SIGNAL] | -s SIGNAL | -SIGNAL] PID...
24
25 Send signal to process(es).
26
27 -l List signal name(s) and number(s)
28 -s Send SIGNAL (default SIGTERM)
29
30 config KILLALL5
31 bool "killall5"
32 default y
33 depends on KILL
34 help
35 usage: killall5 [-l [SIGNAL]] [-SIGNAL|-s SIGNAL] [-o PID]...
36
37 Send a signal to all processes outside current session.
38
39 -l List signal name(s) and number(s)
40 -o PID Omit PID
41 -s Send SIGNAL (default SIGTERM)
42 */
43
44 // This has to match the filename:
45 #define FOR_kill
46 #define FORCE_FLAGS
47 #include "toys.h"
48
GLOBALS(char * s;struct arg_list * o;)49 GLOBALS(
50 char *s;
51 struct arg_list *o;
52 )
53
54 // But kill's flags are a subset of killall5's
55
56 #define FOR_killall5
57 #include "generated/flags.h"
58
59 void kill_main(void)
60 {
61 int signum;
62 char *tmp, **args = toys.optargs;
63 pid_t pid;
64
65 // list signal(s)
66 if (FLAG(l)) {
67 if (*args) {
68 int signum = sig_to_num(*args);
69 char *s = 0;
70
71 if (signum>=0) s = num_to_sig(signum&127);
72 if (isdigit(**args)) puts(s ? s : "UNKNOWN");
73 else printf("%d\n", signum);
74 } else list_signals();
75
76 return;
77 }
78
79 // signal must come before pids, so "kill -9 -1" isn't confusing.
80
81 if (!TT.s && *args && **args=='-') TT.s = *(args++)+1;
82 if (TT.s) {
83 char *arg;
84 int i = strtol(TT.s, &arg, 10);
85
86 if (!*arg) arg = num_to_sig(i);
87 else arg = TT.s;
88
89 if (!arg || -1 == (signum = sig_to_num(arg)))
90 error_exit("Unknown signal '%s'", arg);
91 } else signum = SIGTERM;
92
93 // is it killall5?
94 if (CFG_KILLALL5 && toys.which->name[4]=='a') {
95 DIR *dp;
96 struct dirent *entry;
97 int pid, sid;
98 long *olist = 0, ocount = 0;
99
100 // parse omit list
101 if (FLAG(o)) {
102 struct arg_list *ptr;
103
104 for (ptr = TT.o; ptr; ptr = ptr->next) ocount++;
105 olist = xmalloc(ocount*sizeof(long));
106 ocount = 0;
107 for (ptr = TT.o; ptr; ptr=ptr->next) olist[ocount++] = atolx(ptr->arg);
108 }
109
110 sid = getsid(pid = getpid());
111
112 if (!(dp = opendir("/proc"))) {
113 free(olist);
114 perror_exit("/proc");
115 }
116 while ((entry = readdir(dp))) {
117 int count, procpid, procsid;
118
119 if (!(procpid = atoi(entry->d_name))) continue;
120
121 snprintf(toybuf, sizeof(toybuf), "/proc/%d/stat", procpid);
122 if (!readfile(toybuf, toybuf, sizeof(toybuf))) continue;
123 // command name can have embedded space and/or )
124 if (!(tmp = strrchr(toybuf, ')'))
125 || sscanf(tmp, " %*c %*d %*d %d", &procsid) != 1) continue;
126 if (pid == procpid || sid == procsid || procpid == 1) continue;
127
128 // Check for kernel threads.
129 snprintf(toybuf, sizeof(toybuf), "/proc/%d/cmdline", procpid);
130 if (!readfile(toybuf, toybuf, sizeof(toybuf)) || !*toybuf) continue;
131
132 // Check with omit list.
133 for (count = 0; count < ocount; count++)
134 if (procpid == olist[count]) break;
135 if (count != ocount) continue;
136
137 kill(procpid, signum);
138 }
139 closedir(dp);
140 free(olist);
141
142 // is it kill?
143 } else {
144
145 // "<1" in optstr wouldn't cover this because "-SIGNAL"
146 if (!*args) help_exit("missing argument");
147
148 while (*args) {
149 char *arg = *(args++);
150
151 pid = estrtol(arg, &tmp, 10);
152 if (!errno && *tmp) errno = ESRCH;
153 if (errno || kill(pid, signum)<0) perror_msg("bad pid '%s'", arg);
154 }
155 }
156 }
157
killall5_main(void)158 void killall5_main(void)
159 {
160 kill_main();
161 }
162