1 1.34 roy /* $NetBSD: pkill.c,v 1.34 2024/10/07 06:14:05 roy Exp $ */ 2 1.1 ad 3 1.1 ad /*- 4 1.32 ad * Copyright (c) 2002, 2022 The NetBSD Foundation, Inc. 5 1.1 ad * All rights reserved. 6 1.1 ad * 7 1.1 ad * This code is derived from software contributed to The NetBSD Foundation 8 1.1 ad * by Andrew Doran. 9 1.1 ad * 10 1.1 ad * Redistribution and use in source and binary forms, with or without 11 1.1 ad * modification, are permitted provided that the following conditions 12 1.1 ad * are met: 13 1.1 ad * 1. Redistributions of source code must retain the above copyright 14 1.1 ad * notice, this list of conditions and the following disclaimer. 15 1.1 ad * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 ad * notice, this list of conditions and the following disclaimer in the 17 1.1 ad * documentation and/or other materials provided with the distribution. 18 1.1 ad * 19 1.1 ad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 ad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 ad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 ad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 ad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 ad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 ad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 ad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 ad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 ad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 ad * POSSIBILITY OF SUCH DAMAGE. 30 1.1 ad */ 31 1.1 ad 32 1.1 ad #include <sys/cdefs.h> 33 1.2 ad #ifndef lint 34 1.34 roy __RCSID("$NetBSD: pkill.c,v 1.34 2024/10/07 06:14:05 roy Exp $"); 35 1.2 ad #endif /* !lint */ 36 1.1 ad 37 1.1 ad #include <sys/types.h> 38 1.1 ad #include <sys/param.h> 39 1.1 ad #include <sys/sysctl.h> 40 1.1 ad #include <sys/proc.h> 41 1.1 ad #include <sys/queue.h> 42 1.29 dsl #include <sys/resource.h> 43 1.1 ad #include <sys/stat.h> 44 1.1 ad 45 1.1 ad #include <stdio.h> 46 1.1 ad #include <stdlib.h> 47 1.1 ad #include <limits.h> 48 1.1 ad #include <string.h> 49 1.1 ad #include <unistd.h> 50 1.1 ad #include <signal.h> 51 1.1 ad #include <regex.h> 52 1.1 ad #include <ctype.h> 53 1.1 ad #include <kvm.h> 54 1.1 ad #include <err.h> 55 1.34 roy #include <fcntl.h> 56 1.1 ad #include <pwd.h> 57 1.1 ad #include <grp.h> 58 1.1 ad #include <errno.h> 59 1.11 christos #include <paths.h> 60 1.1 ad 61 1.1 ad #define STATUS_MATCH 0 62 1.1 ad #define STATUS_NOMATCH 1 63 1.1 ad #define STATUS_BADUSAGE 2 64 1.1 ad #define STATUS_ERROR 3 65 1.1 ad 66 1.34 roy #define MIN_PID 5 67 1.34 roy #define MAX_PID 30000 // XXX PID_MAX from sys/proc.h? 68 1.34 roy 69 1.1 ad enum listtype { 70 1.1 ad LT_GENERIC, 71 1.1 ad LT_USER, 72 1.1 ad LT_GROUP, 73 1.1 ad LT_TTY, 74 1.1 ad LT_PGRP, 75 1.1 ad LT_SID 76 1.1 ad }; 77 1.1 ad 78 1.1 ad struct list { 79 1.1 ad SLIST_ENTRY(list) li_chain; 80 1.1 ad long li_number; 81 1.1 ad }; 82 1.1 ad 83 1.1 ad SLIST_HEAD(listhead, list); 84 1.1 ad 85 1.11 christos static struct kinfo_proc2 *plist; 86 1.11 christos static char *selected; 87 1.11 christos static const char *delim = "\n"; 88 1.11 christos static int nproc; 89 1.11 christos static int pgrep; 90 1.26 mrg static int prenice; 91 1.11 christos static int signum = SIGTERM; 92 1.26 mrg static int nicenum; 93 1.11 christos static int newest; 94 1.33 simonb static int quiet; 95 1.11 christos static int inverse; 96 1.11 christos static int longfmt; 97 1.11 christos static int matchargs; 98 1.11 christos static int fullmatch; 99 1.11 christos static int cflags = REG_EXTENDED; 100 1.11 christos static kvm_t *kd; 101 1.11 christos static pid_t mypid; 102 1.11 christos 103 1.11 christos static struct listhead euidlist = SLIST_HEAD_INITIALIZER(list); 104 1.11 christos static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list); 105 1.11 christos static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list); 106 1.11 christos static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list); 107 1.11 christos static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list); 108 1.11 christos static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list); 109 1.11 christos static struct listhead sidlist = SLIST_HEAD_INITIALIZER(list); 110 1.1 ad 111 1.22 perry static void usage(void) __dead; 112 1.14 dsainty static int killact(const struct kinfo_proc2 *); 113 1.26 mrg static int reniceact(const struct kinfo_proc2 *); 114 1.14 dsainty static int grepact(const struct kinfo_proc2 *); 115 1.11 christos static void makelist(struct listhead *, enum listtype, char *); 116 1.34 roy static int takepid(const char *, int); 117 1.1 ad 118 1.1 ad int 119 1.1 ad main(int argc, char **argv) 120 1.1 ad { 121 1.34 roy char buf[_POSIX2_LINE_MAX], **pargv, *q, *pidfile = NULL; 122 1.34 roy int i, j, ch, bestidx, rv, criteria, pidfromfile, pidfilelock = 0; 123 1.14 dsainty int (*action)(const struct kinfo_proc2 *); 124 1.14 dsainty const struct kinfo_proc2 *kp; 125 1.1 ad struct list *li; 126 1.28 christos const char *p; 127 1.1 ad u_int32_t bestsec, bestusec; 128 1.1 ad regex_t reg; 129 1.1 ad regmatch_t regmatch; 130 1.1 ad 131 1.11 christos setprogname(argv[0]); 132 1.11 christos 133 1.1 ad if (strcmp(getprogname(), "pgrep") == 0) { 134 1.1 ad action = grepact; 135 1.1 ad pgrep = 1; 136 1.26 mrg } else if (strcmp(getprogname(), "prenice") == 0) { 137 1.30 prlw1 action = reniceact; 138 1.26 mrg prenice = 1; 139 1.1 ad } else { 140 1.1 ad action = killact; 141 1.1 ad p = argv[1]; 142 1.1 ad 143 1.3 augustss if (argc > 1 && p[0] == '-') { 144 1.1 ad p++; 145 1.3 augustss i = (int)strtol(p, &q, 10); 146 1.3 augustss if (*q == '\0') { 147 1.1 ad signum = i; 148 1.1 ad argv++; 149 1.3 augustss argc--; 150 1.1 ad } else { 151 1.1 ad if (strncasecmp(p, "sig", 3) == 0) 152 1.1 ad p += 3; 153 1.1 ad for (i = 1; i < NSIG; i++) 154 1.1 ad if (strcasecmp(sys_signame[i], p) == 0) 155 1.1 ad break; 156 1.1 ad if (i != NSIG) { 157 1.1 ad signum = i; 158 1.1 ad argv++; 159 1.3 augustss argc--; 160 1.1 ad } 161 1.1 ad } 162 1.1 ad } 163 1.1 ad } 164 1.1 ad 165 1.1 ad criteria = 0; 166 1.1 ad 167 1.27 mrg if (prenice) { 168 1.27 mrg if (argc < 2) 169 1.27 mrg usage(); 170 1.27 mrg 171 1.27 mrg if (strcmp(argv[1], "-l") == 0) { 172 1.27 mrg longfmt = 1; 173 1.27 mrg argv++; 174 1.27 mrg argc--; 175 1.27 mrg } 176 1.27 mrg 177 1.27 mrg if (argc < 2) 178 1.27 mrg usage(); 179 1.27 mrg 180 1.27 mrg p = argv[1]; 181 1.27 mrg 182 1.27 mrg i = (int)strtol(p, &q, 10); 183 1.27 mrg if (*q == '\0') { 184 1.27 mrg nicenum = i; 185 1.27 mrg argv++; 186 1.27 mrg argc--; 187 1.27 mrg } else 188 1.27 mrg usage(); 189 1.27 mrg } else { 190 1.34 roy while ((ch = getopt(argc, argv, "F:G:LP:U:d:fg:ilnqs:t:u:vx")) != -1) 191 1.26 mrg switch (ch) { 192 1.34 roy case 'F': 193 1.34 roy pidfile = optarg; 194 1.34 roy criteria = 1; 195 1.34 roy break; 196 1.26 mrg case 'G': 197 1.26 mrg makelist(&rgidlist, LT_GROUP, optarg); 198 1.26 mrg criteria = 1; 199 1.26 mrg break; 200 1.34 roy case 'L': 201 1.34 roy pidfilelock = 1; 202 1.34 roy break; 203 1.26 mrg case 'P': 204 1.26 mrg makelist(&ppidlist, LT_GENERIC, optarg); 205 1.26 mrg criteria = 1; 206 1.26 mrg break; 207 1.26 mrg case 'U': 208 1.26 mrg makelist(&ruidlist, LT_USER, optarg); 209 1.26 mrg criteria = 1; 210 1.26 mrg break; 211 1.26 mrg case 'd': 212 1.26 mrg if (!pgrep) 213 1.26 mrg usage(); 214 1.26 mrg delim = optarg; 215 1.26 mrg break; 216 1.26 mrg case 'f': 217 1.26 mrg matchargs = 1; 218 1.26 mrg break; 219 1.26 mrg case 'g': 220 1.26 mrg makelist(&pgrplist, LT_PGRP, optarg); 221 1.26 mrg criteria = 1; 222 1.26 mrg break; 223 1.26 mrg case 'i': 224 1.26 mrg cflags |= REG_ICASE; 225 1.26 mrg break; 226 1.26 mrg case 'l': 227 1.26 mrg longfmt = 1; 228 1.26 mrg break; 229 1.26 mrg case 'n': 230 1.26 mrg newest = 1; 231 1.26 mrg criteria = 1; 232 1.26 mrg break; 233 1.33 simonb case 'q': 234 1.33 simonb if (!pgrep) 235 1.33 simonb usage(); 236 1.33 simonb quiet = 1; 237 1.33 simonb break; 238 1.26 mrg case 's': 239 1.26 mrg makelist(&sidlist, LT_SID, optarg); 240 1.26 mrg criteria = 1; 241 1.26 mrg break; 242 1.26 mrg case 't': 243 1.26 mrg makelist(&tdevlist, LT_TTY, optarg); 244 1.26 mrg criteria = 1; 245 1.26 mrg break; 246 1.26 mrg case 'u': 247 1.26 mrg makelist(&euidlist, LT_USER, optarg); 248 1.26 mrg criteria = 1; 249 1.26 mrg break; 250 1.26 mrg case 'v': 251 1.26 mrg inverse = 1; 252 1.26 mrg break; 253 1.26 mrg case 'x': 254 1.26 mrg fullmatch = 1; 255 1.26 mrg break; 256 1.26 mrg default: 257 1.1 ad usage(); 258 1.26 mrg /* NOTREACHED */ 259 1.26 mrg } 260 1.27 mrg argc -= optind; 261 1.27 mrg argv += optind; 262 1.26 mrg } 263 1.1 ad 264 1.1 ad if (argc != 0) 265 1.1 ad criteria = 1; 266 1.1 ad if (!criteria) 267 1.1 ad usage(); 268 1.34 roy if (pidfile != NULL) 269 1.34 roy pidfromfile = takepid(pidfile, pidfilelock); 270 1.34 roy else { 271 1.34 roy if (pidfilelock) { 272 1.34 roy errx(STATUS_ERROR, 273 1.34 roy "Option -L doesn't make sense without -F"); 274 1.34 roy } 275 1.34 roy pidfromfile = -1; 276 1.34 roy } 277 1.1 ad 278 1.1 ad mypid = getpid(); 279 1.1 ad 280 1.1 ad /* 281 1.1 ad * Retrieve the list of running processes from the kernel. 282 1.1 ad */ 283 1.1 ad kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf); 284 1.1 ad if (kd == NULL) 285 1.11 christos errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); 286 1.1 ad 287 1.1 ad plist = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc); 288 1.1 ad if (plist == NULL) 289 1.11 christos errx(STATUS_ERROR, "Cannot get process list (%s)", 290 1.11 christos kvm_geterr(kd)); 291 1.1 ad 292 1.1 ad /* 293 1.1 ad * Allocate memory which will be used to keep track of the 294 1.1 ad * selection. 295 1.1 ad */ 296 1.32 ad if ((selected = calloc(sizeof(*selected), (size_t)nproc)) == NULL) 297 1.11 christos err(STATUS_ERROR, "Cannot allocate memory for %d processes", 298 1.11 christos nproc); 299 1.1 ad 300 1.1 ad /* 301 1.1 ad * Refine the selection. 302 1.1 ad */ 303 1.1 ad for (; *argv != NULL; argv++) { 304 1.9 sketch if ((rv = regcomp(®, *argv, cflags)) != 0) { 305 1.12 christos (void)regerror(rv, ®, buf, sizeof(buf)); 306 1.11 christos errx(STATUS_BADUSAGE, 307 1.11 christos "Cannot compile regular expression `%s' (%s)", 308 1.11 christos *argv, buf); 309 1.1 ad } 310 1.1 ad 311 1.1 ad for (i = 0, kp = plist; i < nproc; i++, kp++) { 312 1.20 pavel if ((kp->p_flag & P_SYSTEM) != 0 || kp->p_pid == mypid) 313 1.1 ad continue; 314 1.1 ad 315 1.28 christos if ((pargv = kvm_getargv2(kd, kp, 0)) == NULL) 316 1.28 christos continue; 317 1.1 ad if (matchargs) { 318 1.1 ad 319 1.1 ad j = 0; 320 1.25 lukem while (j < (int)sizeof(buf) && *pargv != NULL) { 321 1.1 ad j += snprintf(buf + j, sizeof(buf) - j, 322 1.1 ad pargv[1] != NULL ? "%s " : "%s", 323 1.1 ad pargv[0]); 324 1.1 ad pargv++; 325 1.1 ad } 326 1.31 kre } else if (pargv[0] != NULL) 327 1.28 christos strlcpy(buf, pargv[0], sizeof(buf)); 328 1.31 kre else 329 1.31 kre strlcpy(buf, kp->p_comm, sizeof(buf)); 330 1.1 ad 331 1.28 christos rv = regexec(®, buf, 1, ®match, 0); 332 1.1 ad if (rv == 0) { 333 1.1 ad if (fullmatch) { 334 1.1 ad if (regmatch.rm_so == 0 && 335 1.28 christos regmatch.rm_eo == 336 1.28 christos (regoff_t)strlen(buf)) 337 1.1 ad selected[i] = 1; 338 1.1 ad } else 339 1.1 ad selected[i] = 1; 340 1.1 ad } else if (rv != REG_NOMATCH) { 341 1.12 christos (void)regerror(rv, ®, buf, sizeof(buf)); 342 1.11 christos errx(STATUS_ERROR, 343 1.11 christos "Regular expression evaluation error (%s)", 344 1.11 christos buf); 345 1.1 ad } 346 1.1 ad } 347 1.1 ad 348 1.1 ad regfree(®); 349 1.1 ad } 350 1.1 ad 351 1.1 ad for (i = 0, kp = plist; i < nproc; i++, kp++) { 352 1.20 pavel if ((kp->p_flag & P_SYSTEM) != 0) 353 1.1 ad continue; 354 1.1 ad 355 1.34 roy if (pidfromfile >= 0 && kp->p_pid != pidfromfile) { 356 1.34 roy selected[i] = 0; 357 1.34 roy continue; 358 1.34 roy } 359 1.34 roy 360 1.1 ad SLIST_FOREACH(li, &ruidlist, li_chain) 361 1.1 ad if (kp->p_ruid == (uid_t)li->li_number) 362 1.1 ad break; 363 1.1 ad if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 364 1.1 ad selected[i] = 0; 365 1.1 ad continue; 366 1.1 ad } 367 1.1 ad 368 1.1 ad SLIST_FOREACH(li, &rgidlist, li_chain) 369 1.1 ad if (kp->p_rgid == (gid_t)li->li_number) 370 1.1 ad break; 371 1.1 ad if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 372 1.1 ad selected[i] = 0; 373 1.1 ad continue; 374 1.1 ad } 375 1.1 ad 376 1.1 ad SLIST_FOREACH(li, &euidlist, li_chain) 377 1.1 ad if (kp->p_uid == (uid_t)li->li_number) 378 1.1 ad break; 379 1.1 ad if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 380 1.1 ad selected[i] = 0; 381 1.1 ad continue; 382 1.1 ad } 383 1.1 ad 384 1.1 ad SLIST_FOREACH(li, &ppidlist, li_chain) 385 1.25 lukem if ((uid_t)kp->p_ppid == (uid_t)li->li_number) 386 1.1 ad break; 387 1.1 ad if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 388 1.1 ad selected[i] = 0; 389 1.1 ad continue; 390 1.1 ad } 391 1.1 ad 392 1.1 ad SLIST_FOREACH(li, &pgrplist, li_chain) 393 1.25 lukem if (kp->p__pgid == (pid_t)li->li_number) 394 1.1 ad break; 395 1.1 ad if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 396 1.1 ad selected[i] = 0; 397 1.1 ad continue; 398 1.1 ad } 399 1.1 ad 400 1.1 ad SLIST_FOREACH(li, &tdevlist, li_chain) { 401 1.1 ad if (li->li_number == -1 && 402 1.20 pavel (kp->p_flag & P_CONTROLT) == 0) 403 1.1 ad break; 404 1.1 ad if (kp->p_tdev == (uid_t)li->li_number) 405 1.1 ad break; 406 1.1 ad } 407 1.1 ad if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 408 1.1 ad selected[i] = 0; 409 1.1 ad continue; 410 1.1 ad } 411 1.1 ad 412 1.1 ad SLIST_FOREACH(li, &sidlist, li_chain) 413 1.25 lukem if (kp->p_sid == (pid_t)li->li_number) 414 1.1 ad break; 415 1.1 ad if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 416 1.1 ad selected[i] = 0; 417 1.1 ad continue; 418 1.1 ad } 419 1.1 ad 420 1.1 ad if (argc == 0) 421 1.1 ad selected[i] = 1; 422 1.1 ad } 423 1.1 ad 424 1.1 ad if (newest) { 425 1.1 ad bestsec = 0; 426 1.1 ad bestusec = 0; 427 1.1 ad bestidx = -1; 428 1.1 ad 429 1.1 ad for (i = 0, kp = plist; i < nproc; i++, kp++) { 430 1.1 ad if (!selected[i]) 431 1.1 ad continue; 432 1.1 ad 433 1.1 ad if (kp->p_ustart_sec > bestsec || 434 1.1 ad (kp->p_ustart_sec == bestsec 435 1.1 ad && kp->p_ustart_usec > bestusec)) { 436 1.1 ad bestsec = kp->p_ustart_sec; 437 1.1 ad bestusec = kp->p_ustart_usec; 438 1.1 ad bestidx = i; 439 1.1 ad } 440 1.1 ad } 441 1.1 ad 442 1.12 christos (void)memset(selected, 0, (size_t)nproc); 443 1.1 ad if (bestidx != -1) 444 1.1 ad selected[bestidx] = 1; 445 1.1 ad } 446 1.1 ad 447 1.1 ad /* 448 1.1 ad * Take the appropriate action for each matched process, if any. 449 1.1 ad */ 450 1.1 ad for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { 451 1.1 ad if (kp->p_pid == mypid) 452 1.1 ad continue; 453 1.1 ad if (selected[i]) { 454 1.1 ad if (inverse) 455 1.1 ad continue; 456 1.1 ad } else if (!inverse) 457 1.4 ad continue; 458 1.4 ad 459 1.20 pavel if ((kp->p_flag & P_SYSTEM) != 0) 460 1.1 ad continue; 461 1.1 ad 462 1.10 christos rv |= (*action)(kp); 463 1.1 ad } 464 1.1 ad 465 1.12 christos return rv ? STATUS_MATCH : STATUS_NOMATCH; 466 1.1 ad } 467 1.1 ad 468 1.11 christos static void 469 1.1 ad usage(void) 470 1.1 ad { 471 1.1 ad const char *ustr; 472 1.1 ad 473 1.26 mrg if (prenice) 474 1.27 mrg fprintf(stderr, "Usage: %s [-l] priority pattern ...\n", 475 1.26 mrg getprogname()); 476 1.26 mrg else { 477 1.26 mrg if (pgrep) 478 1.34 roy ustr = "[-Lfilnqvx] [-d delim]"; 479 1.26 mrg else 480 1.34 roy ustr = "[-signal] [-Lfilnvx]"; 481 1.26 mrg 482 1.26 mrg (void)fprintf(stderr, 483 1.34 roy "Usage: %s %s [-F pidfile] [-G gid] [-g pgrp] [-P ppid] [-s sid] " 484 1.26 mrg "[-t tty]\n" 485 1.26 mrg " [-U uid] [-u euid] pattern ...\n", 486 1.26 mrg getprogname(), ustr); 487 1.26 mrg } 488 1.1 ad 489 1.16 kleink exit(STATUS_BADUSAGE); 490 1.1 ad } 491 1.1 ad 492 1.11 christos static int 493 1.14 dsainty killact(const struct kinfo_proc2 *kp) 494 1.1 ad { 495 1.21 erh if (longfmt) 496 1.21 erh grepact(kp); 497 1.10 christos if (kill(kp->p_pid, signum) == -1) { 498 1.13 dsainty 499 1.13 dsainty /* 500 1.13 dsainty * Check for ESRCH, which indicates that the process 501 1.13 dsainty * disappeared between us matching it and us 502 1.15 kleink * signalling it; don't issue a warning about it. 503 1.13 dsainty */ 504 1.15 kleink if (errno != ESRCH) 505 1.15 kleink warn("signalling pid %d", (int)kp->p_pid); 506 1.1 ad 507 1.15 kleink /* 508 1.15 kleink * Return 0 to indicate that the process should not be 509 1.15 kleink * considered a match, since we didn't actually get to 510 1.15 kleink * signal it. 511 1.15 kleink */ 512 1.15 kleink return 0; 513 1.10 christos } 514 1.10 christos 515 1.10 christos return 1; 516 1.1 ad } 517 1.1 ad 518 1.11 christos static int 519 1.26 mrg reniceact(const struct kinfo_proc2 *kp) 520 1.26 mrg { 521 1.26 mrg int oldprio; 522 1.26 mrg 523 1.26 mrg if (longfmt) 524 1.26 mrg grepact(kp); 525 1.26 mrg 526 1.26 mrg errno = 0; 527 1.26 mrg if ((oldprio = getpriority(PRIO_PROCESS, kp->p_pid)) == -1 && 528 1.26 mrg errno != 0) { 529 1.26 mrg warn("%d: getpriority", kp->p_pid); 530 1.26 mrg return 0; 531 1.26 mrg } 532 1.26 mrg 533 1.26 mrg if (setpriority(PRIO_PROCESS, kp->p_pid, nicenum) == -1) { 534 1.26 mrg warn("%d: setpriority", kp->p_pid); 535 1.26 mrg return 0; 536 1.26 mrg } 537 1.26 mrg 538 1.26 mrg (void)printf("%d: old priority %d, new priority %d\n", 539 1.26 mrg kp->p_pid, oldprio, nicenum); 540 1.26 mrg 541 1.26 mrg return 1; 542 1.26 mrg } 543 1.26 mrg 544 1.26 mrg static int 545 1.14 dsainty grepact(const struct kinfo_proc2 *kp) 546 1.1 ad { 547 1.1 ad char **argv; 548 1.1 ad 549 1.33 simonb if (quiet) 550 1.33 simonb return 1; 551 1.33 simonb 552 1.1 ad if (longfmt && matchargs) { 553 1.13 dsainty 554 1.13 dsainty /* 555 1.13 dsainty * If kvm_getargv2() failed the process has probably 556 1.13 dsainty * disappeared. Return 0 to indicate that the process 557 1.13 dsainty * should not be considered a match, since we are no 558 1.13 dsainty * longer in a position to output it as a match. 559 1.13 dsainty */ 560 1.1 ad if ((argv = kvm_getargv2(kd, kp, 0)) == NULL) 561 1.10 christos return 0; 562 1.1 ad 563 1.11 christos (void)printf("%d ", (int)kp->p_pid); 564 1.1 ad for (; *argv != NULL; argv++) { 565 1.11 christos (void)printf("%s", *argv); 566 1.1 ad if (argv[1] != NULL) 567 1.11 christos (void)putchar(' '); 568 1.1 ad } 569 1.1 ad } else if (longfmt) 570 1.11 christos (void)printf("%d %s", (int)kp->p_pid, kp->p_comm); 571 1.1 ad else 572 1.11 christos (void)printf("%d", (int)kp->p_pid); 573 1.1 ad 574 1.11 christos (void)printf("%s", delim); 575 1.10 christos 576 1.10 christos return 1; 577 1.1 ad } 578 1.1 ad 579 1.11 christos static void 580 1.1 ad makelist(struct listhead *head, enum listtype type, char *src) 581 1.1 ad { 582 1.1 ad struct list *li; 583 1.1 ad struct passwd *pw; 584 1.1 ad struct group *gr; 585 1.1 ad struct stat st; 586 1.11 christos char *sp, *ep, buf[MAXPATHLEN]; 587 1.11 christos const char *p; 588 1.1 ad int empty; 589 1.11 christos const char *prefix = _PATH_DEV; 590 1.1 ad 591 1.1 ad empty = 1; 592 1.1 ad 593 1.1 ad while ((sp = strsep(&src, ",")) != NULL) { 594 1.1 ad if (*sp == '\0') 595 1.1 ad usage(); 596 1.1 ad 597 1.1 ad if ((li = malloc(sizeof(*li))) == NULL) 598 1.28 christos err(STATUS_ERROR, "Cannot allocate %zu bytes", 599 1.11 christos sizeof(*li)); 600 1.1 ad SLIST_INSERT_HEAD(head, li, li_chain); 601 1.1 ad empty = 0; 602 1.1 ad 603 1.11 christos li->li_number = (uid_t)strtol(sp, &ep, 0); 604 1.24 christos if (*ep == '\0' && type != LT_TTY) { 605 1.1 ad switch (type) { 606 1.1 ad case LT_PGRP: 607 1.1 ad if (li->li_number == 0) 608 1.1 ad li->li_number = getpgrp(); 609 1.1 ad break; 610 1.1 ad case LT_SID: 611 1.1 ad if (li->li_number == 0) 612 1.1 ad li->li_number = getsid(mypid); 613 1.1 ad break; 614 1.1 ad default: 615 1.1 ad break; 616 1.1 ad } 617 1.1 ad continue; 618 1.1 ad } 619 1.1 ad 620 1.1 ad switch (type) { 621 1.1 ad case LT_USER: 622 1.1 ad if ((pw = getpwnam(sp)) == NULL) 623 1.11 christos errx(STATUS_BADUSAGE, "Unknown user `%s'", 624 1.8 abs sp); 625 1.1 ad li->li_number = pw->pw_uid; 626 1.1 ad break; 627 1.1 ad case LT_GROUP: 628 1.1 ad if ((gr = getgrnam(sp)) == NULL) 629 1.11 christos errx(STATUS_BADUSAGE, "Unknown group `%s'", 630 1.8 abs sp); 631 1.1 ad li->li_number = gr->gr_gid; 632 1.1 ad break; 633 1.1 ad case LT_TTY: 634 1.24 christos p = sp; 635 1.24 christos if (*sp == '/') 636 1.24 christos prefix = ""; 637 1.24 christos else if (strcmp(sp, "-") == 0) { 638 1.1 ad li->li_number = -1; 639 1.1 ad break; 640 1.1 ad } else if (strcmp(sp, "co") == 0) 641 1.1 ad p = "console"; 642 1.1 ad else if (strncmp(sp, "tty", 3) == 0) 643 1.24 christos /* all set */; 644 1.24 christos else if (strncmp(sp, "pts/", 4) == 0) 645 1.24 christos /* all set */; 646 1.24 christos else if (*ep != '\0' || (strlen(sp) == 2 && *sp == '0')) 647 1.11 christos prefix = _PATH_TTY; 648 1.24 christos else 649 1.24 christos prefix = _PATH_DEV_PTS; 650 1.1 ad 651 1.11 christos (void)snprintf(buf, sizeof(buf), "%s%s", prefix, p); 652 1.1 ad 653 1.11 christos if (stat(buf, &st) == -1) { 654 1.1 ad if (errno == ENOENT) 655 1.1 ad errx(STATUS_BADUSAGE, 656 1.24 christos "No such tty: `%s'", buf); 657 1.24 christos err(STATUS_ERROR, "Cannot access `%s'", buf); 658 1.1 ad } 659 1.1 ad 660 1.1 ad if ((st.st_mode & S_IFCHR) == 0) 661 1.24 christos errx(STATUS_BADUSAGE, "Not a tty: `%s'", buf); 662 1.1 ad 663 1.1 ad li->li_number = st.st_rdev; 664 1.1 ad break; 665 1.1 ad default: 666 1.1 ad usage(); 667 1.11 christos } 668 1.1 ad } 669 1.1 ad 670 1.1 ad if (empty) 671 1.1 ad usage(); 672 1.1 ad } 673 1.34 roy 674 1.34 roy static int 675 1.34 roy takepid(const char *pidfile, int pidfilelock) 676 1.34 roy { 677 1.34 roy char *endp, line[BUFSIZ]; 678 1.34 roy FILE *fh; 679 1.34 roy long rval; 680 1.34 roy 681 1.34 roy fh = fopen(pidfile, "r"); 682 1.34 roy if (fh == NULL) 683 1.34 roy err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); 684 1.34 roy 685 1.34 roy if (pidfilelock) { 686 1.34 roy /* 687 1.34 roy * If we can lock pidfile, this means that daemon is not 688 1.34 roy * running, so would be better not to kill some random process. 689 1.34 roy */ 690 1.34 roy if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { 691 1.34 roy (void)fclose(fh); 692 1.34 roy errx(STATUS_ERROR, "File '%s' can be locked", pidfile); 693 1.34 roy } else { 694 1.34 roy if (errno != EWOULDBLOCK) { 695 1.34 roy errx(STATUS_ERROR, 696 1.34 roy "Error while locking file '%s'", pidfile); 697 1.34 roy } 698 1.34 roy } 699 1.34 roy } 700 1.34 roy 701 1.34 roy if (fgets(line, sizeof(line), fh) == NULL) { 702 1.34 roy if (feof(fh)) { 703 1.34 roy (void)fclose(fh); 704 1.34 roy errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); 705 1.34 roy } 706 1.34 roy (void)fclose(fh); 707 1.34 roy err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); 708 1.34 roy } 709 1.34 roy (void)fclose(fh); 710 1.34 roy 711 1.34 roy rval = strtol(line, &endp, 10); 712 1.34 roy if (*endp != '\0' && !isspace((unsigned char)*endp)) 713 1.34 roy errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 714 1.34 roy else if (rval < MIN_PID || rval > MAX_PID) 715 1.34 roy errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); 716 1.34 roy return (rval); 717 1.34 roy } 718