GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/pkill/pkill.c Lines: 143 286 50.0 %
Date: 2017-11-07 Branches: 124 281 44.1 %

Line Branch Exec Source
1
/*	$OpenBSD: pkill.c,v 1.39 2016/10/10 02:22:59 gsoares 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/param.h>	/* MAXCOMLEN */
34
#include <sys/types.h>
35
#include <sys/sysctl.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 *
114
getargv(struct kinfo_proc *kp)
115
{
116
	static char buf[_POSIX2_LINE_MAX];
117
	char **pargv;
118
	size_t j;
119
120
10446
	if ((pargv = kvm_getargv(kd, kp, 0)) == NULL) {
121
6
		strlcpy(buf, kp->p_comm, sizeof(buf));
122
6
		return buf;
123
	}
124
125
	j = 0;
126

41448
	while (j < sizeof(buf) && *pargv != NULL) {
127
		int ret;
128
129
17198
		ret = snprintf(buf + j, sizeof(buf) - j,
130
8599
		    pargv[1] != NULL ? "%s " : "%s", pargv[0]);
131
8599
		if (ret >= sizeof(buf) - j)
132
			j += sizeof(buf) - j - 1;
133
8599
		else if (ret > 0)
134
8599
			j += ret;
135
8599
		pargv++;
136
	}
137
5217
	return buf;
138
5223
}
139
140
int
141
main(int argc, char **argv)
142
{
143
2932
	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
1466
	regex_t reg;
150
1466
	regmatch_t regmatch;
151
152
1466
	if (strcmp(__progname, "pgrep") == 0) {
153
		action = grepact;
154
160
		pgrep = 1;
155
160
	} else {
156
		action = killact;
157
1306
		p = argv[1];
158
159

2612
		if (argc > 1 && p[0] == '-') {
160
1306
			p++;
161
1306
			i = (int)strtol(p, &q, 10);
162
1306
			if (*q == '\0') {
163
				signum = i;
164
				argv++;
165
				argc--;
166
			} else {
167
1306
				if (strncasecmp(p, "sig", 3) == 0)
168
					p += 3;
169
27138
				for (i = 1; i < NSIG; i++)
170
13497
					if (strcasecmp(sys_signame[i], p) == 0)
171
						break;
172
1306
				if (i != NSIG) {
173
1234
					signum = i;
174
1234
					argv++;
175
1234
					argc--;
176
1234
				}
177
			}
178
		}
179
	}
180
181
	criteria = 0;
182
183
4584
	while ((ch = getopt(argc, argv, "G:P:T:U:d:fg:Ilnoqs:t:u:vx")) != -1)
184




1652
		switch (ch) {
185
		case 'G':
186
			makelist(&rgidlist, LT_GROUP, optarg);
187
			criteria = 1;
188
			break;
189
		case 'P':
190
9
			makelist(&ppidlist, LT_GENERIC, optarg);
191
			criteria = 1;
192
9
			break;
193
		case 'T':
194
82
			makelist(&rtablist, LT_RTABLE, optarg);
195
			criteria = 1;
196
82
			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
127
			matchargs = 1;
208
127
			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
55
			quiet = 1;
229
55
			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
1379
			fullmatch = 1;
247
1379
			break;
248
		default:
249
			usage();
250
			/* NOTREACHED */
251
		}
252
253
1466
	argc -= optind;
254
1466
	argv += optind;
255
1466
	if (argc != 0)
256
1457
		criteria = 1;
257

2932
	if (!criteria || (newest && oldest))
258
		usage();
259
260
1466
	mypid = getpid();
261
262
	/*
263
	 * Retrieve the list of running processes from the kernel.
264
	 */
265
1466
	kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf);
266
1466
	if (kd == NULL)
267
		errx(STATUS_ERROR, "kvm_openfiles(): %s", buf);
268
269
1466
	plist = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc);
270
1466
	if (plist == NULL)
271
		errx(STATUS_ERROR, "kvm_getprocs() failed");
