killall - Add support for pts specifications
[dragonfly.git] / usr.bin / killall / killall.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
3 * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: src/usr.bin/killall/killall.c,v 1.5.2.4 2001/05/19 19:22:49 phk Exp $
5dfd06ac 28 * $DragonFly: src/usr.bin/killall/killall.c,v 1.9 2007/02/01 10:33:26 corecode Exp $
984263bc
MD
29 */
30
e0ecab34 31#include <sys/user.h>
984263bc
MD
32#include <sys/param.h>
33#include <sys/stat.h>
984263bc
MD
34#include <sys/sysctl.h>
35#include <fcntl.h>
36#include <dirent.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <pwd.h>
41#include <signal.h>
42#include <regex.h>
43#include <ctype.h>
44#include <err.h>
45#include <errno.h>
46#include <unistd.h>
47
48static char *prog;
49
50static void __dead2
51usage(void)
52{
53
c5017cd9
MD
54 fprintf(stderr, "usage: %s [-l] [-v] [-m] [-sig] "
55 "[-u user] [-j jail] [-t tty] "
56 "[-c cmd] [cmd]...\n", prog);
57 fprintf(stderr, "At least one option or argument to specify "
58 "processes must be given.\n");
984263bc
MD
59 exit(1);
60}
61
62static char *
63upper(const char *str)
64{
65 static char buf[80];
66 char *s;
67
0ec73fda 68 strlcpy(buf, str, sizeof(buf));
984263bc 69 for (s = buf; *s; s++)
a38bc7f3 70 *s = toupper((unsigned char)*s);
984263bc
MD
71 return buf;
72}
73
74
75static void
76printsig(FILE *fp)
77{
78 const char *const * p;
79 int cnt;
80 int offset = 0;
81
82 for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
83 offset += fprintf(fp, "%s ", upper(*p));
84 if (offset >= 75 && cnt > 1) {
85 offset = 0;
86 fprintf(fp, "\n");
87 }
88 }
89 fprintf(fp, "\n");
90}
91
92static void
93nosig(char *name)
94{
95
96 warnx("unknown signal %s; valid signals:", name);
97 printsig(stderr);
98 exit(1);
99}
100
101int
102main(int ac, char **av)
103{
104 struct kinfo_proc *procs = NULL, *newprocs;
105 struct stat sb;
106 struct passwd *pw;
107 regex_t rgx;
108 regmatch_t pmatch;
109 int i, j;
110 char buf[256];
111 char *user = NULL;
112 char *tty = NULL;
113 char *cmd = NULL;
0ec73fda 114 int qflag = 0;
984263bc
MD
115 int vflag = 0;
116 int sflag = 0;
35048f4d 117 int jflag = 0, jailid = 0;
984263bc
MD
118 int dflag = 0;
119 int mflag = 0;
120 uid_t uid = 0;
121 dev_t tdev = 0;
1991012b 122 pid_t mypid;
984263bc
MD
123 char thiscmd[MAXCOMLEN + 1];
124 pid_t thispid;
125 uid_t thisuid;
126 dev_t thistdev;
127 int sig = SIGTERM;
128 const char *const *p;
129 char *ep;
130 int errors = 0;
131 int mib[4];
132 size_t miblen;
133 int st, nprocs;
134 size_t size;
135 int matched;
136 int killed = 0;
137
138 prog = av[0];
139 av++;
140 ac--;
141
142 while (ac > 0) {
143 if (strcmp(*av, "-l") == 0) {
144 printsig(stdout);
145 exit(0);
146 }
147 if (strcmp(*av, "-help") == 0)
148 usage();
149 if (**av == '-') {
150 ++*av;
151 switch (**av) {
152 case 'u':
153 ++*av;
154 if (**av == '\0')
155 ++av;
156 --ac;
157 user = *av;
158 break;
159 case 't':
160 ++*av;
161 if (**av == '\0')
162 ++av;
163 --ac;
164 tty = *av;
165 break;
166 case 'c':
167 ++*av;
168 if (**av == '\0')
169 ++av;
170 --ac;
171 cmd = *av;
172 break;
35048f4d
JS
173 case 'j':
174 {
175 const char *errstr;
176 ++*av;
177 if (**av == '\0')
178 ++av;
179 --ac;
180 jailid = strtonum(*av, 1, INT_MAX, &errstr);
181
182 if (errstr)
183 errx(1, "jail id is %s: %s", errstr, *av);
184 jflag++;
185 break;
186 }
0ec73fda
HP
187 case 'q':
188 qflag++;
189 break;
984263bc
MD
190 case 'v':
191 vflag++;
192 break;
193 case 's':
194 sflag++;
195 break;
196 case 'd':
197 dflag++;
198 break;
199 case 'm':
200 mflag++;
201 break;
202 default:
a38bc7f3 203 if (isalpha((unsigned char)**av)) {
984263bc
MD
204 if (strncasecmp(*av, "sig", 3) == 0)
205 *av += 3;
206 for (sig = NSIG, p = sys_signame + 1;
207 --sig; ++p)
208 if (strcasecmp(*p, *av) == 0) {
209 sig = p - sys_signame;
210 break;
211 }
212 if (!sig)
213 nosig(*av);
a38bc7f3 214 } else if (isdigit((unsigned char)**av)) {
984263bc
MD
215 sig = strtol(*av, &ep, 10);
216 if (!*av || *ep)
217 errx(1, "illegal signal number: %s", *av);
c24db2df 218 if (sig < 0 || sig >= NSIG)
984263bc
MD
219 nosig(*av);
220 } else
221 nosig(*av);
222 }
223 ++av;
224 --ac;
225 } else {
226 break;
227 }
228 }
229
35048f4d 230 if (user == NULL && tty == NULL && cmd == NULL && jflag == 0 && ac == 0)
984263bc
MD
231 usage();
232
233 if (tty) {
234 if (strncmp(tty, "/dev/", 5) == 0)
235 snprintf(buf, sizeof(buf), "%s", tty);
236 else if (strncmp(tty, "tty", 3) == 0)
237 snprintf(buf, sizeof(buf), "/dev/%s", tty);
c5017cd9
MD
238 else if (isdigit(tty[0]))
239 snprintf(buf, sizeof(buf), "/dev/pts/%s", tty);
984263bc
MD
240 else
241 snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
242 if (stat(buf, &sb) < 0)
243 err(1, "stat(%s)", buf);
244 if (!S_ISCHR(sb.st_mode))
245 errx(1, "%s: not a character device", buf);
246 tdev = sb.st_rdev;
247 if (dflag)
248 printf("ttydev:0x%x\n", tdev);
249 }
250 if (user) {
251 pw = getpwnam(user);
252 if (pw == NULL)
253 errx(1, "user %s does not exist", user);
254 uid = pw->pw_uid;
255 if (dflag)
256 printf("uid:%d\n", uid);
257 } else {
258 uid = getuid();
259 if (uid != 0) {
260 pw = getpwuid(uid);
261 if (pw)
262 user = pw->pw_name;
263 if (dflag)
264 printf("uid:%d\n", uid);
265 }
266 }
267 size = 0;
268 mib[0] = CTL_KERN;
269 mib[1] = KERN_PROC;
270 mib[2] = KERN_PROC_ALL;
271 mib[3] = 0;
272 miblen = 3;
273
274 if (user && mib[2] == KERN_PROC_ALL) {
275 mib[2] = KERN_PROC_RUID;
276 mib[3] = uid;
277 miblen = 4;
278 }
279 if (tty && mib[2] == KERN_PROC_ALL) {
280 mib[2] = KERN_PROC_TTY;
281 mib[3] = tdev;
282 miblen = 4;
283 }
284
285 st = sysctl(mib, miblen, NULL, &size, NULL, 0);
286 do {
287 size += size / 10;
288 newprocs = realloc(procs, size);
289 if (newprocs == 0) {
290 if (procs)
291 free(procs);
292 errx(1, "could not reallocate memory");
293 }
294 procs = newprocs;
295 st = sysctl(mib, miblen, procs, &size, NULL, 0);
296 } while (st == -1 && errno == ENOMEM);
297 if (st == -1)
298 err(1, "could not sysctl(KERN_PROC)");
299 if (size % sizeof(struct kinfo_proc) != 0) {
a38bc7f3 300 fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
984263bc
MD
301 size, sizeof(struct kinfo_proc));
302 fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
303 exit(1);
304 }
305 nprocs = size / sizeof(struct kinfo_proc);
306 if (dflag)
307 printf("nprocs %d\n", nprocs);
1991012b 308 mypid = getpid();
984263bc
MD
309
310 for (i = 0; i < nprocs; i++) {
5dfd06ac
SS
311 thispid = procs[i].kp_pid;
312 strncpy(thiscmd, procs[i].kp_comm, MAXCOMLEN);
984263bc 313 thiscmd[MAXCOMLEN] = '\0';
5dfd06ac
SS
314 thistdev = procs[i].kp_tdev;
315 thisuid = procs[i].kp_ruid; /* real uid */
984263bc 316
1991012b
MD
317 if (thispid == mypid)
318 continue;
984263bc 319 matched = 1;
5dfd06ac 320 if ((int)procs[i].kp_pid < 0)
17c88c3a 321 matched = 0;
984263bc
MD
322 if (user) {
323 if (thisuid != uid)
324 matched = 0;
325 }
326 if (tty) {
327 if (thistdev != tdev)
328 matched = 0;
329 }
35048f4d 330 if (jflag) {
5dfd06ac 331 if (procs[i].kp_jailid != jailid)
35048f4d
JS
332 matched = 0;
333 }
984263bc
MD
334 if (cmd) {
335 if (mflag) {
336 if (regcomp(&rgx, cmd,
337 REG_EXTENDED|REG_NOSUB) != 0) {
338 mflag = 0;
339 warnx("%s: illegal regexp", cmd);
340 }
341 }
342 if (mflag) {
343 pmatch.rm_so = 0;
344 pmatch.rm_eo = strlen(thiscmd);
345 if (regexec(&rgx, thiscmd, 0, &pmatch,
346 REG_STARTEND) != 0)
347 matched = 0;
348 regfree(&rgx);
349 } else {
350 if (strcmp(thiscmd, cmd) != 0)
351 matched = 0;
352 }
353 }
354 if (matched == 0)
355 continue;
35048f4d
JS
356 if (ac > 0) {
357 matched = 0;
358 for (j = 0; j < ac; j++) {
359 if (mflag) {
360 if (regcomp(&rgx, av[j],
361 REG_EXTENDED|REG_NOSUB) != 0) {
362 mflag = 0;
363 warnx("%s: illegal regexp", av[j]);
364 }
984263bc 365 }
35048f4d
JS
366 if (mflag) {
367 pmatch.rm_so = 0;
368 pmatch.rm_eo = strlen(thiscmd);
369 if (regexec(&rgx, thiscmd, 0, &pmatch,
370 REG_STARTEND) == 0)
371 matched = 1;
372 regfree(&rgx);
373 } else {
374 if (strcmp(thiscmd, av[j]) == 0)
375 matched = 1;
376 }
377 if (matched)
378 break;
984263bc 379 }
35048f4d
JS
380 if (matched == 0)
381 continue;
984263bc 382 }
984263bc
MD
383 if (dflag)
384 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
385 thiscmd, thispid, thistdev, thisuid);
386
387 if (vflag || sflag)
388 printf("kill -%s %d\n", upper(sys_signame[sig]),
389 thispid);
390
391 killed++;
392 if (!dflag && !sflag) {
393 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
394 warn("kill -%s %d", upper(sys_signame[sig]),
395 thispid);
396 errors = 1;
397 }
398 }
399 }
0ec73fda 400 if (!qflag && killed == 0) {
984263bc
MD
401 fprintf(stderr, "No matching processes %swere found\n",
402 getuid() != 0 ? "belonging to you " : "");
403 errors = 1;
404 }
405 exit(errors);
406}