Index: pkill.1 =================================================================== RCS file: /usr/repo/src/usr.bin/pkill/pkill.1,v retrieving revision 1.18 diff -u -p -r1.18 pkill.1 --- pkill.1 25 Aug 2005 20:10:47 -0000 1.18 +++ pkill.1 7 Nov 2005 16:02:19 -0000 @@ -60,7 +60,7 @@ .Ar pattern ... .Nm pkill .Op Fl Ar signal -.Op Fl Lfinovx +.Op Fl ILfinovx .Op Fl F Ar pidfile .Op Fl G Ar gid .Op Fl M Ar core @@ -95,6 +95,8 @@ file. Restrict matches to processes with a real group ID in the comma-separated list .Ar gid . +.It Fl I +Request confirmation before attempting to kill each process. .It Fl L The .Ar pidfile Index: pkill.c =================================================================== RCS file: /usr/repo/src/usr.bin/pkill/pkill.c,v retrieving revision 1.28 diff -u -p -r1.28 pkill.c --- pkill.c 25 Aug 2005 20:10:47 -0000 1.28 +++ pkill.c 7 Nov 2005 17:14:45 -0000 @@ -2,6 +2,7 @@ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. + * Copyright (c) 2005 Pawel Jakub Dawidek * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -93,50 +94,48 @@ struct list { SLIST_HEAD(listhead, list); -struct kinfo_proc *plist; -char *selected; -const char *delim = "\n"; -int nproc; -int pgrep; -int signum = SIGTERM; -int newest; -int oldest; -int inverse; -int longfmt; -int matchargs; -int fullmatch; -int kthreads; -int cflags = REG_EXTENDED; -kvm_t *kd; -pid_t mypid; - -struct listhead euidlist = SLIST_HEAD_INITIALIZER(list); -struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list); -struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list); -struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list); -struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list); -struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list); -struct listhead sidlist = SLIST_HEAD_INITIALIZER(list); -struct listhead jidlist = SLIST_HEAD_INITIALIZER(list); - -int main(int, char **); -void usage(void); -void killact(struct kinfo_proc *); -void grepact(struct kinfo_proc *); -void makelist(struct listhead *, enum listtype, char *); -int takepid(const char *, int); +static struct kinfo_proc *plist; +static char *selected; +static const char *delim = "\n"; +static int nproc; +static int pgrep; +static int signum = SIGTERM; +static int newest; +static int oldest; +static int interactive; +static int inverse; +static int longfmt; +static int matchargs; +static int fullmatch; +static int kthreads; +static int cflags = REG_EXTENDED; +static kvm_t *kd; +static pid_t mypid; + +static struct listhead euidlist = SLIST_HEAD_INITIALIZER(list); +static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(list); +static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(list); +static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(list); +static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(list); +static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(list); +static struct listhead sidlist = SLIST_HEAD_INITIALIZER(list); +static struct listhead jidlist = SLIST_HEAD_INITIALIZER(list); + +static void usage(void); +static int killact(const struct kinfo_proc *); +static int grepact(const struct kinfo_proc *); +static void makelist(struct listhead *, enum listtype, char *); +static int takepid(const char *, int); int main(int argc, char **argv) { - extern char *optarg; - extern int optind; char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile; const char *execf, *coref; int debug_opt; int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock; size_t jsz; - void (*action)(struct kinfo_proc *); + int (*action)(const struct kinfo_proc *); struct kinfo_proc *kp; struct list *li; struct timeval best_tval; @@ -180,7 +179,7 @@ main(int argc, char **argv) pidfilelock = 0; execf = coref = _PATH_DEVNULL; - while ((ch = getopt(argc, argv, "DF:G:LM:N:P:SU:d:fg:ij:lnos:t:u:vx")) != -1) + while ((ch = getopt(argc, argv, "DF:G:LM:N:P:SU:d:fg:iIj:lnos:t:u:vx")) != -1) switch (ch) { case 'D': debug_opt++; @@ -193,6 +192,11 @@ main(int argc, char **argv) makelist(&rgidlist, LT_GROUP, optarg); criteria = 1; break; + case 'I': + if (pgrep) + usage(); + interactive = 1; + break; case 'L': pidfilelock = 1; break; @@ -495,14 +499,13 @@ main(int argc, char **argv) continue; } else if (!inverse) continue; - rv = 1; - (*action)(kp); + rv |= (*action)(kp); } exit(rv ? STATUS_MATCH : STATUS_NOMATCH); } -void +static void usage(void) { const char *ustr; @@ -510,7 +513,7 @@ usage(void) if (pgrep) ustr = "[-LSfilnovx] [-d delim]"; else - ustr = "[-signal] [-Lfinovx]"; + ustr = "[-signal] [-ILfinovx]"; fprintf(stderr, "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" @@ -518,23 +521,15 @@ usage(void) " [-t tty] [-u euid] pattern ...\n", getprogname(), ustr); - exit(STATUS_ERROR); -} - -void -killact(struct kinfo_proc *kp) -{ - - if (kill(kp->ki_pid, signum) == -1) - err(STATUS_ERROR, "signalling pid %d", (int)kp->ki_pid); + exit(STATUS_BADUSAGE); } -void -grepact(struct kinfo_proc *kp) +static void +show_process(const struct kinfo_proc *kp) { char **argv; - if (longfmt && matchargs && + if ((longfmt || !pgrep) && matchargs && (argv = kvm_getargv(kd, kp, 0)) != NULL) { printf("%d ", (int)kp->ki_pid); for (; *argv != NULL; argv++) { @@ -542,23 +537,67 @@ grepact(struct kinfo_proc *kp) if (argv[1] != NULL) putchar(' '); } - } else if (longfmt) + } else if (longfmt || !pgrep) printf("%d %s", (int)kp->ki_pid, kp->ki_comm); else printf("%d", (int)kp->ki_pid); +} + +static int +killact(const struct kinfo_proc *kp) +{ + int ch, first; + + if (interactive) { + /* + * Be careful, ask before killing. + */ + printf("kill "); + show_process(kp); + printf("? "); + fflush(stdout); + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (first != 'y' && first != 'Y') + return (1); + } + if (kill(kp->ki_pid, signum) == -1) { + /* + * Check for ESRCH, which indicates that the process + * disappeared between us matching it and us + * signalling it; don't issue a warning about it. + */ + if (errno != ESRCH) + warn("signalling pid %d", (int)kp->ki_pid); + /* + * Return 0 to indicate that the process should not be + * considered a match, since we didn't actually get to + * signal it. + */ + return (0); + } + return (1); +} +static int +grepact(const struct kinfo_proc *kp) +{ + + show_process(kp); printf("%s", delim); + return (1); } -void +static void makelist(struct listhead *head, enum listtype type, char *src) { struct list *li; struct passwd *pw; struct group *gr; struct stat st; - const char *cp; - char *sp, *p, buf[MAXPATHLEN]; + const char *cp, *prefix = _PATH_DEV; + char *sp, *ep, buf[MAXPATHLEN]; int empty; empty = 1; @@ -572,8 +611,8 @@ makelist(struct listhead *head, enum lis SLIST_INSERT_HEAD(head, li, li_chain); empty = 0; - li->li_number = (uid_t)strtol(sp, &p, 0); - if (*p == '\0') { + li->li_number = (uid_t)strtol(sp, &ep, 0); + if (*ep == '\0') { switch (type) { case LT_PGRP: if (li->li_number == 0) @@ -585,6 +624,7 @@ makelist(struct listhead *head, enum lis break; case LT_TTY: usage(); + /* NOTREACHED */ default: break; } @@ -608,19 +648,17 @@ makelist(struct listhead *head, enum lis if (strcmp(sp, "-") == 0) { li->li_number = -1; break; - } else if (strcmp(sp, "co") == 0) + } else if (strcmp(sp, "co") == 0) { cp = "console"; - else if (strncmp(sp, "tty", 3) == 0) + } else { cp = sp; - else - cp = NULL; + if (strncmp(sp, "tty", 3) != 0) + prefix = _PATH_TTY; + } - if (cp == NULL) - snprintf(buf, sizeof(buf), "/dev/tty%s", sp); - else - snprintf(buf, sizeof(buf), "/dev/%s", cp); + snprintf(buf, sizeof(buf), "%s%s", prefix, cp); - if (stat(buf, &st) < 0) { + if (stat(buf, &st) == -1) { if (errno == ENOENT) errx(STATUS_BADUSAGE, "no such tty: `%s'", sp); @@ -634,14 +672,14 @@ makelist(struct listhead *head, enum lis break; default: usage(); - }; + } } if (empty) usage(); } -int +static int takepid(const char *pidfile, int pidfilelock) { char *endp, line[BUFSIZ];