272
273
1466
	if (matchargs == 0 && confirmkill == 0) {
274
1339
		if (action == killact) {
275
1234
			if (pledge("stdio proc flock rpath cpath wpath", NULL) == -1)
276
				err(STATUS_ERROR, "pledge");
277
105
		} else if (action == grepact) {
278
105
			if (pledge("stdio flock rpath cpath wpath", 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
1466
	if ((selected = calloc(nproc, 1)) == NULL)
288
		errx(STATUS_ERROR, "memory allocation failure");
289
290
	/*
291
	 * Refine the selection.
292
	 */
293
4380
	for (; *argv != NULL; argv++) {
294
1457
		if ((rv = regcomp(&reg, *argv, REG_EXTENDED)) != 0) {
295
			regerror(rv, &reg, buf, sizeof(buf));
296
			errx(STATUS_BADUSAGE, "bad expression: %s", buf);
297
		}
298
299
139406
		for (i = 0, kp = plist; i < nproc; i++, kp++) {
300

136492
			if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 ||
301
68246
			     kp->p_pid == mypid)
302
				continue;
303
304
66789
			if (matchargs)
305
5223
				mstr = getargv(kp);
306
			else
307
61566
				mstr = kp->p_comm;
308
309
66789
			rv = regexec(&reg, mstr, 1, &regmatch, 0);
310
66789
			if (rv == 0) {
311
213
				if (fullmatch) {
312

166
					if (regmatch.rm_so == 0 &&
313
73
					    regmatch.rm_eo == strlen(mstr))
314
73
						selected[i] = 1;
315
				} else
316
120
					selected[i] = 1;
317
66576
			} else if (rv != REG_NOMATCH) {
318
				regerror(rv, &reg, buf, sizeof(buf));
319
				errx(STATUS_ERROR, "regexec(): %s", buf);
320
			}
321
		}
322
323
1457
		regfree(&reg);
324
	}
325
326
140246
	for (i = 0, kp = plist; i < nproc; i++, kp++) {
327

137314
		if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 ||
328
68657
		     kp->p_pid == mypid)
329
			continue;
330
331
134382
		SLIST_FOREACH(li, &ruidlist, li_chain)
332
			if (kp->p_ruid == (uid_t)li->li_number)
333
				break;
334
67191
		if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
335
			selected[i] = 0;
336
			continue;
337
		}
338
339
134382
		SLIST_FOREACH(li, &rgidlist, li_chain)
340
			if (kp->p_rgid == (gid_t)li->li_number)
341
				break;
342
67191
		if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
343
			selected[i] = 0;
344
			continue;
345
		}
346
347
134382
		SLIST_FOREACH(li, &euidlist, li_chain)
348
			if (kp->p_uid == (uid_t)li->li_number)
349
				break;
350
67191
		if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
351
			selected[i] = 0;
352
			continue;
353
		}
354
355
135168
		SLIST_FOREACH(li, &ppidlist, li_chain)
356
402
			if (kp->p_ppid == (uid_t)li->li_number)
357
				break;
358
67191
		if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
359
393
			selected[i] = 0;
360
393
			continue;
361
		}
362
363
133596
		SLIST_FOREACH(li, &pgrplist, li_chain)
364
			if (kp->p__pgid == (uid_t)li->li_number)
365
				break;
366
66798
		if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
367
			selected[i] = 0;
368
			continue;
369
		}
370
371
133596
		SLIST_FOREACH(li, &tdevlist, li_chain) {
372
			if (li->li_number == -1 &&
373
			    (kp->p_psflags & PS_CONTROLT) == 0)
374
				break;
375
			if (kp->p_tdev == (uid_t)li->li_number)
376
				break;
377
		}
378
66798
		if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
379
			selected[i] = 0;
380
			continue;
381
		}
382
383
133596
		SLIST_FOREACH(li, &sidlist, li_chain)
384
			if (kp->p_sid == (uid_t)li->li_number)
385
				break;
386
66798
		if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
387
			selected[i] = 0;
388
			continue;
389
		}
390
391
135136
		SLIST_FOREACH(li, &rtablist, li_chain)
392
3422
			if (kp->p_rtableid == (u_int32_t)li->li_number)
393
				break;
