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