1 /*
2  * pgrep, pkill - find or signal processes by name and other attributes
3  *
4  * Gunnar Ritter, Freiburg i. Br., Germany, March 2003.
5  */
6 /*
7  * Copyright (c) 2003 Gunnar Ritter
8  *
9  * This software is provided 'as-is', without any express or implied
10  * warranty. In no event will the authors be held liable for any damages
11  * arising from the use of this software.
12  *
13  * Permission is granted to anyone to use this software for any purpose,
14  * including commercial applications, and to alter it and redistribute
15  * it freely, subject to the following restrictions:
16  *
17  * 1. The origin of this software must not be misrepresented; you must not
18  *    claim that you wrote the original software. If you use this software
19  *    in a product, an acknowledgment in the product documentation would be
20  *    appreciated but is not required.
21  *
22  * 2. Altered source versions must be plainly marked as such, and must not be
23  *    misrepresented as being the original software.
24  *
25  * 3. This notice may not be removed or altered from any source distribution.
26  */
27 
28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
29 #define	USED	__attribute__ ((used))
30 #elif defined __GNUC__
31 #define	USED	__attribute__ ((unused))
32 #else
33 #define	USED
34 #endif
35 static const char sccsid[] USED = "@(#)pgrep.sl	1.24 (gritter) 1/12/07";
36 
37 #include	<sys/types.h>
38 #include	<sys/stat.h>
39 #include	<fcntl.h>
40 #include	<unistd.h>
41 #include	<stdio.h>
42 #include	<string.h>
43 #include	<stdlib.h>
44 #include	<errno.h>
45 #include	<libgen.h>
46 #include	<dirent.h>
47 #include	<limits.h>
48 #include	<pwd.h>
49 #include	<signal.h>
50 #include	<grp.h>
51 #include	<locale.h>
52 #include	<ctype.h>
53 #include	<regex.h>
54 
55 #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
56 	&& !defined (__APPLE__)
57 #if defined (__hpux)
58 #include	<sys/param.h>
59 #include	<sys/pstat.h>
60 #elif defined (_AIX)
61 #include	<procinfo.h>
62 #define	proc	process
63 #else	/* !__hpux, !_AIX */
64 #ifdef	sun
65 #define	_STRUCTURED_PROC	1
66 #endif	/* sun */
67 #include	<sys/procfs.h>
68 #endif	/* !__hpux, !_AIX */
69 #endif	/* !__linux__, !__NetBSD__, !__OpenBSD__ */
70 
71 #if defined (__NetBSD__) || defined (__OpenBSD__) || defined (__APPLE__)
72 #include <kvm.h>
73 #include <sys/param.h>
74 #include <sys/sysctl.h>
75 #if defined (__APPLE__)
76 #include <mach/mach_types.h>
77 #include <mach/task_info.h>
78 #endif /* __APPLE__ */
79 #define	proc	process
80 #undef	p_pgid
81 #define	p_pgid	p__pgid
82 #endif /* __NetBSD__, __OpenBSD__, __APPLE__ */
83 
84 #ifndef	PRNODEV
85 #define	PRNODEV		0
86 #endif
87 
88 #include	<blank.h>
89 
90 #define	PROCDIR		"/proc"
91 #define	eq(a, b)	(strcmp(a, b) == 0)
92 
93 enum	okay {
94 	OKAY,
95 	STOP
96 };
97 
98 enum	valtype {
99 	VT_CHAR,
100 	VT_INT,
101 	VT_UINT,
102 	VT_LONG,
103 	VT_ULONG
104 };
105 
106 union	value {
107 	char	v_char;
108 	int	v_int;
109 	unsigned int	v_uint;
110 	long	v_long;
111 	unsigned long	v_ulong;
112 };
113 
114 struct	proc {
115 	struct proc	*p_nxt;		/* next proc structure */
116 	pid_t		p_pid;		/* process id */
117 	char		p_fname[19];	/* executable name */
118 	pid_t		p_ppid;		/* parent process id */
119 	pid_t		p_pgid;		/* process group id */
120 	pid_t		p_sid;		/* session id */
121 	int		p_ttydev;	/* controlling terminal */
122 	char		p_psargs[80];	/* process arguments */
123 	uid_t		p_uid;		/* real user id */
124 	uid_t		p_euid;		/* effective user id */
125 	gid_t		p_gid;		/* real group id */
126 	gid_t		p_egid;		/* effective group id */
127 	unsigned long	p_start;	/* start time (in jiffies except BSD) */
128 	unsigned long	p_size;		/* size in kilobytes */
129 	int		p_match;	/* matched this process */
130 };
131 
132 enum	attype {
133 	ATT_PPID,			/* parent process id */
134 	ATT_PGRP,			/* process group id */
135 	ATT_SID,			/* sessiond id */
136 	ATT_EUID,			/* effective user id */
137 	ATT_UID,			/* real user id */
138 	ATT_GID,			/* real group id */
139 	ATT_TTY,			/* controlling terminal */
140 	ATT_ALL
141 };
142 
143 struct	attrib {
144 	struct attrib	*a_nxt;		/* next element of list */
145 	enum	attype	a_type;		/* type of attribute */
146 	long		a_val;		/* value of attribute */
147 };
148 
149 struct	attlist {
150 	struct attlist	*al_nxt;	/* next element of list */
151 	struct attrib	*al_att;	/* this attribute */
152 };
153 
154 static const char	*progname;
155 static pid_t		mypid;		/* this instance's pid */
156 static unsigned		errcnt;		/* error count */
157 static int		matched;	/* a process matched */
158 static int		pkill;		/* this is the pkill command */
159 static int		fflag;		/* match against full command line */
160 static int		lflag;		/* long output format */
161 static int		nflag;		/* match newest process only */
162 static int		oflag;		/* match oldest process only */
163 static int		vflag;		/* reverse matching */
164 static int		xflag;		/* match exact string */
165 static int		signo = SIGTERM;	/* signal to send */
166 static int		need_euid_egid;	/* need euid or egid */
167 static struct attlist	*attributes;	/* required attributes */
168 static struct proc	*processes;	/* collected processes */
169 static regex_t		*expression;	/* regular expression to match */
170 static const char	*delimiter;	/* delimiter string */
171 static int		prdelim;	/* print a delimiter (not first proc) */
172 
173 static int	str_2_sig(const char *, int *);
174 
175 static void *
srealloc(void * vp,size_t nbytes)176 srealloc(void *vp, size_t nbytes)
177 {
178 	void	*p;
179 
180 	if ((p = realloc(vp, nbytes)) == NULL) {
181 		write(2, "no memory\n", 10);
182 		exit(3);
183 	}
184 	return p;
185 }
186 
187 static void *
smalloc(size_t nbytes)188 smalloc(size_t nbytes)
189 {
190 	return srealloc(NULL, nbytes);
191 }
192 
193 static void *
scalloc(size_t nmemb,size_t size)194 scalloc(size_t nmemb, size_t size)
195 {
196 	void	*p;
197 
198 	if ((p = (void *)calloc(nmemb, size)) == NULL) {
199 		write(2, "no memory\n", 10);
200 		exit(3);
201 	}
202 	return p;
203 }
204 
205 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) \
206 	&& !defined (__OpenBSD__) && !defined (__APPLE__)
207 static void
chdir_to_proc(void)208 chdir_to_proc(void)
209 {
210 	static int	fd = -1;
211 
212 	if (fd == -1 && (fd = open(PROCDIR, O_RDONLY)) < 0) {
213 		fprintf(stderr, "%s: cannot open %s\n", progname, PROCDIR);
214 		exit(3);
215 	}
216 	if (fchdir(fd) < 0) {
217 		fprintf(stderr, "%s: cannot chdir to %s\n", progname, PROCDIR);
218 		exit(3);
219 	}
220 }
221 
222 static union value *
getval(char ** listp,enum valtype type,int separator,int sep2)223 getval(char **listp, enum valtype type, int separator, int sep2)
224 {
225 	char	*buf;
226 	static union value	v;
227 	const char	*cp, *op;
228 	char	*cq, *x;
229 
230 	if (**listp == '\0')
231 		return NULL;
232 	op = *listp;
233 	while (**listp != '\0') {
234 		if ((separator==' ' ? isspace(**listp) : **listp == separator)
235 				|| **listp == sep2)
236 			break;
237 		(*listp)++;
238 	}
239 	buf = alloca(*listp - op + 1);
240 	for (cp = op, cq = buf; cp < *listp; cp++, cq++)
241 		*cq = *cp;
242 	*cq = '\0';
243 	if (**listp) {
244 		while ((separator == ' ' ?
245 				isspace(**listp) : **listp == separator) ||
246 				**listp == sep2)
247 			(*listp)++;
248 	}
249 	switch (type) {
250 	case VT_CHAR:
251 		if (buf[1] != '\0')
252 			return NULL;
253 		v.v_char = buf[0];
254 		break;
255 	case VT_INT:
256 		v.v_int = strtol(buf, &x, 10);
257 		if (*x != '\0')
258 			return NULL;
259 		break;
260 	case VT_UINT:
261 		v.v_uint = strtoul(buf, &x, 10);
262 		if (*x != '\0')
263 			return NULL;
264 		break;
265 	case VT_LONG:
266 		v.v_long = strtol(buf, &x, 10);
267 		if (*x != '\0')
268 			return NULL;
269 		break;
270 	case VT_ULONG:
271 		v.v_ulong = strtoul(buf, &x, 10);
272 		if (*x != '\0')
273 			return NULL;
274 		break;
275 	}
276 	return &v;
277 }
278 #endif	/* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */
279 
280 static const char *
element(const char ** listp,int override)281 element(const char **listp, int override)
282 {
283 	static char	*buf;
284 	static size_t	buflen;
285 	const char	*cp, *op;
286 	char	*cq;
287 	size_t	sz;
288 	int	stop = ',';
289 
290 	if (**listp == '\0')
291 		return NULL;
292 	op = *listp;
293 	while (**listp != '\0') {
294 		if (**listp == override)
295 			stop = '\0';
296 		if (stop != '\0' && (**listp == stop || isblank(**listp)))
297 			break;
298 		(*listp)++;
299 	}
300 	if (**listp == '\0')
301 		return op;
302 	if ((sz = *listp - op + 1) > buflen) {
303 		buflen = sz;
304 		buf = srealloc(buf, buflen);
305 	}
306 	for (cp = op, cq = buf; cp < *listp; cp++, cq++)
307 		*cq = *cp;
308 	*cq = '\0';
309 	if (**listp) {
310 		while (**listp == stop || isblank(**listp))
311 			(*listp)++;
312 	}
313 	return buf;
314 }
315 
316 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \
317 	!defined (__OpenBSD__) && !defined (__APPLE__)
318 
319 #if defined (__linux__) || defined (__FreeBSD__) || defined (__DragonFly__)
320 
321 #define	GETVAL_REQ(a)		if ((v = getval(&cp, (a), ' ', 0)) == NULL) \
322 					return STOP
323 
324 #define	GETVAL_OPT(a)		if ((v = getval(&cp, (a), ' ', 0)) == NULL) \
325 					goto complete
326 
327 #define	GETVAL_COMMA(a)		if ((v = getval(&cp, (a), ' ', ',')) == NULL) \
328 					return STOP
329 
330 #endif	/* __linux__ || __FreeBSD__ || __DragonFly__ */
331 
332 
333 #if defined (__linux__)
334 static enum okay
getproc_stat(struct proc * p,pid_t expected_pid)335 getproc_stat(struct proc *p, pid_t expected_pid)
336 {
337 	static char	*buf;
338 	static size_t	buflen;
339 	union value	*v;
340 	FILE	*fp;
341 	char	*cp, *cq, *ce;
342 	size_t	sz, sc;
343 
344 	if ((fp = fopen("stat", "r")) == NULL)
345 		return STOP;
346 	for (cp = buf; ;) {
347 		const unsigned	chunk = 32;
348 
349 		if (buflen < (sz = cp - buf + chunk)) {
350 			sc = cp - buf;
351 			buf = srealloc(buf, buflen = sz);
352 			cp = &buf[sc];
353 		}
354 		if ((sz = fread(cp, 1, chunk, fp)) < chunk) {
355 			ce = &cp[sz - 1];
356 			break;
357 		}
358 		cp += chunk;
359 	}
360 	fclose(fp);
361 	if (*ce != '\n')
362 		return STOP;
363 	*ce-- = '\0';
364 	cp = buf;
365 	GETVAL_REQ(VT_INT);
366 	if ((p->p_pid = v->v_int) != expected_pid)
367 		return STOP;
368 	if (*cp++ != '(')
369 		return STOP;
370 	for (cq = ce; cq >= cp && *cq != ')'; cq--);
371 	if (cq < cp)
372 		return STOP;
373 	*cq = '\0';
374 	strncpy(p->p_fname, cp, sizeof p->p_fname);
375 	p->p_fname[sizeof p->p_fname - 1] = '\0';
376 	cp = &cq[1];
377 	while (isspace(*cp))
378 		cp++;
379 	GETVAL_REQ(VT_CHAR);
380 	if (v->v_char == 'Z')
381 		return STOP;
382 	GETVAL_REQ(VT_INT);
383 	p->p_ppid = v->v_int;
384 	GETVAL_REQ(VT_INT);
385 	p->p_pgid = v->v_int;
386 	GETVAL_REQ(VT_INT);
387 	p->p_sid = v->v_int;
388 	GETVAL_REQ(VT_INT);
389 	p->p_ttydev = v->v_int;
390 	GETVAL_REQ(VT_INT);
391 	/* tty_pgrp not used */
392 	GETVAL_REQ(VT_ULONG);
393 	/* flag not used */
394 	GETVAL_REQ(VT_ULONG);
395 	/* min_flt */
396 	GETVAL_REQ(VT_ULONG);
397 	/* cmin_flt */
398 	GETVAL_REQ(VT_ULONG);
399 	/* maj_flt */
400 	GETVAL_REQ(VT_ULONG);
401 	/* cmaj_flt */
402 	GETVAL_REQ(VT_ULONG);
403 	/* time */
404 	GETVAL_REQ(VT_ULONG);
405 	/* stime */
406 	GETVAL_REQ(VT_LONG);
407 	/* ctime */
408 	GETVAL_REQ(VT_LONG);
409 	/* cstime */
410 	GETVAL_REQ(VT_LONG);
411 	/* priority */
412 	GETVAL_REQ(VT_LONG);
413 	/* nice */
414 	GETVAL_REQ(VT_LONG);
415 	/* timeout not used */
416 	GETVAL_REQ(VT_LONG);
417 	/* it_real_value not used */
418 	GETVAL_REQ(VT_ULONG);
419 	p->p_start = v->v_ulong;
420 	GETVAL_REQ(VT_ULONG);
421 	p->p_size = (v->v_ulong >> 10);
422 	return OKAY;
423 }
424 
425 static enum okay
getproc_cmdline(struct proc * p)426 getproc_cmdline(struct proc *p)
427 {
428 	FILE	*fp;
429 	char	*cp, *ce;
430 	int	hadzero = 0, c;
431 
432 	if ((fp = fopen("cmdline", "r")) != NULL) {
433 		cp = p->p_psargs;
434 		ce = cp + sizeof p->p_psargs - 1;
435 		while (cp < ce && (c = getc(fp)) != EOF) {
436 			if (c != '\0') {
437 				if (hadzero) {
438 					*cp++ = ' ';
439 					if (cp == ce)
440 						break;
441 					hadzero = 0;
442 				}
443 				*cp++ = c;
444 			} else {
445 				hadzero = 1;
446 			}
447 		}
448 		*cp = '\0';
449 		fclose(fp);
450 	}
451 	if (*p->p_psargs == '\0' && p->p_size == 0)
452 		strcpy(p->p_psargs, p->p_fname);
453 	return OKAY;
454 }
455 
456 static enum okay
getproc_status(struct proc * p)457 getproc_status(struct proc *p)
458 {
459 	char	line[LINE_MAX];
460 	union value	*v;
461 	FILE	*fp;
462 	char	*cp;
463 	int	scanr;
464 
465 	if ((fp = fopen("status", "r")) == NULL)
466 		return STOP;
467 	scanr = 0;
468 	while (fgets(line, sizeof line, fp) != NULL) {
469 		if (strncmp(line, "Uid:", 4) == 0) {
470 			cp = &line[4];
471 			while (isspace(*cp))
472 				cp++;
473 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
474 				fclose(fp);
475 				return STOP;
476 			}
477 			p->p_uid = v->v_int;
478 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
479 				fclose(fp);
480 				return STOP;
481 			}
482 			p->p_euid = v->v_int;
483 			scanr++;
484 		} else if (strncmp(line, "Gid:", 4) == 0) {
485 			cp = &line[4];
486 			while (isspace(*cp))
487 				cp++;
488 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
489 				fclose(fp);
490 				return STOP;
491 			}
492 			p->p_gid = v->v_int;
493 			if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
494 				fclose(fp);
495 				return STOP;
496 			}
497 			p->p_egid = v->v_int;
498 			scanr++;
499 		}
500 	}
501 	fclose(fp);
502 	if (scanr != 2)
503 		return STOP;
504 	return OKAY;
505 }
506 
507 static struct proc *
getproc(const char * dir,pid_t expected_pid)508 getproc(const char *dir, pid_t expected_pid)
509 {
510 	struct proc	*p;
511 	enum okay	result;
512 
513 	p = scalloc(1, sizeof *p);
514 	if (chdir(dir) == 0) {
515 		if ((result = getproc_stat(p, expected_pid)) == OKAY)
516 			if ((result = getproc_cmdline(p)) == OKAY)
517 				result = getproc_status(p);
518 		chdir_to_proc();
519 	} else
520 		result = STOP;
521 	if (result == STOP) {
522 		free(p);
523 		return NULL;
524 	}
525 	return p;
526 }
527 
528 #elif defined (__FreeBSD__) || defined (__DragonFly__)
529 
530 static enum okay
getproc_status(struct proc * p,pid_t expected_pid)531 getproc_status(struct proc *p, pid_t expected_pid)
532 {
533 	static char	*buf;
534 	static size_t	buflen;
535 	union value	*v;
536 	FILE	*fp;
537 	char	*cp, *ce, *cq;
538 	size_t	sz, sc;
539 	int	mj, mi;
540 
541 	if ((fp = fopen("status", "r")) == NULL)
542 		return STOP;
543 	for (cp = buf; ;) {
544 		const unsigned	chunk = 32;
545 
546 		if (buflen < (sz = cp - buf + chunk)) {
547 			sc = cp - buf;
548 			buf = srealloc(buf, buflen = sz);
549 			cp = &buf[sc];
550 		}
551 		if ((sz = fread(cp, 1, chunk, fp)) < chunk) {
552 			ce = &cp[sz - 1];
553 			break;
554 		}
555 		cp += chunk;
556 	}
557 	fclose(fp);
558 	if (*ce != '\n')
559 		return STOP;
560 	*ce-- = '\0';
561 	cp = buf;
562 	while (*cp != ' ') {
563 		if (cp - buf < sizeof p->p_fname - 2)
564 			p->p_fname[cp-buf] = *cp;
565 		cp++;
566 	}
567 	if (cp - buf < sizeof p->p_fname - 1)
568 		p->p_fname[cp-buf] = '\0';
569 	else
570 		p->p_fname[sizeof p->p_fname - 1] = '\0';
571 	while (*cp == ' ')
572 		cp++;
573 	GETVAL_REQ(VT_INT);
574 	p->p_pid = v->v_int;
575 	GETVAL_REQ(VT_INT);
576 	p->p_ppid = v->v_int;
577 	GETVAL_REQ(VT_INT);
578 	p->p_pgid = v->v_int;
579 	GETVAL_REQ(VT_INT);
580 	p->p_sid = v->v_int;
581 	if (isdigit(*cp)) {
582 		GETVAL_COMMA(VT_INT);
583 		mj = v->v_int;
584 		GETVAL_REQ(VT_INT);
585 		mi = v->v_int;
586 		if (mj != -1 || mi != -1)
587 			p->p_ttydev = makedev(mj, mi);
588 	} else {
589 		struct stat	st;
590 		char	*dev;
591 		cq = cp;
592 		while (*cp != ' ') cp++;
593 		*cp = '\0';
594 		dev = smalloc(cp - cq + 8);
595 		strcpy(dev, "/dev/");
596 		strcpy(&dev[5], cq);
597 		if (stat(dev, &st) < 0)
598 			p->p_ttydev = PRNODEV;
599 		else
600 			p->p_ttydev = st.st_rdev;
601 		free(dev);
602 		*cp = ' ';
603 		while (*cp == ' ') cp++;
604 	}
605 	while (*cp != ' ') cp++; while (*cp == ' ') cp++;
606 	/* skip flags */
607 	GETVAL_COMMA(VT_LONG);
608 	p->p_start = v->v_long;
609 	GETVAL_REQ(VT_LONG);
610 	/* skip microseconds */
611 	while (*cp != ' ') cp++; while (*cp == ' ') cp++;
612 	/* skip user time */
613 	while (*cp != ' ') cp++; while (*cp == ' ') cp++;
614 	/* skip system time */
615 	while (*cp != ' ') cp++; while (*cp == ' ') cp++;
616 	/* skip wchan message */
617 	GETVAL_REQ(VT_INT);
618 	p->p_euid = v->v_int;
619 	GETVAL_REQ(VT_INT);
620 	p->p_uid = v->v_int;
621 	GETVAL_COMMA(VT_INT);
622 	p->p_gid = v->v_int;
623 	GETVAL_COMMA(VT_INT);
624 	p->p_egid = v->v_int;
625 	return OKAY;
626 }
627 
628 static enum okay
getproc_cmdline(struct proc * p)629 getproc_cmdline(struct proc *p)
630 {
631 	FILE	*fp;
632 	char	*cp, *ce;
633 	int	hadzero = 0, c;
634 
635 	if ((fp = fopen("cmdline", "r")) != NULL) {
636 		cp = p->p_psargs;
637 		ce = cp + sizeof p->p_psargs - 1;
638 		while (cp < ce && (c = getc(fp)) != EOF) {
639 			if (c != '\0') {
640 				if (hadzero) {
641 					*cp++ = ' ';
642 					if (cp == ce)
643 						break;
644 					hadzero = 0;
645 				}
646 				*cp++ = c;
647 			} else {
648 				hadzero = 1;
649 			}
650 		}
651 		*cp = '\0';
652 		fclose(fp);
653 	}
654 	if (*p->p_psargs == '\0' && p->p_size == 0)
655 		strcpy(p->p_psargs, p->p_fname);
656 	return OKAY;
657 }
658 
659 static struct proc *
getproc(const char * dir,pid_t expected_pid)660 getproc(const char *dir, pid_t expected_pid)
661 {
662 	struct proc	*p;
663 	enum okay	result;
664 
665 	p = scalloc(1, sizeof *p);
666 	if (chdir(dir) == 0) {
667 		if ((result = getproc_status(p, expected_pid)) == OKAY)
668 				result = getproc_cmdline(p);
669 		chdir_to_proc();
670 	} else
671 		result = STOP;
672 	if (result == STOP) {
673 		free(p);
674 		return NULL;
675 	}
676 	return p;
677 }
678 
679 #else	/* !__linux__, !__FreeBSD__, !__DragonFly__ */
680 
681 static const char *
concat(const char * dir,const char * base)682 concat(const char *dir, const char *base)
683 {
684 	static char	*name;
685 	static long	size;
686 	long	length;
687 	char	*np;
688 	const char	*cp;
689 
690 	if ((length = strlen(dir) + strlen(base) + 2) > size)
691 		name = srealloc(name, size = length);
692 	np = name;
693 	for (cp = dir; *cp; cp++)
694 		*np++ = *cp;
695 	*np++ = '/';
696 	for (cp = base; *cp; cp++)
697 		*np++ = *cp;
698 	*np = '\0';
699 	return name;
700 }
701 
702 static enum okay
getproc_psinfo(const char * dir,struct proc * p,pid_t expected_pid)703 getproc_psinfo(const char *dir, struct proc *p, pid_t expected_pid)
704 {
705 	FILE	*fp;
706 	struct psinfo	pi;
707 
708 	if ((fp = fopen(concat(dir, "psinfo"), "r")) == NULL)
709 		return STOP;
710 	if (fread(&pi, 1, sizeof pi, fp) != sizeof pi ||
711 			pi.pr_pid != expected_pid) {
712 		fclose(fp);
713 		return STOP;
714 	}
715 	fclose(fp);
716 	p->p_pid = pi.pr_pid;
717 	strncpy(p->p_fname, pi.pr_fname, sizeof p->p_fname);
718 	p->p_fname[sizeof p->p_fname - 1] = '\0';
719 	p->p_ppid = pi.pr_ppid;
720 	p->p_pgid = pi.pr_pgid;
721 	p->p_sid = pi.pr_sid;
722 	p->p_ttydev = pi.pr_ttydev;
723 	strncpy(p->p_psargs, pi.pr_psargs, sizeof p->p_psargs);
724 	p->p_psargs[sizeof p->p_psargs - 1] = '\0';
725 	p->p_uid = pi.pr_uid;
726 	p->p_gid = pi.pr_gid;
727 #ifdef	__sun
728 	p->p_euid = pi.pr_euid;
729 	p->p_egid = pi.pr_egid;
730 #endif	/* __sun */
731 	p->p_start = pi.pr_start.tv_sec;
732 	p->p_size = pi.pr_size;
733 	return OKAY;
734 }
735 
736 #ifndef	__sun
737 static enum okay
getproc_cred(const char * dir,struct proc * p)738 getproc_cred(const char *dir, struct proc *p)
739 {
740 	FILE	*fp;
741 	struct prcred	pc;
742 
743 	if ((fp = fopen(concat(dir, "cred"), "r")) == NULL)
744 		return need_euid_egid ? STOP : OKAY;
745 	if (fread(&pc, 1, sizeof pc, fp) != sizeof pc) {
746 		fclose(fp);
747 		return STOP;
748 	}
749 	fclose(fp);
750 	p->p_euid = pc.pr_euid;
751 	p->p_egid = pc.pr_egid;
752 	return OKAY;
753 }
754 #endif	/* !__sun */
755 
756 static struct proc *
getproc(const char * dir,pid_t expected_pid)757 getproc(const char *dir, pid_t expected_pid)
758 {
759 	struct proc	*p;
760 	enum okay	result;
761 
762 	p = scalloc(1, sizeof *p);
763 	result = getproc_psinfo(dir, p, expected_pid);
764 #ifndef	__sun
765 	if (result == OKAY)
766 		result = getproc_cred(dir, p);
767 #endif	/* !__sun */
768 	if (result == STOP) {
769 		free(p);
770 		return NULL;
771 	}
772 	return p;
773 }
774 #endif	/* !__linux__ */
775 
776 static void
collectprocs(void)777 collectprocs(void)
778 {
779 	struct proc	*p, *pq = NULL;
780 	DIR	*Dp;
781 	struct dirent	*dp;
782 	unsigned long	val;
783 	char	*x;
784 
785 	if ((Dp = opendir(".")) != NULL) {
786 		while ((dp = readdir(Dp)) != NULL) {
787 			if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
788 					(dp->d_name[1] == '.' &&
789 				 	dp->d_name[2] == '\0')))
790 				continue;
791 			val = strtoul(dp->d_name, &x, 10);
792 			if (*x != 0)
793 				continue;
794 			if ((p = getproc(dp->d_name, val)) != NULL) {
795 				if (pq)
796 					pq->p_nxt = p;
797 				else
798 					processes = p;
799 				pq = p;
800 			}
801 		}
802 		closedir(Dp);
803 	}
804 }
805 
806 #elif defined (__hpux)
807 static void
collectprocs(void)808 collectprocs(void)
809 {
810 #define	burst	((size_t)10)
811 	struct proc	*p, *pq = NULL;
812 	struct pst_status	pst[burst];
813 	int	i, count;
814 	int	idx = 0;
815 
816 	while ((count = pstat_getproc(pst, sizeof *pst, burst, idx)) > 0) {
817 		for (i = 0; i < count; i++) {
818 			p = scalloc(sizeof *p, 1);
819 			if (pq)
820 				pq->p_nxt = p;
821 			else
822 				processes = p;
823 			pq = p;
824 			p->p_pid = pst[i].pst_pid;
825 			strncpy(p->p_fname, pst[i].pst_ucomm,
826 					sizeof p->p_fname);
827 			p->p_fname[sizeof p->p_fname - 1] = '\0';
828 			p->p_ppid = pst[i].pst_ppid;
829 			p->p_pgid = pst[i].pst_pgrp;
830 			p->p_sid = pst[i].pst_sid;
831 			if (pst[i].pst_term.psd_major != -1 ||
832 					pst[i].pst_term.psd_minor != -1)
833 				p->p_ttydev = makedev(pst[i].pst_term.psd_major,
834 					pst[i].pst_term.psd_minor);
835 			strncpy(p->p_psargs, pst[i].pst_cmd,
836 					sizeof p->p_psargs);
837 			p->p_psargs[sizeof p->p_psargs - 1] = '\0';
838 			p->p_uid = pst[i].pst_uid;
839 			p->p_euid = pst[i].pst_euid;
840 			p->p_gid = pst[i].pst_gid;
841 			p->p_egid = pst[i].pst_egid;
842 			p->p_start = pst[i].pst_start;
843 			p->p_size = pst[i].pst_dsize + pst[i].pst_tsize +
844 				pst[i].pst_ssize;
845 		}
846 		idx = pst[count-1].pst_idx + 1;
847 	}
848 }
849 #elif defined (_AIX)
850 static void
oneproc(struct proc * p,struct procentry64 * pi)851 oneproc(struct proc *p, struct procentry64 *pi)
852 {
853 	char	args[100], *ap, *cp;
854 
855 	p->p_pid = pi->pi_pid;
856 	strncpy(p->p_fname, pi->pi_comm, sizeof p->p_fname);
857 	p->p_fname[sizeof p->p_fname - 1] = '\0';
858 	p->p_ppid = pi->pi_ppid;
859 	p->p_pgid = pi->pi_pgrp;
860 	p->p_sid = pi->pi_sid;
861 	p->p_ttydev = pi->pi_ttyp ? pi->pi_ttyd : PRNODEV;
862 	p->p_uid = pi->pi_uid;
863 	p->p_euid = pi->pi_cred.crx_uid;
864 	p->p_gid = pi->pi_cred.crx_rgid;
865 	p->p_egid = pi->pi_cred.crx_gid;
866 	p->p_start = pi->pi_start;
867 	p->p_size = pi->pi_size;
868 	if (getargs(pi, sizeof *pi, args, sizeof args) == 0) {
869 		ap = args;
870 		cp = p->p_psargs;
871 		while (cp < &p->p_psargs[sizeof p->p_psargs - 1]) {
872 			if (ap[0] == '\0') {
873 				if (ap[1] == '\0')
874 					break;
875 				*cp++ = ' ';
876 			} else
877 				*cp++ = *ap;
878 			ap++;
879 		}
880 		*cp = '\0';
881 	}
882 }
883 
884 static void
collectprocs(void)885 collectprocs(void)
886 {
887 #define	burst	((size_t)10)
888 	struct proc	*p, *pq = NULL;
889 	struct procentry64	pi[burst];
890 	pid_t	idx = 0;
891 	int	i, count;
892 
893 	while ((count = getprocs64(pi, sizeof *pi, NULL, 0, &idx, burst)) > 0) {
894 		for (i = 0; i < count; i++) {
895 			p = scalloc(sizeof *p, 1);
896 			if (pq)
897 				pq->p_nxt = p;
898 			else
899 				processes = p;
900 			pq = p;
901 			oneproc(p, &pi[i]);
902 		}
903 		if (count < burst)
904 			break;
905 	}
906 }
907 #elif defined (__OpenBSD__)
908 #include <uvm/uvm_extern.h>
909 static void
oneproc(struct proc * p,struct kinfo_proc * kp)910 oneproc(struct proc *p, struct kinfo_proc *kp)
911 {
912 	p->p_pid = kp->kp_proc.p_pid;
913 	strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname);
914 	p->p_fname[sizeof p->p_fname - 1] = '\0';
915 	p->p_ppid = kp->kp_eproc.e_ppid;
916 	p->p_pgid = kp->kp_eproc.e_pgid;
917 	p->p_sid = kp->kp_eproc.e_tpgid;	/* ? */
918 	p->p_ttydev = kp->kp_eproc.e_tdev;
919 	p->p_uid = kp->kp_eproc.e_pcred.p_ruid;
920 	p->p_euid = kp->kp_eproc.e_ucred.cr_uid;
921 	p->p_gid = kp->kp_eproc.e_pcred.p_rgid;
922 	p->p_egid = kp->kp_eproc.e_ucred.cr_gid;
923 	p->p_start = kp->kp_eproc.e_pstats.p_start.tv_sec;
924 	p->p_size = kp->kp_eproc.e_vm.vm_tsize +
925 		kp->kp_eproc.e_vm.vm_dsize +
926 		kp->kp_eproc.e_vm.vm_ssize;
927 }
928 static void
argproc(struct proc * p,struct kinfo_proc * kp,kvm_t * kt)929 argproc(struct proc *p, struct kinfo_proc *kp, kvm_t *kt)
930 {
931 	char	**args;
932 	char	*ap, *pp;
933 
934 	if ((args = kvm_getargv(kt, kp, sizeof p->p_psargs)) == NULL)
935 		return;
936 	ap = args[0];
937 	for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) {
938 		if (*ap == '\0') {
939 			*pp = ' ';
940 			ap = *++args;
941 			if (ap == NULL)
942 				break;
943 		} else
944 			*pp = *ap++;
945 	}
946 }
947 
948 static void
collectprocs(void)949 collectprocs(void)
950 {
951 	struct proc	*p, *pq = NULL;
952 	kvm_t	*kt;
953 	struct	kinfo_proc *kp;
954 	int	i, cnt;
955 
956 	if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
957 		exit(1);
958 	kp = kvm_getprocs(kt, KERN_PROC_ALL, 0, &cnt);
959 	for (i = 0; i < cnt; i++) {
960 		p = scalloc(sizeof *p, 1);
961 		if (pq)
962 			pq->p_nxt = p;
963 		else
964 			processes = p;
965 		pq = p;
966 		oneproc(p, &kp[i]);
967 		argproc(p, &kp[i], kt);
968 	}
969 	kvm_close(kt);
970 }
971 #elif defined (__NetBSD__)
972 static void
oneproc(struct proc * p,struct kinfo_proc2 * kp)973 oneproc(struct proc *p, struct kinfo_proc2 *kp)
974 {
975 	p->p_pid = kp->p_pid;
976 	strncpy(p->p_fname, kp->p_comm, sizeof p->p_fname);
977 	p->p_fname[sizeof p->p_fname - 1] = '\0';
978 	p->p_ppid = kp->p_ppid;
979 	p->p_pgid = kp->p__pgid;
980 	p->p_sid = kp->p_sid;
981 	p->p_ttydev = kp->p_tdev;
982 	p->p_uid = kp->p_ruid;
983 	p->p_euid = kp->p_uid;
984 	p->p_gid = kp->p_rgid;
985 	p->p_egid = kp->p_gid;
986 	p->p_start = kp->p_ustart_sec;
987 	p->p_size = kp->p_vm_tsize + kp->p_vm_dsize + kp->p_vm_ssize;
988 }
989 
990 static void
argproc(struct proc * p,struct kinfo_proc2 * kp,kvm_t * kt)991 argproc(struct proc *p, struct kinfo_proc2 *kp, kvm_t *kt)
992 {
993 	char	**args;
994 	char	*ap, *pp;
995 
996 	if ((args = kvm_getargv2(kt, kp, sizeof p->p_psargs)) == NULL)
997 		return;
998 	ap = args[0];
999 	for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) {
1000 		if (*ap == '\0') {
1001 			*pp = ' ';
1002 			ap = *++args;
1003 			if (ap == NULL)
1004 				break;
1005 		} else
1006 			*pp = *ap++;
1007 	}
1008 }
1009 
1010 static void
collectprocs(void)1011 collectprocs(void)
1012 {
1013 	struct proc	*p, *pq = NULL;
1014 	kvm_t	*kt;
1015 	struct	kinfo_proc2 *kp;
1016 	int	i, cnt;
1017 
1018 	if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
1019 		exit(1);
1020 	kp = kvm_getproc2(kt, KERN_PROC_ALL, 0, sizeof *kp, &cnt);
1021 	for (i = 0; i < cnt; i++) {
1022 		p = scalloc(sizeof *p, 1);
1023 		if (pq)
1024 			pq->p_nxt = p;
1025 		else
1026 			processes = p;
1027 		pq = p;
1028 		oneproc(p, &kp[i]);
1029 		argproc(p, &kp[i], kt);
1030 	}
1031 	kvm_close(kt);
1032 }
1033 #elif defined (__APPLE__)
1034 
1035 static int
GetBSDProcessList(pid_t thepid,struct kinfo_proc ** procList,size_t * procCount)1036 GetBSDProcessList(pid_t thepid, struct kinfo_proc **procList, size_t *procCount)
1037     /* derived from http://developer.apple.com/qa/qa2001/qa1123.html */
1038     /* Returns a list of all BSD processes on the system.  This routine
1039        allocates the list and puts it in *procList and a count of the
1040        number of entries in *procCount.  You are responsible for freeing
1041        this list (use "free" from System framework).
1042        all classic apps run in one process
1043        On success, the function returns 0.
1044        On error, the function returns a BSD errno value.
1045        Preconditions:
1046 	assert( procList != NULL);
1047 	assert(*procList == NULL);
1048 	assert(procCount != NULL);
1049        Postconditions:
1050 	assert( (err == 0) == (*procList != NULL) );
1051     */
1052 {
1053 	int			err;
1054 	struct kinfo_proc	*result;
1055 	int			mib[4];
1056 	size_t			length;
1057 
1058 	mib[0] = CTL_KERN;
1059 	mib[1] = KERN_PROC;
1060 	if (thepid == 0) {
1061 		mib[2] = KERN_PROC_ALL;
1062 		mib[3] = 0;
1063 	} else {
1064 		mib[2] = KERN_PROC_PID;
1065 		mib[3] = thepid;
1066 	}
1067 	/* We start by calling sysctl with result == NULL and length == 0.
1068 	   That will succeed, and set length to the appropriate length.
1069 	   We then allocate a buffer of that size and call sysctl again
1070 	   with that buffer.
1071 	*/
1072 	length = 0;
1073 	err = sysctl(mib, 4, NULL, &length, NULL, 0);
1074 	if (err == -1)
1075 		err = errno;
1076 	if (err == 0) {
1077 		result = smalloc(length);
1078 		err = sysctl(mib, 4, result, &length, NULL, 0);
1079 		if (err == -1)
1080 			err = errno;
1081 		if (err == ENOMEM) {
1082 			free(result); /* clean up */
1083 			result = NULL;
1084 		}
1085 	}
1086 	*procList = result;
1087 	*procCount = err == 0 ? length / sizeof **procList : 0;
1088 	return err;
1089 }
1090 
1091 extern	kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target);
1092 
1093 static void
oneproc(struct proc * p,struct kinfo_proc * kp)1094 oneproc(struct proc *p, struct kinfo_proc *kp)
1095 {
1096 	task_port_t	task;
1097 	kern_return_t   error;
1098 	struct		task_basic_info	task_binfo;
1099 	unsigned int	info_count = TASK_BASIC_INFO_COUNT;
1100 
1101 	p->p_pid = kp->kp_proc.p_pid;
1102 	strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname);
1103 	p->p_fname[sizeof p->p_fname - 1] = '\0';
1104 	p->p_ppid = kp->kp_eproc.e_ppid;
1105 	p->p_pgid = kp->kp_eproc.e_pgid;
1106 	p->p_sid = kp->kp_eproc.e_tpgid;
1107 	p->p_ttydev = kp->kp_eproc.e_tdev == -1 ? PRNODEV : kp->kp_eproc.e_tdev;;
1108 	p->p_uid = kp->kp_eproc.e_pcred.p_ruid;
1109 	p->p_euid = kp->kp_eproc.e_ucred.cr_uid;
1110 	p->p_gid = kp->kp_eproc.e_pcred.p_rgid;
1111 	p->p_egid = kp->kp_eproc.e_ucred.cr_gid;
1112 	p->p_start = kp->kp_proc.p_starttime.tv_sec +
1113 		(kp->kp_proc.p_starttime.tv_usec >= 500000);
1114 
1115 	error = task_for_pid(mach_task_self(), p->p_pid, &task);
1116 	if (error != KERN_SUCCESS) {
1117 		return; /* no process, nothing to show/kill */
1118 	}
1119 
1120 	info_count = TASK_BASIC_INFO_COUNT;
1121 	error = task_info(task, TASK_BASIC_INFO, &task_binfo, &info_count);
1122 	if (error != KERN_SUCCESS) {
1123 		fprintf(stderr, "Error calling task_info():%d\n", error);
1124 		exit(3);
1125 	}
1126 
1127 	p->p_size = task_binfo.virtual_size / 1024; /* in kilobytes */
1128 }
1129 
1130 static void
argproc(struct proc * p,struct kinfo_proc * kp)1131 argproc(struct proc *p, struct kinfo_proc *kp)
1132 {
1133 	size_t	size, argsz;
1134 	char	*argbuf;
1135 	int	mib[3];
1136 	long	nargs;
1137 	char	*ap, *pp;
1138 
1139 	/* allocate a procargs space per process */
1140 	mib[0] = CTL_KERN;
1141 	mib[1] = KERN_ARGMAX;
1142 	size = sizeof argsz;
1143 	if (sysctl(mib, 2, &argsz, &size, NULL, 0) == -1) {
1144 		fprintf(stderr, "error in sysctl(): %s\n", strerror(errno));
1145 		exit(3);
1146 	}
1147 	argbuf = (char *)smalloc(argsz);
1148 
1149 	/* fetch the process arguments */
1150 	mib[0] = CTL_KERN;
1151 	mib[1] = KERN_PROCARGS2;
1152 	mib[2] = kp->kp_proc.p_pid;
1153 	if (sysctl(mib, 3, argbuf, &argsz, NULL, 0) == -1)
1154 		goto DONE; /* process has no args or already left the system */
1155 
1156 	/* the number of args is at offset 0, this works for 32 and 64bit */
1157 	memcpy(&nargs, argbuf, sizeof nargs);
1158 	ap = argbuf + sizeof nargs;
1159 
1160 	/* skip the exec_path */
1161 	while (ap < &argbuf[argsz] && *ap != '\0')
1162 		ap++;
1163 	if (ap == &argbuf[argsz])
1164 		goto DONE; /* no args to show */
1165 	/* skip trailing '\0' chars */
1166 	while (ap < &argbuf[argsz] && *ap == '\0')
1167 		ap++;
1168 	if (ap == &argbuf[argsz])
1169 		goto DONE; /* no args to show */
1170 
1171 	/* now concat copy the arguments */
1172 	for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) {
1173 		if (*ap == '\0') {
1174 			if (--nargs == 0)
1175 				break;
1176 			*pp = ' ';
1177 			++ap;
1178 		} else
1179 			*pp = *ap++;
1180 	}
1181 	*pp = '\0';
1182 
1183 DONE:	free(argbuf);
1184 	return;
1185 }
1186 
1187 static void
collectprocs(void)1188 collectprocs(void)
1189 {
1190 	int	mib[2];
1191 	struct	proc *p, *pq = NULL;
1192 	struct	kinfo_proc *kp = NULL;
1193 	size_t	i, cnt;
1194 	int	err;
1195 
1196 	if ((err = GetBSDProcessList(0, &kp, &cnt)) != 0) {
1197 		fprintf(stderr, "error getting proc list: %s\n", strerror(err));
1198 		exit(3);
1199 	}
1200 	for (i = 0; i < cnt; i++) {
1201 		p = smalloc(sizeof *p);
1202 		if (pq)
1203 			pq->p_nxt = p;
1204 		else
1205 			processes = p;
1206 		pq = p;
1207 		oneproc(p, &kp[i]);
1208 		argproc(p, &kp[i]);
1209 	}
1210 	/* free the memory allocated by GetBSDProcessList */
1211 	free(kp);
1212 }
1213 #endif	/* all */
1214 
1215 static enum okay
hasattr(struct proc * p,struct attrib * a)1216 hasattr(struct proc *p, struct attrib *a)
1217 {
1218 	long	val = 0;
1219 
1220 	switch (a->a_type) {
1221 	case ATT_ALL:
1222 		return OKAY;
1223 	case ATT_PPID:
1224 		val = p->p_ppid;
1225 		break;
1226 	case ATT_PGRP:
1227 		val = p->p_pgid;
1228 		break;
1229 	case ATT_SID:
1230 		val = p->p_sid;
1231 		break;
1232 	case ATT_EUID:
1233 		val = p->p_euid;
1234 		break;
1235 	case ATT_UID:
1236 		val = p->p_uid;
1237 		break;
1238 	case ATT_GID:
1239 		val = p->p_gid;
1240 		break;
1241 	case ATT_TTY:
1242 		/*
1243 		 * Never matches processes without controlling tty.
1244 		 */
1245 		if (p->p_ttydev == PRNODEV)
1246 			return STOP;
1247 		val = p->p_ttydev;
1248 		break;
1249 	}
1250 	return val == a->a_val ? OKAY : STOP;
1251 }
1252 
1253 static void
tryproc(struct proc * p)1254 tryproc(struct proc *p)
1255 {
1256 	struct attlist	*alp;
1257 	struct attrib	*ap;
1258 	const char	*line;
1259 	regmatch_t	where;
1260 
1261 	for (alp = attributes; alp; alp = alp->al_nxt) {
1262 		for (ap = alp->al_att; ap; ap = ap->a_nxt)
1263 			if (hasattr(p, ap) == OKAY)
1264 				break;
1265 		if (ap == NULL)
1266 			return;
1267 	}
1268 	if (expression) {
1269 		line = fflag ? p->p_psargs : p->p_fname;
1270 		if (regexec(expression, line, 1, &where, 0) != 0)
1271 			return;
1272 		if (xflag && (where.rm_so != 0 || where.rm_eo == -1 ||
1273 					line[where.rm_eo] != '\0'))
1274 			return;
1275 	}
1276 	p->p_match = 1;
1277 }
1278 
1279 static void
selectprocs(void)1280 selectprocs(void)
1281 {
1282 	struct proc	*p;
1283 
1284 	for (p = processes; p; p = p->p_nxt)
1285 		tryproc(p);
1286 }
1287 
1288 static void
outproc(struct proc * p)1289 outproc(struct proc *p)
1290 {
1291 	if (pkill) {
1292 		if (kill(p->p_pid, signo) < 0)
1293 			fprintf(stderr,
1294 				"%s: Failed to signal pid %ld: %s\n",
1295 				progname, (long)p->p_pid, strerror(errno));
1296 	} else {
1297 		if (delimiter && prdelim++)
1298 			printf("%s", delimiter);
1299 		if (lflag)
1300 			printf("%5ld %s", (long)p->p_pid,
1301 					fflag ? p->p_psargs : p->p_fname);
1302 		else
1303 			printf("%ld", (long)p->p_pid);
1304 		if (delimiter == NULL)
1305 			printf("\n");
1306 	}
1307 }
1308 
1309 static void
handleprocs(void)1310 handleprocs(void)
1311 {
1312 	struct proc	*p, *selected = NULL;
1313 
1314 	for (p = processes; p; p = p->p_nxt) {
1315 		if (p->p_pid != mypid && p->p_match ^ vflag) {
1316 			matched = 1;
1317 			if (nflag) {
1318 				if (selected == NULL ||
1319 						p->p_start >= selected->p_start)
1320 					selected = p;
1321 			} else if (oflag) {
1322 				if (selected == NULL ||
1323 						p->p_start < selected->p_start)
1324 					selected = p;
1325 			} else
1326 				outproc(p);
1327 		}
1328 	}
1329 	if ((nflag || oflag) && selected)
1330 		outproc(selected);
1331 	if (prdelim && delimiter)
1332 		printf("\n");
1333 }
1334 
1335 static long
getrdev(const char * device)1336 getrdev(const char *device)
1337 {
1338 	struct stat	st;
1339 	long	id = 0;
1340 	char	*file;
1341 
1342 	file = alloca(strlen(device) + 9);
1343 	strcpy(file, "/dev/");
1344 	strcpy(&file[5], device);
1345 	if (stat(file, &st) < 0) {
1346 		strcpy(file, "/dev/tty/");
1347 		strcpy(&file[8], device);
1348 		if (stat(file, &st) == 0)
1349 			id = st.st_rdev;
1350 		else {
1351 			fprintf(stderr, "%s: unknown terminal name -- %s\n",
1352 					progname, device);
1353 			exit(2);
1354 		}
1355 	} else
1356 		id = st.st_rdev;
1357 	return id;
1358 }
1359 
1360 static struct attrib *
makatt(enum attype at,const char * string,int optc,struct attrib * aq)1361 makatt(enum attype at, const char *string, int optc, struct attrib *aq)
1362 {
1363 	struct attrib	*ap;
1364 	struct passwd	*pwd;
1365 	struct group	*grp;
1366 	char	*x;
1367 	long	val = 0;
1368 
1369 	if (*string == '\0')
1370 		at = ATT_ALL;
1371 	else switch (at) {
1372 	case ATT_PPID:
1373 	case ATT_PGRP:
1374 	case ATT_SID:
1375 		val = strtol(string, &x, 10);
1376 		if (*x != '\0' || *string == '+' || *string == '-') {
1377 			fprintf(stderr,
1378 				"%s: invalid argument for option '%c' -- %s\n",
1379 					progname, optc, string);
1380 			exit(2);
1381 		}
1382 		if (val == 0) switch (at) {
1383 		case ATT_PGRP:
1384 			val = getpgid(0);
1385 			break;
1386 		case ATT_SID:
1387 			val = getsid(0);
1388 			break;
1389 		}
1390 		break;
1391 	case ATT_EUID:
1392 		need_euid_egid = 1;
1393 		/*FALLTHRU*/
1394 	case ATT_UID:
1395 		if ((pwd = getpwnam(string)) != NULL)
1396 			val = pwd->pw_uid;
1397 		else {
1398 			val = strtol(string, &x, 10);
1399 			if (*x != '\0' || *string == '+' || *string == '-') {
1400 				fprintf(stderr,
1401 					"%s: invalid user name -- %s\n",
1402 						progname, string);
1403 				exit(2);
1404 			}
1405 		}
1406 		break;
1407 	case ATT_GID:
1408 		if ((grp = getgrnam(string)) != NULL)
1409 			val = grp->gr_gid;
1410 		else {
1411 			val = strtol(string, &x, 10);
1412 			if (*x != '\0' || *string == '+' || *string == '-') {
1413 				fprintf(stderr,
1414 					"%s: invalid group name -- %s\n",
1415 						progname, string);
1416 				exit(2);
1417 			}
1418 		}
1419 		break;
1420 	case ATT_TTY:
1421 		val = getrdev(string);
1422 		break;
1423 	}
1424 	ap = scalloc(1, sizeof *ap);
1425 	ap->a_type = at;
1426 	ap->a_val = val;
1427 	ap->a_nxt = aq;
1428 	return ap;
1429 }
1430 
1431 static void
addattribs(enum attype at,const char * list,int optc)1432 addattribs(enum attype at, const char *list, int optc)
1433 {
1434 	struct attlist	*al = NULL;
1435 	const char	*cp;
1436 
1437 	for (al = attributes; al; al = al->al_nxt)
1438 		if (al->al_att && al->al_att->a_type == at)
1439 			break;
1440 	if (al == NULL) {
1441 		al = scalloc(1, sizeof *al);
1442 		al->al_nxt = attributes;
1443 		attributes = al;
1444 	}
1445 	while (*list == ',' || isblank(*list&0377))
1446 		list++;
1447 	if (*list)
1448 		while ((cp = element(&list, '\0')) != NULL)
1449 			al->al_att = makatt(at, cp, optc, al->al_att);
1450 	else
1451 		al->al_att = makatt(at, "", optc, al->al_att);
1452 }
1453 
1454 static enum okay
getsig(const char * str)1455 getsig(const char *str)
1456 {
1457 	char	*x;
1458 	int	val;
1459 
1460 	if ((val = strtol(str, &x, 10)) >= 0 && *x == '\0' &&
1461 			*str != '-' && *str != '+') {
1462 		signo = val;
1463 		return OKAY;
1464 	}
1465 	if (str_2_sig(str, &val) == OKAY) {
1466 		signo = val;
1467 		return OKAY;
1468 	}
1469 	return STOP;
1470 }
1471 
1472 static void
usage(void)1473 usage(void)
1474 {
1475 	if (pkill)
1476 		fprintf(stderr, "\
1477 Usage: %s [-signal] [-fnovx] [-P ppidlist] [-g pgrplist] [-s sidlist]\n\
1478 \t[-u euidlist] [-U uidlist] [-G gidlist] [-t termlist] [pattern]\n",
1479 			progname);
1480 	else
1481 		fprintf(stderr, "\
1482 Usage: %s [-flnovx] [-d delim] [-P ppidlist] [-g pgrplist] [-s sidlist]\n\
1483 \t[-u euidlist] [-U uidlist] [-G gidlist] [-t termlist] [pattern]\n",
1484 			progname);
1485 	exit(2);
1486 }
1487 
1488 int
main(int argc,char ** argv)1489 main(int argc, char **argv)
1490 {
1491 	int	i, flags;
1492 
1493 	progname = basename(argv[0]);
1494 	if (strncmp(progname, "pkill", 5) == 0)
1495 		pkill = 1;
1496 	setlocale(LC_COLLATE, "");
1497 	setlocale(LC_CTYPE, "");
1498 	if (pkill && argc > 1 && argv[1][0] == '-' &&
1499 			getsig(&argv[1][1]) == OKAY)
1500 		optind = 2;
1501 	while ((i = getopt(argc, argv, pkill ? "fnovxP:g:s:u:U:G:t:" :
1502 					"flnovxd:P:g:s:u:U:G:t:")) != EOF) {
1503 		switch (i) {
1504 		case 'f':
1505 			fflag = 1;
1506 			break;
1507 		case 'l':
1508 			lflag = 1;
1509 			break;
1510 		case 'n':
1511 			nflag = 1;
1512 			break;
1513 		case 'o':
1514 			oflag = 1;
1515 			break;
1516 		case 'v':
1517 			vflag = 1;
1518 			break;
1519 		case 'x':
1520 			xflag = 1;
1521 			break;
1522 		case 'd':
1523 			delimiter = optarg;
1524 			break;
1525 		case 'P':
1526 			addattribs(ATT_PPID, optarg, i);
1527 			break;
1528 		case 'g':
1529 			addattribs(ATT_PGRP, optarg, i);
1530 			break;
1531 		case 's':
1532 			addattribs(ATT_SID, optarg, i);
1533 			break;
1534 		case 'u':
1535 			addattribs(ATT_EUID, optarg, i);
1536 			break;
1537 		case 'U':
1538 			addattribs(ATT_UID, optarg, i);
1539 			break;
1540 		case 'G':
1541 			addattribs(ATT_GID, optarg, i);
1542 			break;
1543 		case 't':
1544 			addattribs(ATT_TTY, optarg, i);
1545 			break;
1546 		default:
1547 			usage();
1548 		}
1549 	}
1550 	if (nflag && oflag) {
1551 		fprintf(stderr, "%s: -n and -o are mutually exclusive\n",
1552 				progname);
1553 		usage();
1554 	}
1555 	if (argv[optind]) {
1556 		if (argv[optind+1]) {
1557 			fprintf(stderr, "%s: illegal argument -- %s\n",
1558 					progname, argv[optind + 1]);
1559 			usage();
1560 		}
1561 		flags = REG_EXTENDED;
1562 #ifdef	REG_MTPARENBAD
1563 		flags |= REG_MTPARENBAD;
1564 #endif
1565 		if (!xflag)
1566 			flags |= REG_NOSUB;
1567 #ifdef	REG_ONESUB
1568 		else
1569 			flags |= REG_ONESUB;
1570 #endif
1571 		expression = scalloc(1, sizeof *expression);
1572 		if ((i = regcomp(expression, argv[optind], flags)) != 0) {
1573 			char	*errst;
1574 			size_t	errsz;
1575 
1576 			errsz = regerror(i, expression, NULL, 0) + 1;
1577 			errst = smalloc(errsz);
1578 			regerror(i, expression, errst, errsz);
1579 			fprintf(stderr, "%s: %s\n", progname, errst);
1580 			exit(2);
1581 		}
1582 	} else if (attributes == NULL) {
1583 		fprintf(stderr, "%s: No matching criteria specified\n",
1584 				progname);
1585 		usage();
1586 	}
1587 	mypid = getpid();
1588 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \
1589 		!defined (__OpenBSD__) && !defined (__APPLE__)
1590 	chdir_to_proc();
1591 #endif	/* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */
1592 	collectprocs();
1593 	selectprocs();
1594 	handleprocs();
1595 	return errcnt ? errcnt : matched == 0;
1596 }
1597 
1598 struct sig_strlist
1599 {
1600 	const int	sig_num;
1601 	const char	*sig_str;
1602 };
1603 
1604 static const struct sig_strlist sig_strs[] = {
1605 	{ 0,		"EXIT"	},
1606 	{ SIGHUP,	"HUP"	},
1607 	{ SIGINT,	"INT"	},
1608 	{ SIGQUIT,	"QUIT"	},
1609 	{ SIGILL,	"ILL"	},
1610 	{ SIGTRAP,	"TRAP"	},
1611 	{ SIGABRT,	"ABRT"	},
1612 #ifdef	SIGIOT
1613 	{ SIGIOT,	"IOT"	},
1614 #endif
1615 #ifdef	SIGEMT
1616 	{ SIGEMT,	"EMT"	},
1617 #endif
1618 #ifdef	SIGFPE
1619 	{ SIGFPE,	"FPE"	},
1620 #endif
1621 #ifdef	SIGKILL
1622 	{ SIGKILL,	"KILL"	},
1623 #endif
1624 #ifdef	SIGBUS
1625 	{ SIGBUS,	"BUS"	},
1626 #endif
1627 #ifdef	SIGSEGV
1628 	{ SIGSEGV,	"SEGV"	},
1629 #endif
1630 #ifdef	SIGSYS
1631 	{ SIGSYS,	"SYS"	},
1632 #endif
1633 #ifdef	SIGPIPE
1634 	{ SIGPIPE,	"PIPE"	},
1635 #endif
1636 #ifdef	SIGALRM
1637 	{ SIGALRM,	"ALRM"	},
1638 #endif
1639 #ifdef	SIGTERM
1640 	{ SIGTERM,	"TERM"	},
1641 #endif
1642 #ifdef	SIGUSR1
1643 	{ SIGUSR1,	"USR1"	},
1644 #endif
1645 #ifdef	SIGUSR2
1646 	{ SIGUSR2,	"USR2"	},
1647 #endif
1648 #ifdef	SIGCLD
1649 	{ SIGCLD,	"CLD"	},
1650 #endif
1651 #ifdef	SIGCHLD
1652 	{ SIGCHLD,	"CHLD"	},
1653 #endif
1654 #ifdef	SIGPWR
1655 	{ SIGPWR,	"PWR"	},
1656 #endif
1657 #ifdef	SIGWINCH
1658 	{ SIGWINCH,	"WINCH"	},
1659 #endif
1660 #ifdef	SIGURG
1661 	{ SIGURG,	"URG"	},
1662 #endif
1663 #ifdef	SIGPOLL
1664 	{ SIGPOLL,	"POLL"	},
1665 #endif
1666 #ifdef	SIGIO
1667 	{ SIGIO,	"IO"	},
1668 #endif
1669 #ifdef	SIGSTOP
1670 	{ SIGSTOP,	"STOP"	},
1671 #endif
1672 #ifdef	SIGTSTP
1673 	{ SIGTSTP,	"TSTP"	},
1674 #endif
1675 #ifdef	SIGCONT
1676 	{ SIGCONT,	"CONT"	},
1677 #endif
1678 #ifdef	SIGTTIN
1679 	{ SIGTTIN,	"TTIN"	},
1680 #endif
1681 #ifdef	SIGTTOU
1682 	{ SIGTTOU,	"TTOU"	},
1683 #endif
1684 #ifdef	SIGVTALRM
1685 	{ SIGVTALRM,	"VTALRM"	},
1686 #endif
1687 #ifdef	SIGPROF
1688 	{ SIGPROF,	"PROF"	},
1689 #endif
1690 #ifdef	SIGXCPU
1691 	{ SIGXCPU,	"XCPU"	},
1692 #endif
1693 #ifdef	SIGXFSZ
1694 	{ SIGXFSZ,	"XFSZ"	},
1695 #endif
1696 #ifdef	SIGWAITING
1697 	{ SIGWAITING,	"WAITING"	},
1698 #endif
1699 #ifdef	SIGLWP
1700 	{ SIGLWP,	"LWP"	},
1701 #endif
1702 #ifdef	SIGFREEZE
1703 	{ SIGFREEZE,	"FREEZE"	},
1704 #endif
1705 #ifdef	SIGTHAW
1706 	{ SIGTHAW,	"THAW"	},
1707 #endif
1708 #ifdef	SIGCANCEL
1709 	{ SIGCANCEL,	"CANCEL"	},
1710 #endif
1711 #ifdef	SIGLOST
1712 	{ SIGLOST,	"LOST"	},
1713 #endif
1714 #ifdef	SIGSTKFLT
1715 	{ SIGSTKFLT,	"STKFLT"	},
1716 #endif
1717 #ifdef	SIGINFO
1718 	{ SIGINFO,	"INFO"	},
1719 #endif
1720 #ifdef	SIG_2_STR_WITH_RT_SIGNALS
1721 	{ SIGRTMIN,	"RTMIN"	},
1722 	{ SIGRTMIN+1,	"RTMIN+1"	},
1723 	{ SIGRTMIN+2,	"RTMIN+2"	},
1724 	{ SIGRTMIN+3,	"RTMIN+3"	},
1725 	{ SIGRTMAX-3,	"RTMAX-3"	},
1726 	{ SIGRTMAX-2,	"RTMAX-2"	},
1727 	{ SIGRTMAX-1,	"RTMAX-1"	},
1728 	{ SIGRTMAX,	"RTMAX"	},
1729 #endif	/* SIG_2_STR_WITH_RT_SIGNALS */
1730 	{ -1,		NULL	}
1731 };
1732 
1733 static int
str_2_sig(const char * str,int * signum)1734 str_2_sig(const char *str, int *signum)
1735 {
1736 	int	i;
1737 
1738 	for (i = 0; sig_strs[i].sig_str; i++)
1739 		if (eq(str, sig_strs[i].sig_str))
1740 			break;
1741 	if (sig_strs[i].sig_str == NULL)
1742 		return STOP;
1743 	*signum = sig_strs[i].sig_num;
1744 	return OKAY;
1745 }
1746