pkill.c revision 143879
1143079Sdelphij/* $NetBSD: pkill.c,v 1.8 2005/03/02 15:31:44 abs Exp $ */ 2127412Sgad 3127412Sgad/*- 4127412Sgad * Copyright (c) 2002 The NetBSD Foundation, Inc. 5127412Sgad * All rights reserved. 6127412Sgad * 7127412Sgad * This code is derived from software contributed to The NetBSD Foundation 8127412Sgad * by Andrew Doran. 9127412Sgad * 10127412Sgad * Redistribution and use in source and binary forms, with or without 11127412Sgad * modification, are permitted provided that the following conditions 12127412Sgad * are met: 13127412Sgad * 1. Redistributions of source code must retain the above copyright 14127412Sgad * notice, this list of conditions and the following disclaimer. 15127412Sgad * 2. Redistributions in binary form must reproduce the above copyright 16127412Sgad * notice, this list of conditions and the following disclaimer in the 17127412Sgad * documentation and/or other materials provided with the distribution. 18127412Sgad * 3. All advertising materials mentioning features or use of this software 19127412Sgad * must display the following acknowledgement: 20127412Sgad * This product includes software developed by the NetBSD 21127412Sgad * Foundation, Inc. and its contributors. 22127412Sgad * 4. Neither the name of The NetBSD Foundation nor the names of its 23127412Sgad * contributors may be used to endorse or promote products derived 24127412Sgad * from this software without specific prior written permission. 25127412Sgad * 26127412Sgad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27127412Sgad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28127412Sgad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29127412Sgad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30127412Sgad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31127412Sgad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32127412Sgad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33127412Sgad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34127412Sgad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35127412Sgad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36127412Sgad * POSSIBILITY OF SUCH DAMAGE. 37127412Sgad */ 38127412Sgad 39127412Sgad#include <sys/cdefs.h> 40127412Sgad__FBSDID("$FreeBSD: head/usr.bin/pkill/pkill.c 143879 2005-03-20 11:47:44Z pjd $"); 41127412Sgad 42127412Sgad#include <sys/types.h> 43127412Sgad#include <sys/param.h> 44127412Sgad#include <sys/sysctl.h> 45127412Sgad#include <sys/proc.h> 46127412Sgad#include <sys/queue.h> 47127412Sgad#include <sys/stat.h> 48143878Spjd#include <sys/time.h> 49127425Sgad#include <sys/user.h> 50127412Sgad 51127412Sgad#include <stdio.h> 52127412Sgad#include <stdlib.h> 53127412Sgad#include <limits.h> 54127425Sgad#include <paths.h> 55127412Sgad#include <string.h> 56127412Sgad#include <unistd.h> 57127412Sgad#include <signal.h> 58127412Sgad#include <regex.h> 59127412Sgad#include <ctype.h> 60127425Sgad#include <fcntl.h> 61127412Sgad#include <kvm.h> 62127412Sgad#include <err.h> 63127412Sgad#include <pwd.h> 64127412Sgad#include <grp.h> 65127412Sgad#include <errno.h> 66132198Stjr#include <locale.h> 67127412Sgad 68127412Sgad#define STATUS_MATCH 0 69127412Sgad#define STATUS_NOMATCH 1 70127412Sgad#define STATUS_BADUSAGE 2 71127412Sgad#define STATUS_ERROR 3 72127412Sgad 73143874Spjd#define MIN_PID 5 74143874Spjd#define MAX_PID 99999 75143874Spjd 76143877Spjd/* Ignore system-processes (if '-S' flag is not specified) and myself. */ 77143877Spjd#define PSKIP(kp) ((kp)->ki_pid == mypid || \ 78143877Spjd (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0)) 79127425Sgad 80127412Sgadenum listtype { 81127412Sgad LT_GENERIC, 82127412Sgad LT_USER, 83127412Sgad LT_GROUP, 84127412Sgad LT_TTY, 85127412Sgad LT_PGRP, 86127412Sgad LT_SID 87127412Sgad}; 88127412Sgad 89127412Sgadstruct list { 90127412Sgad SLIST_ENTRY(list) li_chain; 91127412Sgad long li_number; 92127412Sgad}; 93127412Sgad 94127412SgadSLIST_HEAD(listhead, list); 95127412Sgad 96127425Sgadstruct kinfo_proc *plist; 97127412Sgadchar *selected; 98127430Sgadconst char *delim = "\n"; 99127412Sgadint nproc; 100127412Sgadint pgrep; 101127412Sgadint signum = SIGTERM; 102127412Sgadint newest; 103143878Spjdint oldest; 104127412Sgadint inverse; 105127412Sgadint longfmt; 106127412Sgadint matchargs; 107127412Sgadint fullmatch; 108143877Spjdint kthreads; 109143875Spjdint cflags = REG_EXTENDED; 110127412Sgadkvm_t *kd; 111127412Sgadpid_t mypid; 112127412Sgad 113127412Sgadstruct listhead euidlist = SLIST_HEAD_INITIALIZER(list); 114127412Sgadstruct listhead ruidlist = SLIST_HEAD_INITIALIZER(list); 115127412Sgadstruct listhead rgidlist = SLIST_HEAD_INITIALIZER(list); 116127412Sgadstruct listhead pgrplist = SLIST_HEAD_INITIALIZER(list); 117127412Sgadstruct listhead ppidlist = SLIST_HEAD_INITIALIZER(list); 118127412Sgadstruct listhead tdevlist = SLIST_HEAD_INITIALIZER(list); 119127412Sgadstruct listhead sidlist = SLIST_HEAD_INITIALIZER(list); 120143873Spjdstruct listhead jidlist = SLIST_HEAD_INITIALIZER(list); 121127412Sgad 122127412Sgadint main(int, char **); 123127412Sgadvoid usage(void); 124127425Sgadvoid killact(struct kinfo_proc *); 125127425Sgadvoid grepact(struct kinfo_proc *); 126127412Sgadvoid makelist(struct listhead *, enum listtype, char *); 127143874Spjdint takepid(const char *); 128127412Sgad 129127412Sgadint 130127412Sgadmain(int argc, char **argv) 131127412Sgad{ 132127412Sgad extern char *optarg; 133127412Sgad extern int optind; 134127412Sgad char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q; 135127462Sgad const char *execf, *coref; 136127433Sgad int debug_opt; 137143874Spjd int i, ch, bestidx, rv, criteria, pidfromfile; 138127430Sgad size_t jsz; 139127425Sgad void (*action)(struct kinfo_proc *); 140127425Sgad struct kinfo_proc *kp; 141127412Sgad struct list *li; 142127430Sgad struct timeval best_tval; 143127412Sgad regex_t reg; 144127412Sgad regmatch_t regmatch; 145127412Sgad 146132198Stjr setlocale(LC_ALL, ""); 147132198Stjr 148127412Sgad if (strcmp(getprogname(), "pgrep") == 0) { 149127412Sgad action = grepact; 150127412Sgad pgrep = 1; 151127412Sgad } else { 152127412Sgad action = killact; 153127412Sgad p = argv[1]; 154127412Sgad 155127412Sgad if (argc > 1 && p[0] == '-') { 156127412Sgad p++; 157127412Sgad i = (int)strtol(p, &q, 10); 158127412Sgad if (*q == '\0') { 159127412Sgad signum = i; 160127412Sgad argv++; 161127412Sgad argc--; 162127412Sgad } else { 163127412Sgad if (strncasecmp(p, "sig", 3) == 0) 164127412Sgad p += 3; 165127412Sgad for (i = 1; i < NSIG; i++) 166127412Sgad if (strcasecmp(sys_signame[i], p) == 0) 167127412Sgad break; 168127412Sgad if (i != NSIG) { 169127412Sgad signum = i; 170127412Sgad argv++; 171127412Sgad argc--; 172127412Sgad } 173127412Sgad } 174127412Sgad } 175127412Sgad } 176127412Sgad 177127412Sgad criteria = 0; 178127433Sgad debug_opt = 0; 179143874Spjd pidfromfile = -1; 180127462Sgad execf = coref = _PATH_DEVNULL; 181127412Sgad 182143878Spjd while ((ch = getopt(argc, argv, "DF:G:M:N:P:SU:d:fg:ij:lnos:t:u:vx")) != -1) 183127412Sgad switch (ch) { 184127433Sgad case 'D': 185127433Sgad debug_opt++; 186127433Sgad break; 187143874Spjd case 'F': 188143874Spjd pidfromfile = takepid(optarg); 189143874Spjd criteria = 1; 190143874Spjd break; 191127412Sgad case 'G': 192127412Sgad makelist(&rgidlist, LT_GROUP, optarg); 193127412Sgad criteria = 1; 194127412Sgad break; 195127427Sgad case 'M': 196127427Sgad coref = optarg; 197127427Sgad break; 198127427Sgad case 'N': 199127427Sgad execf = optarg; 200127427Sgad break; 201127412Sgad case 'P': 202127412Sgad makelist(&ppidlist, LT_GENERIC, optarg); 203127412Sgad criteria = 1; 204127412Sgad break; 205143877Spjd case 'S': 206143877Spjd if (!pgrep) 207143877Spjd usage(); 208143877Spjd kthreads = 1; 209143877Spjd break; 210127412Sgad case 'U': 211127412Sgad makelist(&ruidlist, LT_USER, optarg); 212127412Sgad criteria = 1; 213127412Sgad break; 214127412Sgad case 'd': 215127412Sgad if (!pgrep) 216127412Sgad usage(); 217127412Sgad delim = optarg; 218127412Sgad break; 219127412Sgad case 'f': 220127412Sgad matchargs = 1; 221127412Sgad break; 222127412Sgad case 'g': 223127412Sgad makelist(&pgrplist, LT_PGRP, optarg); 224127412Sgad criteria = 1; 225127412Sgad break; 226143875Spjd case 'i': 227143875Spjd cflags |= REG_ICASE; 228143875Spjd break; 229143873Spjd case 'j': 230143873Spjd makelist(&jidlist, LT_GENERIC, optarg); 231143873Spjd criteria = 1; 232143873Spjd break; 233127412Sgad case 'l': 234127412Sgad if (!pgrep) 235127412Sgad usage(); 236127412Sgad longfmt = 1; 237127412Sgad break; 238127412Sgad case 'n': 239127412Sgad newest = 1; 240127412Sgad criteria = 1; 241127412Sgad break; 242143878Spjd case 'o': 243143878Spjd oldest = 1; 244143878Spjd criteria = 1; 245143878Spjd break; 246127412Sgad case 's': 247127412Sgad makelist(&sidlist, LT_SID, optarg); 248127412Sgad criteria = 1; 249127412Sgad break; 250127412Sgad case 't': 251127412Sgad makelist(&tdevlist, LT_TTY, optarg); 252127412Sgad criteria = 1; 253127412Sgad break; 254127412Sgad case 'u': 255127412Sgad makelist(&euidlist, LT_USER, optarg); 256127412Sgad criteria = 1; 257127412Sgad break; 258127412Sgad case 'v': 259127412Sgad inverse = 1; 260127412Sgad break; 261127412Sgad case 'x': 262127412Sgad fullmatch = 1; 263127412Sgad break; 264127412Sgad default: 265127412Sgad usage(); 266127412Sgad /* NOTREACHED */ 267127412Sgad } 268127412Sgad 269127412Sgad argc -= optind; 270127412Sgad argv += optind; 271127412Sgad if (argc != 0) 272127412Sgad criteria = 1; 273127412Sgad if (!criteria) 274127412Sgad usage(); 275143878Spjd if (newest && oldest) 276143878Spjd errx(STATUS_ERROR, "-n and -o are mutually exclusive"); 277127412Sgad 278127412Sgad mypid = getpid(); 279127412Sgad 280127412Sgad /* 281127412Sgad * Retrieve the list of running processes from the kernel. 282127412Sgad */ 283127462Sgad kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf); 284127412Sgad if (kd == NULL) 285127412Sgad errx(STATUS_ERROR, "kvm_openfiles(): %s", buf); 286127412Sgad 287127622Sgad /* 288127622Sgad * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we 289127622Sgad * just want processes and not individual kernel threads. 290127622Sgad */ 291127622Sgad plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc); 292127412Sgad if (plist == NULL) 293127425Sgad errx(STATUS_ERROR, "kvm_getprocs() failed"); 294127412Sgad 295127412Sgad /* 296127412Sgad * Allocate memory which will be used to keep track of the 297127412Sgad * selection. 298127412Sgad */ 299127412Sgad if ((selected = malloc(nproc)) == NULL) 300127412Sgad errx(STATUS_ERROR, "memory allocation failure"); 301127412Sgad memset(selected, 0, nproc); 302127412Sgad 303127412Sgad /* 304127412Sgad * Refine the selection. 305127412Sgad */ 306127412Sgad for (; *argv != NULL; argv++) { 307143875Spjd if ((rv = regcomp(®, *argv, cflags)) != 0) { 308127412Sgad regerror(rv, ®, buf, sizeof(buf)); 309127412Sgad errx(STATUS_BADUSAGE, "bad expression: %s", buf); 310127412Sgad } 311127412Sgad 312127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 313143877Spjd if (PSKIP(kp)) { 314127433Sgad if (debug_opt > 0) 315127434Sgad fprintf(stderr, "* Skipped %5d %3d %s\n", 316127433Sgad kp->ki_pid, kp->ki_uid, kp->ki_comm); 317127412Sgad continue; 318127433Sgad } 319127412Sgad 320143877Spjd if (matchargs && 321143877Spjd (pargv = kvm_getargv(kd, kp, 0)) != NULL) { 322127430Sgad jsz = 0; 323127430Sgad while (jsz < sizeof(buf) && *pargv != NULL) { 324127430Sgad jsz += snprintf(buf + jsz, 325127430Sgad sizeof(buf) - jsz, 326127412Sgad pargv[1] != NULL ? "%s " : "%s", 327127412Sgad pargv[0]); 328127412Sgad pargv++; 329127412Sgad } 330127412Sgad mstr = buf; 331127412Sgad } else 332127425Sgad mstr = kp->ki_comm; 333127412Sgad 334127412Sgad rv = regexec(®, mstr, 1, ®match, 0); 335127412Sgad if (rv == 0) { 336127412Sgad if (fullmatch) { 337127412Sgad if (regmatch.rm_so == 0 && 338127431Sgad regmatch.rm_eo == 339127431Sgad (off_t)strlen(mstr)) 340127412Sgad selected[i] = 1; 341127412Sgad } else 342127412Sgad selected[i] = 1; 343127412Sgad } else if (rv != REG_NOMATCH) { 344127412Sgad regerror(rv, ®, buf, sizeof(buf)); 345127412Sgad errx(STATUS_ERROR, "regexec(): %s", buf); 346127412Sgad } 347127433Sgad if (debug_opt > 1) { 348127433Sgad const char *rv_res = "NoMatch"; 349127433Sgad if (selected[i]) 350127433Sgad rv_res = "Matched"; 351127434Sgad fprintf(stderr, "* %s %5d %3d %s\n", rv_res, 352127433Sgad kp->ki_pid, kp->ki_uid, mstr); 353127433Sgad } 354127412Sgad } 355127412Sgad 356127412Sgad regfree(®); 357127412Sgad } 358127412Sgad 359127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 360143877Spjd if (PSKIP(kp)) 361127412Sgad continue; 362127412Sgad 363143874Spjd if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { 364143874Spjd selected[i] = 0; 365143874Spjd continue; 366143874Spjd } 367143874Spjd 368127412Sgad SLIST_FOREACH(li, &ruidlist, li_chain) 369127425Sgad if (kp->ki_ruid == (uid_t)li->li_number) 370127412Sgad break; 371127412Sgad if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { 372127412Sgad selected[i] = 0; 373127412Sgad continue; 374127412Sgad } 375127429Sgad 376127412Sgad SLIST_FOREACH(li, &rgidlist, li_chain) 377127425Sgad if (kp->ki_rgid == (gid_t)li->li_number) 378127412Sgad break; 379127412Sgad if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { 380127412Sgad selected[i] = 0; 381127412Sgad continue; 382127412Sgad } 383127412Sgad 384127412Sgad SLIST_FOREACH(li, &euidlist, li_chain) 385127425Sgad if (kp->ki_uid == (uid_t)li->li_number) 386127412Sgad break; 387127412Sgad if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { 388127412Sgad selected[i] = 0; 389127412Sgad continue; 390127412Sgad } 391127412Sgad 392127412Sgad SLIST_FOREACH(li, &ppidlist, li_chain) 393127426Sgad if (kp->ki_ppid == (pid_t)li->li_number) 394127412Sgad break; 395127412Sgad if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { 396127412Sgad selected[i] = 0; 397127412Sgad continue; 398127412Sgad } 399127412Sgad 400127412Sgad SLIST_FOREACH(li, &pgrplist, li_chain) 401127426Sgad if (kp->ki_pgid == (pid_t)li->li_number) 402127412Sgad break; 403127412Sgad if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { 404127412Sgad selected[i] = 0; 405127412Sgad continue; 406127412Sgad } 407127412Sgad 408127412Sgad SLIST_FOREACH(li, &tdevlist, li_chain) { 409127412Sgad if (li->li_number == -1 && 410127425Sgad (kp->ki_flag & P_CONTROLT) == 0) 411127412Sgad break; 412130640Sphk if (kp->ki_tdev == (dev_t)li->li_number) 413127412Sgad break; 414127412Sgad } 415127412Sgad if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { 416127412Sgad selected[i] = 0; 417127412Sgad continue; 418127412Sgad } 419127412Sgad 420127412Sgad SLIST_FOREACH(li, &sidlist, li_chain) 421127426Sgad if (kp->ki_sid == (pid_t)li->li_number) 422127412Sgad break; 423127412Sgad if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { 424127412Sgad selected[i] = 0; 425127412Sgad continue; 426127412Sgad } 427127412Sgad 428143873Spjd SLIST_FOREACH(li, &jidlist, li_chain) { 429143873Spjd if (kp->ki_jid > 0) { 430143873Spjd if (li->li_number == 0) 431143873Spjd break; 432143873Spjd if (kp->ki_jid == (int)li->li_number) 433143873Spjd break; 434143873Spjd } 435143873Spjd } 436143873Spjd if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { 437143873Spjd selected[i] = 0; 438143873Spjd continue; 439143873Spjd } 440143873Spjd 441127412Sgad if (argc == 0) 442127412Sgad selected[i] = 1; 443127412Sgad } 444127412Sgad 445143878Spjd if (newest || oldest) { 446127430Sgad best_tval.tv_sec = 0; 447127430Sgad best_tval.tv_usec = 0; 448127412Sgad bestidx = -1; 449127412Sgad 450127412Sgad for (i = 0, kp = plist; i < nproc; i++, kp++) { 451127412Sgad if (!selected[i]) 452127412Sgad continue; 453143878Spjd if (bestidx == -1) { 454143878Spjd /* The first entry of the list which matched. */ 455143878Spjd ; 456143878Spjd } else if (timercmp(&kp->ki_start, &best_tval, >)) { 457143878Spjd /* This entry is newer than previous "best". */ 458143879Spjd if (oldest) /* but we want the oldest */ 459143878Spjd continue; 460143878Spjd } else { 461143878Spjd /* This entry is older than previous "best". */ 462143879Spjd if (newest) /* but we want the newest */ 463143878Spjd continue; 464127412Sgad } 465143878Spjd /* This entry is better than previous "best" entry. */ 466143878Spjd best_tval.tv_sec = kp->ki_start.tv_sec; 467143878Spjd best_tval.tv_usec = kp->ki_start.tv_usec; 468143878Spjd bestidx = i; 469127412Sgad } 470127412Sgad 471127412Sgad memset(selected, 0, nproc); 472127412Sgad if (bestidx != -1) 473127412Sgad selected[bestidx] = 1; 474127412Sgad } 475127412Sgad 476127412Sgad /* 477127412Sgad * Take the appropriate action for each matched process, if any. 478127412Sgad */ 479127412Sgad for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { 480143877Spjd if (PSKIP(kp)) 481127412Sgad continue; 482127412Sgad if (selected[i]) { 483127412Sgad if (inverse) 484127412Sgad continue; 485127412Sgad } else if (!inverse) 486127412Sgad continue; 487127412Sgad rv = 1; 488127412Sgad (*action)(kp); 489127412Sgad } 490127412Sgad 491127412Sgad exit(rv ? STATUS_MATCH : STATUS_NOMATCH); 492127412Sgad} 493127412Sgad 494127412Sgadvoid 495127412Sgadusage(void) 496127412Sgad{ 497127412Sgad const char *ustr; 498127412Sgad 499127412Sgad if (pgrep) 500143878Spjd ustr = "[-Sfilnovx] [-d delim]"; 501127412Sgad else 502143878Spjd ustr = "[-signal] [-finovx]"; 503127412Sgad 504127412Sgad fprintf(stderr, 505143874Spjd "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" 506143873Spjd " [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n" 507143873Spjd " [-t tty] [-u euid] pattern ...\n", getprogname(), 508143873Spjd ustr); 509127412Sgad 510127412Sgad exit(STATUS_ERROR); 511127412Sgad} 512127412Sgad 513127412Sgadvoid 514127425Sgadkillact(struct kinfo_proc *kp) 515127412Sgad{ 516127412Sgad 517127425Sgad if (kill(kp->ki_pid, signum) == -1) 518127425Sgad err(STATUS_ERROR, "signalling pid %d", (int)kp->ki_pid); 519127412Sgad} 520127412Sgad 521127412Sgadvoid 522127425Sgadgrepact(struct kinfo_proc *kp) 523127412Sgad{ 524127412Sgad char **argv; 525127412Sgad 526143877Spjd if (longfmt && matchargs && 527143877Spjd (argv = kvm_getargv(kd, kp, 0)) != NULL) { 528127425Sgad printf("%d ", (int)kp->ki_pid); 529127412Sgad for (; *argv != NULL; argv++) { 530127412Sgad printf("%s", *argv); 531127412Sgad if (argv[1] != NULL) 532127412Sgad putchar(' '); 533127412Sgad } 534127412Sgad } else if (longfmt) 535127425Sgad printf("%d %s", (int)kp->ki_pid, kp->ki_comm); 536127412Sgad else 537127425Sgad printf("%d", (int)kp->ki_pid); 538127412Sgad 539127412Sgad printf("%s", delim); 540127412Sgad} 541127412Sgad 542127412Sgadvoid 543127412Sgadmakelist(struct listhead *head, enum listtype type, char *src) 544127412Sgad{ 545127412Sgad struct list *li; 546127412Sgad struct passwd *pw; 547127412Sgad struct group *gr; 548127412Sgad struct stat st; 549127430Sgad const char *cp; 550127412Sgad char *sp, *p, buf[MAXPATHLEN]; 551127412Sgad int empty; 552127412Sgad 553127412Sgad empty = 1; 554127412Sgad 555127412Sgad while ((sp = strsep(&src, ",")) != NULL) { 556127412Sgad if (*sp == '\0') 557127412Sgad usage(); 558127412Sgad 559127412Sgad if ((li = malloc(sizeof(*li))) == NULL) 560127412Sgad errx(STATUS_ERROR, "memory allocation failure"); 561127412Sgad SLIST_INSERT_HEAD(head, li, li_chain); 562127412Sgad empty = 0; 563127412Sgad 564127412Sgad li->li_number = (uid_t)strtol(sp, &p, 0); 565127412Sgad if (*p == '\0') { 566127412Sgad switch (type) { 567127412Sgad case LT_PGRP: 568127412Sgad if (li->li_number == 0) 569127412Sgad li->li_number = getpgrp(); 570127412Sgad break; 571127412Sgad case LT_SID: 572127412Sgad if (li->li_number == 0) 573127412Sgad li->li_number = getsid(mypid); 574127412Sgad break; 575127412Sgad case LT_TTY: 576127412Sgad usage(); 577127412Sgad default: 578127412Sgad break; 579127412Sgad } 580127412Sgad continue; 581127412Sgad } 582127412Sgad 583127412Sgad switch (type) { 584127412Sgad case LT_USER: 585127412Sgad if ((pw = getpwnam(sp)) == NULL) 586127412Sgad errx(STATUS_BADUSAGE, "unknown user `%s'", 587143079Sdelphij sp); 588127412Sgad li->li_number = pw->pw_uid; 589127412Sgad break; 590127412Sgad case LT_GROUP: 591127412Sgad if ((gr = getgrnam(sp)) == NULL) 592127412Sgad errx(STATUS_BADUSAGE, "unknown group `%s'", 593143079Sdelphij sp); 594127412Sgad li->li_number = gr->gr_gid; 595127412Sgad break; 596127412Sgad case LT_TTY: 597127412Sgad if (strcmp(sp, "-") == 0) { 598127412Sgad li->li_number = -1; 599127412Sgad break; 600127412Sgad } else if (strcmp(sp, "co") == 0) 601127430Sgad cp = "console"; 602127412Sgad else if (strncmp(sp, "tty", 3) == 0) 603127430Sgad cp = sp; 604127412Sgad else 605127430Sgad cp = NULL; 606127412Sgad 607127430Sgad if (cp == NULL) 608127412Sgad snprintf(buf, sizeof(buf), "/dev/tty%s", sp); 609127412Sgad else 610127430Sgad snprintf(buf, sizeof(buf), "/dev/%s", cp); 611127412Sgad 612127412Sgad if (stat(buf, &st) < 0) { 613127412Sgad if (errno == ENOENT) 614127412Sgad errx(STATUS_BADUSAGE, 615127412Sgad "no such tty: `%s'", sp); 616127412Sgad err(STATUS_ERROR, "stat(%s)", sp); 617127412Sgad } 618127412Sgad 619127412Sgad if ((st.st_mode & S_IFCHR) == 0) 620127412Sgad errx(STATUS_BADUSAGE, "not a tty: `%s'", sp); 621127412Sgad 622127412Sgad li->li_number = st.st_rdev; 623127412Sgad break; 624127412Sgad default: 625127412Sgad usage(); 626127412Sgad }; 627127412Sgad } 628127412Sgad 629127412Sgad if (empty) 630127412Sgad usage(); 631127412Sgad} 632143874Spjd 633143874Spjdint 634143874Spjdtakepid(const char *pidfile) 635143874Spjd{ 636143874Spjd char *endp, line[BUFSIZ]; 637143874Spjd FILE *fh; 638143874Spjd long rval; 639143879Spjd 640143874Spjd fh = fopen(pidfile, "r"); 641143874Spjd if (fh == NULL) 642143874Spjd err(STATUS_ERROR, "can't open pid file `%s'", pidfile); 643143879Spjd 644143874Spjd if (fgets(line, sizeof(line), fh) == NULL) { 645143874Spjd if (feof(fh)) { 646143874Spjd (void)fclose(fh); 647143874Spjd errx(STATUS_ERROR, "pid file `%s' is empty", pidfile); 648143874Spjd } 649143874Spjd (void)fclose(fh); 650143874Spjd err(STATUS_ERROR, "can't read from pid file `%s'", pidfile); 651143874Spjd } 652143874Spjd (void)fclose(fh); 653143879Spjd 654143874Spjd rval = strtol(line, &endp, 10); 655143874Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) 656143874Spjd errx(STATUS_ERROR, "invalid pid in file `%s'", pidfile); 657143874Spjd else if (rval < MIN_PID || rval > MAX_PID) 658143874Spjd errx(STATUS_ERROR, "invalid pid in file `%s'", pidfile); 659143874Spjd return (rval); 660143874Spjd} 661