xref: /aosp_15_r20/external/toybox/toys/posix/kill.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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