394
66798
		if (SLIST_FIRST(&rtablist) != NULL && li == NULL) {
395
770
			selected[i] = 0;
396
770
			continue;
397
		}
398
399
66028
		if (argc == 0)
400
9
			selected[i] = 1;
401
	}
402
403
1466
	if (newest || oldest) {
404
		bestidx = -1;
405
406
		if (newest)
407
			bestsec = bestusec = 0;
408
		else
409
			bestsec = bestusec = UINT32_MAX;
410
411
		for (i = 0, kp = plist; i < nproc; i++, kp++) {
412
			if (!selected[i])
413
				continue;
414
415
			if ((newest && (kp->p_ustart_sec > bestsec ||
416
			    (kp->p_ustart_sec == bestsec
417
			    && kp->p_ustart_usec > bestusec)))
418
			|| (oldest && (kp->p_ustart_sec < bestsec ||
419
                            (kp->p_ustart_sec == bestsec
420
                            && kp->p_ustart_usec < bestusec)))) {
421
422
				bestsec = kp->p_ustart_sec;
423
				bestusec = kp->p_ustart_usec;
424
				bestidx = i;
425
			}
426
		}
427
428
		memset(selected, 0, nproc);
429
		if (bestidx != -1)
430
			selected[bestidx] = 1;
431
	}
432
433
	/*
434
	 * Take the appropriate action for each matched process, if any.
435
	 */
436
	rv = STATUS_NOMATCH;
437
140246
	for (i = 0, j = 0, kp = plist; i < nproc; i++, kp++) {
438

137314
		if ((kp->p_flag & (P_SYSTEM | P_THREAD)) != 0 ||
439
68657
		     kp->p_pid == mypid)
440
			continue;
441
67191
		if (selected[i] == inverse)
442
			continue;
443
444

5458
		switch ((*action)(kp, j++)) {
445
		case STATUS_MATCH:
446
202
			if (rv != STATUS_ERROR)
447
202
				rv = STATUS_MATCH;
448
			break;
449
		case STATUS_NOMATCH:
450
			j--;
451
			break;
452
		case STATUS_ERROR:
453
			rv = STATUS_ERROR;
454
			break;
455
		}
456
	}
457
1466
	if (pgrep && j && !quiet)
458
116
		putchar('\n');
459
460
1466
	return(rv);
