hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

pgrep.c (37451B)


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