1 /* $OpenBSD: pkill.c,v 1.43 2021/09/01 15:54:40 deraadt Exp $ */
2 /* $NetBSD: pkill.c,v 1.5 2002/10/27 11:49:34 kleink Exp $ */
3
4 /*-
5 * Copyright (c) 2002 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Andrew Doran.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/types.h>
34 #include <sys/sysctl.h>
35 #include <sys/signal.h>
36 #include <sys/proc.h>
37 #include <sys/queue.h>
38 #include <sys/stat.h>
39 #include <sys/socket.h>
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdint.h>
44 #include <limits.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <signal.h>
48 #include <regex.h>
49 #include <ctype.h>
50 #include <kvm.h>
51 #include <err.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <errno.h>
55
56 #define STATUS_MATCH 0
57 #define STATUS_NOMATCH 1
58 #define STATUS_BADUSAGE 2
59 #define STATUS_ERROR 3
60
61 enum listtype {
62 LT_GENERIC,
63 LT_USER,
64 LT_GROUP,
65 LT_TTY,
66 LT_PGRP,
67 LT_SID,
68 LT_RTABLE
69 };
70
71 struct list {
72 SLIST_ENTRY(list) li_chain;
73 long li_number;
74 };
75
76 SLIST_HEAD(listhead, list);
77
78 struct kinfo_proc *plist;
79 char *selected;
80 const char *delim = "\n";
81 int nproc;
82 int pgrep;
83 int signum = SIGTERM;
84 int newest;
85 int oldest;
86 int quiet;
87 int inverse;
88 int longfmt;
89 int matchargs;
90 int fullmatch;
91 int confirmkill;
92 kvm_t *kd;
93 pid_t mypid;
94
95 struct listhead euidlist = SLIST_HEAD_INITIALIZER(list);
96 struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list);
97 struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list);
98 struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list);
99 struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list);
100 struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list);
101 struct listhead sidlist = SLIST_HEAD_INITIALIZER(list);
102 struct listhead rtablist = SLIST_HEAD_INITIALIZER(list);
103
104 static void __dead usage(void);
105 static int killact(struct kinfo_proc *, int);
106 static int grepact(struct kinfo_proc *, int);
107 static void makelist(struct listhead *, enum listtype, char *);
108 static char *getargv(struct kinfo_proc *);
109 static int askyn(struct kinfo_proc *);
110
111 extern char *__progname;
112
113 static char *
getargv(struct kinfo_proc * kp)114 getargv(struct kinfo_proc *kp)
115 {
116 static char buf[_POSIX2_LINE_MAX];
117 char **pargv;
118 size_t j;
119
120 if ((pargv = kvm_getargv(kd, kp, 0)) == NULL) {
121 strlcpy(buf, kp->p_comm, sizeof(buf));
122 return buf;
123 }
124
125 j = 0;
126 while (j < sizeof(buf) && *pargv != NULL) {
127 int ret;
128
129 ret = snprintf(buf + j, sizeof(buf) - j,
130 pargv[1] != NULL ? "%s " : "%s", pargv[0]);
131 if (ret >= sizeof(buf) - j)
132 j += sizeof(buf) - j - 1;
133 else if (ret > 0)
134 j += ret;
135 pargv++;
136 }
137 return buf;
138 }
139
140 int
main(int argc,char ** argv)141 main(int argc, char **argv)
142 {
143 char buf[_POSIX2_LINE_MAX], *mstr, *p, *q;
144 int i, j, ch, bestidx, rv, criteria;
145 int (*action)(struct kinfo_proc *, int);
146 struct kinfo_proc *kp;
147 struct list *li;
148 u_int32_t bestsec, bestusec;
149 regex_t reg;
150 regmatch_t regmatch;
151
152 if (strcmp(__progname, "pgrep") == 0) {
153 action = grepact;
154 pgrep = 1;
155 } else {
156 action = killact;
157 p = argv[1];
158
159 if (argc > 1 && p[0] == '-') {
160 p++;
161 i = (int)strtol(p, &q, 10);
162 if (*q == '\0') {
163 signum = i;
164 argv++;
165 argc--;
166 } else {
167 if (strncasecmp(p, "sig", 3) == 0)
168 p += 3;
169 for (i = 1; i < NSIG; i++)
170 if (strcasecmp(sys_signame[i], p) == 0)
171 break;
172 if (i != NSIG) {
173 signum = i;
174 argv++;
175 argc--;
176 }
177 }
178 }
179 }
180
181 criteria = 0;
182
183 while ((ch = getopt(argc, argv, "G:P:T:U:d:fg:Ilnoqs:t:u:vx")) != -1)
184 switch (ch) {
185 case 'G':
186 makelist(&rgidlist, LT_GROUP, optarg);
187 criteria = 1;
188 break;
189 case 'P':
190 makelist(&ppidlist, LT_GENERIC, optarg);
191 criteria = 1;
192 break;
193 case 'T':
194 makelist(&rtablist, LT_RTABLE, optarg);
195 criteria = 1;
196 break;
197 case 'U':
198 makelist(&ruidlist, LT_USER, optarg);
199 criteria = 1;
200 break;
201 case 'd':
202 if (!pgrep)
203 usage();
204 delim = optarg;
205 break;
206 case 'f':
207 matchargs = 1;
208 break;
209 case 'g':
210 makelist(&pgrplist, LT_PGRP, optarg);
211 criteria = 1;
212 break;
213 case 'I':
214 confirmkill = 1;
215 break;
216 case 'l':
217 longfmt = 1;
218 break;
219 case 'n':
220 newest = 1;
221 criteria = 1;
222 break;
223 case 'o':
224 oldest = 1;
225 criteria = 1;
226 break;
227 case 'q':
228 quiet = 1;
229 break;
230 case 's':
231 makelist(&sidlist, LT_SID, optarg);
232 criteria = 1;
233 break;
234 case 't':
235 makelist(&tdevlist, LT_TTY, optarg);
236 criteria = 1;
237 break;
238 case 'u':
239 makelist(&euidlist, LT_USER, optarg);
240 criteria = 1;
241 break;
242 case 'v':
243 inverse = 1;
244 break;
245 case 'x':
246 fullmatch = 1;
247 break;
248 default:
249 usage();
250 /* NOTREACHED */
251 }
252
253 argc -= optind;
254 argv += optind;
255 if (argc != 0)
256 criteria = 1;
257 if (!criteria || (newest && oldest))
258 usage();
259
260 mypid = getpid();
261
262 /*
263 * Retrieve the list of running processes from the kernel.
264 */
265 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf);
266 if (kd == NULL)
267 errx(STATUS_ERROR, "kvm_openfiles(): %s", buf);
268
269 plist = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc);
270 if (plist == NULL)
271 errx(STATUS_ERROR, "kvm_getprocs() failed");
272
273 if (matchargs == 0 && confirmkill == 0) {
274 if (action == killact) {
275 if (pledge("stdio proc", NULL) == -1)
276 err(STATUS_ERROR, "pledge");
277 } else if (action == grepact) {
278 if (pledge("stdio", NULL) == -1)
279 err(STATUS_ERROR, "pledge");
280 }
281 }
282
283 /*
284 * Allocate memory which will be used to keep track of the
285 * selection.
286 */
287 if ((selected = calloc(nproc, 1)) == NULL)
288 errx(STATUS_ERROR, "memory allocation failure");
289
290 /*
291 * Refine the selection.
292 */
293 for (; *argv != NULL; argv++) {
294 if ((rv = regcomp(®, *argv, REG_EXTENDED)) != 0) {
295 regerror(rv, ®, buf, sizeof(buf));
296 errx(STATUS_BADUSAGE, "bad expression: %s", buf);
297 }
298
299 for (i = 0, kp = plist; i < nproc; i++, kp++) {
300 if (kp->p_pid == mypid)
301 continue;
302
303 if (matchargs)
304 mstr = getargv(kp);
305 else
306 mstr = kp->p_comm;
307
308 rv = regexec(®, mstr, 1, ®match, 0);
309 if (rv == 0) {
310 if (fullmatch) {
311 if (regmatch.rm_so == 0 &&
312 regmatch.rm_eo == strlen(mstr))
313 selected[i] = 1;
314 } else
315 selected[i] = 1;
316 } else if (rv != REG_NOMATCH) {
317 regerror(rv, ®, buf, sizeof(buf));
318 errx(STATUS_ERROR, "regexec(): %s", buf);
319 }
320 }
321
322 regfree(®);
323 }
324
325 for (i = 0, kp = plist; i < nproc; i++, kp++) {
326 if (kp->p_pid == mypid)
327 continue;
328
329 SLIST_FOREACH(li, &ruidlist, li_chain)
330 if (kp->p_ruid == (uid_t)li->li_number)
331 break;
332 if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
333 selected[i] = 0;
334 continue;
335 }
336
337 SLIST_FOREACH(li, &rgidlist, li_chain)
338 if (kp->p_rgid == (gid_t)li->li_number)
339 break;
340 if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
341 selected[i] = 0;
342 continue;
343 }
344
345 SLIST_FOREACH(li, &euidlist, li_chain)
346 if (kp->p_uid == (uid_t)li->li_number)
347 break;
348 if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
349 selected[i] = 0;
350 continue;
351 }
352
353 SLIST_FOREACH(li, &ppidlist, li_chain)
354 if (kp->p_ppid == (uid_t)li->li_number)
355 break;
356 if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
357 selected[i] = 0;
358 continue;
359 }
360
361 SLIST_FOREACH(li, &pgrplist, li_chain)
362 if (kp->p__pgid == (uid_t)li->li_number)
363 break;
364 if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
365 selected[i] = 0;
366 continue;
367 }
368
369 SLIST_FOREACH(li, &tdevlist, li_chain) {
370 if (li->li_number == -1 &&
371 (kp->p_psflags & PS_CONTROLT) == 0)
372 break;
373 if (kp->p_tdev == (uid_t)li->li_number)
374 break;
375 }
376 if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
377 selected[i] = 0;
378 continue;
379 }
380
381 SLIST_FOREACH(li, &sidlist, li_chain)
382 if (kp->p_sid == (uid_t)li->li_number)
383 break;
384 if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
385 selected[i] = 0;
386 continue;
387 }
388
389 SLIST_FOREACH(li, &rtablist, li_chain)
390 if (kp->p_rtableid == (u_int32_t)li->li_number)
391 break;
392 if (SLIST_FIRST(&rtablist) != NULL && li == NULL) {
393 selected[i] = 0;
394 continue;
395 }
396
397 if (argc == 0)
398 selected[i] = 1;
399 }
400
401 if (newest || oldest) {
402 bestidx = -1;
403
404 if (newest)
405 bestsec = bestusec = 0;
406 else
407 bestsec = bestusec = UINT32_MAX;
408
409 for (i = 0, kp = plist; i < nproc; i++, kp++) {
410 if (!selected[i])
411 continue;
412
413 if ((newest && (kp->p_ustart_sec > bestsec ||
414 (kp->p_ustart_sec == bestsec
415 && kp->p_ustart_usec > bestusec)))
416 || (oldest && (kp->p_ustart_sec < bestsec ||
417 (kp->p_ustart_sec == bestsec
418 && kp->p_ustart_usec < bestusec)))) {
419
420 bestsec = kp->p_ustart_sec;
421 bestusec = kp->p_ustart_usec;
422 bestidx = i;
423 }
424 }
425
426 memset(selected, 0, nproc);
427 if (bestidx != -1)
428 selected[bestidx] = 1;
429 }
430
431 /*
432 * Take the appropriate action for each matched process, if any.
433 */
434 rv = STATUS_NOMATCH;
435 for (i = 0, j = 0, kp = plist; i < nproc; i++, kp++) {
436 if (kp->p_pid == mypid)
437 continue;
438 if (selected[i] == inverse)
439 continue;
440
441 switch ((*action)(kp, j++)) {
442 case STATUS_MATCH:
443 if (rv != STATUS_ERROR)
444 rv = STATUS_MATCH;
445 break;
446 case STATUS_NOMATCH:
447 j--;
448 break;
449 case STATUS_ERROR:
450 rv = STATUS_ERROR;
451 break;
452 }
453 }
454 if (pgrep && j && !quiet)
455 putchar('\n');
456
457 return(rv);
458 }
459
460 static void __dead
usage(void)461 usage(void)
462 {
463 const char *ustr;
464
465 if (pgrep)
466 ustr = "[-flnoqvx] [-d delim]";
467 else
468 ustr = "[-signal] [-fIlnoqvx]";
469
470 fprintf(stderr, "usage: %s %s [-G gid] [-g pgrp] [-P ppid] [-s sid]"
471 "\n\t[-T rtable] [-t tty] [-U uid] [-u euid] [pattern ...]\n",
472 __progname, ustr);
473
474 exit(STATUS_BADUSAGE);
475 }
476
477 static int
askyn(struct kinfo_proc * kp)478 askyn(struct kinfo_proc *kp)
479 {
480 int first, ch;
481
482 printf("kill %d %.60s? ", (int)kp->p_pid, getargv(kp));
483 fflush(stdout);
484
485 first = ch = getchar();
486 while (ch != '\n' && ch != EOF)
487 ch = getchar();
488 return (first == 'y' || first == 'Y');
489 }
490
491 static int
killact(struct kinfo_proc * kp,int dummy)492 killact(struct kinfo_proc *kp, int dummy)
493 {
494 int doit;
495
496 if (confirmkill) {
497 doit = askyn(kp);
498 } else {
499 if (longfmt && !quiet)
500 printf("%d %s\n", (int)kp->p_pid, kp->p_comm);
501 doit = 1;
502 }
503
504 if (doit && kill(kp->p_pid, signum) == -1) {
505 if (errno == ESRCH)
506 return (STATUS_NOMATCH);
507 warn("signalling pid %d", (int)kp->p_pid);
508 return (STATUS_ERROR);
509 }
510 return (STATUS_MATCH);
511 }
512
513 static int
grepact(struct kinfo_proc * kp,int printdelim)514 grepact(struct kinfo_proc *kp, int printdelim)
515 {
516 char **argv;
517
518 if (quiet)
519 return (STATUS_MATCH);
520 if (longfmt && matchargs)
521 if ((argv = kvm_getargv(kd, kp, 0)) == NULL)
522 return (errno == ESRCH ? STATUS_NOMATCH : STATUS_ERROR);
523 if (printdelim)
524 fputs(delim, stdout);
525 if (longfmt && matchargs) {
526 printf("%d ", (int)kp->p_pid);
527 for (; *argv != NULL; argv++) {
528 printf("%s", *argv);
529 if (argv[1] != NULL)
530 putchar(' ');
531 }
532 } else if (longfmt)
533 printf("%d %s", (int)kp->p_pid, kp->p_comm);
534 else
535 printf("%d", (int)kp->p_pid);
536
537 return (STATUS_MATCH);
538 }
539
540 static void
makelist(struct listhead * head,enum listtype type,char * src)541 makelist(struct listhead *head, enum listtype type, char *src)
542 {
543 struct list *li;
544 struct stat st;
545 char *sp, *p, buf[PATH_MAX];
546 uid_t uid;
547 gid_t gid;
548 int empty;
549
550 empty = 1;
551
552 while ((sp = strsep(&src, ",")) != NULL) {
553 if (*sp == '\0')
554 usage();
555
556 if ((li = malloc(sizeof(*li))) == NULL)
557 errx(STATUS_ERROR, "memory allocation failure");
558 SLIST_INSERT_HEAD(head, li, li_chain);
559 empty = 0;
560
561 li->li_number = strtol(sp, &p, 0);
562 if (*p == '\0') {
563 switch (type) {
564 case LT_PGRP:
565 if (li->li_number == 0)
566 li->li_number = getpgrp();
567 break;
568 case LT_SID:
569 if (li->li_number == 0)
570 li->li_number = getsid(mypid);
571 break;
572 case LT_RTABLE:
573 if (li->li_number < 0 ||
574 li->li_number > RT_TABLEID_MAX)
575 errx(STATUS_BADUSAGE,
576 "rtable out of range");
577 break;
578 case LT_TTY:
579 usage();
580 default:
581 break;
582 }
583 continue;
584 }
585
586 switch (type) {
587 case LT_USER:
588 if (uid_from_user(sp, &uid) == -1)
589 errx(STATUS_BADUSAGE, "unknown user `%s'", sp);
590 li->li_number = uid;
591 break;
592 case LT_GROUP:
593 if (gid_from_group(sp, &gid) == -1)
594 errx(STATUS_BADUSAGE, "unknown group `%s'", sp);
595 li->li_number = gid;
596 break;
597 case LT_TTY:
598 if (strcmp(sp, "-") == 0) {
599 li->li_number = -1;
600 break;
601 } else if (strcmp(sp, "co") == 0)
602 p = "console";
603 else if (strncmp(sp, "tty", 3) == 0)
604 p = sp;
605 else
606 p = NULL;
607
608 if (p == NULL)
609 snprintf(buf, sizeof(buf), "/dev/tty%s", sp);
610 else
611 snprintf(buf, sizeof(buf), "/dev/%s", p);
612
613 if (stat(buf, &st) == -1) {
614 if (errno == ENOENT)
615 errx(STATUS_BADUSAGE,
616 "no such tty: `%s'", sp);
617 err(STATUS_ERROR, "stat(%s)", sp);
618 }
619
620 if (!S_ISCHR(st.st_mode))
621 errx(STATUS_BADUSAGE, "not a tty: `%s'", sp);
622
623 li->li_number = st.st_rdev;
624 break;
625 default:
626 usage();
627 }
628 }
629
630 if (empty)
631 usage();
632 }
633