461
1466
}
462
463
static void __dead
464
usage(void)
465
{
466
	const char *ustr;
467
468
	if (pgrep)
469
		ustr = "[-flnoqvx] [-d delim]";
470
	else
471
		ustr = "[-signal] [-fIlnoqvx]";
472
473
	fprintf(stderr, "usage: %s %s [-G gid] [-g pgrp] [-P ppid] [-s sid]"
474
	    "\n\t[-T rtable] [-t tty] [-U uid] [-u euid] [pattern ...]\n",
475
	    __progname, ustr);
476
477
	exit(STATUS_BADUSAGE);
478
}
479
480
static int
481
askyn(struct kinfo_proc *kp)
482
{
483
	int first, ch;
484
485
	printf("kill %d %.60s? ", (int)kp->p_pid, getargv(kp));
486
	fflush(stdout);
487
488
	first = ch = getchar();
489
	while (ch != '\n' && ch != EOF)
490
		ch = getchar();
491
	return (first == 'y' || first == 'Y');
492
}
493
494
static int
495
killact(struct kinfo_proc *kp, int dummy)
496
{
497
	int doit;
498
499
118
	if (confirmkill) {
500
		doit = askyn(kp);
501
	} else {
502
59
		if (longfmt && !quiet)
503
			printf("%d %s\n", (int)kp->p_pid, kp->p_comm);
504
		doit = 1;
505
	}
506
507

118
	if (doit && kill(kp->p_pid, signum) == -1) {
508
		if (errno == ESRCH)
509
			return (STATUS_NOMATCH);
510
		warn("signalling pid %d", (int)kp->p_pid);
511
		return (STATUS_ERROR);
512
	}
513
59
	return (STATUS_MATCH);
514
59
}
515
516
static int
517
grepact(struct kinfo_proc *kp, int printdelim)
518
{
519
	char **argv;
520
521
286
	if (quiet)
522
21
		return (STATUS_MATCH);
523
122
	if (longfmt && matchargs)
524
		if ((argv = kvm_getargv(kd, kp, 0)) == NULL)
525
			return (errno == ESRCH ? STATUS_NOMATCH : STATUS_ERROR);
526
122
	if (printdelim)
527
64
		fputs(delim, stdout);
528
122
	if (longfmt && matchargs) {
529
		printf("%d ", (int)kp->p_pid);
530
		for (; *argv != NULL; argv++) {
531
			printf("%s", *argv);
532
			if (argv[1] != NULL)
533
				putchar(' ');
534
		}
535
122
	} else if (longfmt)
536
		printf("%d %s", (int)kp->p_pid, kp->p_comm);
537
	else
538
122
		printf("%d", (int)kp->p_pid);
539
540
122
	return (STATUS_MATCH);
541
143
}
542
543
static void
544
makelist(struct listhead *head, enum listtype type, char *src)
545
{
546
	struct list *li;
547
	struct passwd *pw;
548
	struct group *gr;
549
91
	struct stat st;
550
91
	char *sp, *p, buf[PATH_MAX];
551
	int empty;
552
553
	empty = 1;
554
555
273
	while ((sp = strsep(&src, ",")) != NULL) {
556
91
		if (*sp == '\0')
557
			usage();
558
559
91
		if ((li = malloc(sizeof(*li))) == NULL)
560
			errx(STATUS_ERROR, "memory allocation failure");
561
91
		SLIST_INSERT_HEAD(head, li, li_chain);
562
		empty = 0;
563
564
91
		li->li_number = strtol(sp, &p, 0);
565
91
		if (*p == '\0') {
566

173
			switch (type) {
567
			case LT_PGRP:
568
				if (li->li_number == 0)
569
					li->li_number = getpgrp();
570
				break;
571
			case LT_SID:
572
				if (li->li_number == 0)
573
					li->li_number = getsid(mypid);
574
				break;
575
			case LT_RTABLE:
576

164
				if (li->li_number < 0 ||
577
82
				    li->li_number > RT_TABLEID_MAX)
578
					errx(STATUS_BADUSAGE,
579
					    "rtable out of range");
580
				break;
581
			case LT_TTY:
582
				usage();
583
			default:
584
				break;
585
			}
586
			continue;
587
		}
588
589
		switch (type) {
590
		case LT_USER:
591
			if ((pw = getpwnam(sp)) == NULL)
592
				errx(STATUS_BADUSAGE, "unknown user `%s'", sp);
593
			li->li_number = pw->pw_uid;
594
			break;
595
		case LT_GROUP:
596
			if ((gr = getgrnam(sp)) == NULL)
597
				errx(STATUS_BADUSAGE, "unknown group `%s'", sp);
598
			li->li_number = gr->gr_gid;
599
			break;
600
		case LT_TTY:
601
			if (strcmp(sp, "-") == 0) {
602
				li->li_number = -1;
603
				break;
604
			} else if (strcmp(sp, "co") == 0)
605
				p = "console";
606
			else if (strncmp(sp, "tty", 3) == 0)
607
				p = sp;
608
			else
609
				p = NULL;
610
611
			if (p == NULL)
612
				snprintf(buf, sizeof(buf), "/dev/tty%s", sp);
613
			else
614
				snprintf(buf, sizeof(buf), "/dev/%s", p);
615
616
			if (stat(buf, &st) < 0) {
617
				if (errno == ENOENT)
618
					errx(STATUS_BADUSAGE,
619
					    "no such tty: `%s'", sp);
620
				err(STATUS_ERROR, "stat(%s)", sp);
621
			}
622
623
			if (!S_ISCHR(st.st_mode))
624
				errx(STATUS_BADUSAGE, "not a tty: `%s'", sp);
625
626
			li->li_number = st.st_rdev;
627
			break;
628
		default:
629
			usage();
630
		}
631
	}
632
633
91
	if (empty)
634
		usage();
635
91
}