--- bin/ps/keyword.c 2005/02/06 16:37:24 +++ bin/ps/keyword.c 2005/03/11 18:50:31 @@ -95,6 +95,7 @@ {"inblk", "INBLK", NULL, USER, rvar, NULL, 4, ROFF(ru_inblock), LONG, "ld", 0}, {"inblock", "", "inblk", 0, NULL, NULL, 0, 0, CHAR, NULL, 0}, + {"jid", "JID", NULL, 0, kvar, NULL, 6, KOFF(ki_jid), INT, "d", 0}, {"jobc", "JOBC", NULL, 0, kvar, NULL, 4, KOFF(ki_jobc), SHORT, "d", 0}, {"ktrace", "KTRACE", NULL, 0, kvar, NULL, 8, KOFF(ki_traceflag), INT, --- bin/ps/ps.1 2005/02/14 17:37:12 +++ bin/ps/ps.1 2005/03/11 18:50:31 @@ -471,6 +471,8 @@ .It Cm inblk total blocks read (alias .Cm inblock ) +.It Cm jid +jail ID .It Cm jobc job control count .It Cm ktrace --- lib/libkvm/kvm_proc.c 2004/11/20 02:37:11 +++ lib/libkvm/kvm_proc.c 2005/03/11 18:38:09 @@ -54,6 +54,12 @@ #include #define _WANT_UCRED /* make ucred.h give us 'struct ucred' */ #include +#include +#include +#include +#include +#define _WANT_PRISON /* make jail.h give us 'struct prison' */ +#include #include #include #include @@ -105,6 +111,7 @@ struct sigacts sigacts; struct pstats pstats; struct ucred ucred; + struct prison pr; struct thread mtd; /*struct kse mke;*/ struct ksegrp mkg; @@ -159,6 +166,15 @@ bcopy(ucred.cr_groups, kp->ki_groups, NGROUPS * sizeof(gid_t)); kp->ki_uid = ucred.cr_uid; + if (ucred.cr_prison != NULL) { + if (KREAD(kd, (u_long)ucred.cr_prison, &pr)) { + _kvm_err(kd, kd->program, + "can't read prison at %x", + ucred.cr_prison); + return (-1); + } + kp->ki_jid = pr.pr_id; + } } switch(what & ~KERN_PROC_INC_THREAD) { --- sys/kern/kern_proc.c 2005/03/12 14:35:15 +++ sys/kern/kern_proc.c 2005/03/15 01:26:51 @@ -646,8 +646,12 @@ kp->ki_rgid = cred->cr_rgid; kp->ki_svgid = cred->cr_svgid; /* If jailed(cred), emulate the old P_JAILED flag. */ - if (jailed(cred)) + if (jailed(cred)) { kp->ki_flag |= P_JAILED; + /* If inside a jail, use 0 as a jail ID. */ + if (!jailed(curthread->td_ucred)) + kp->ki_jid = cred->cr_prison->pr_id; + } } ps = p->p_sigacts; if (ps) { --- sys/sys/jail.h 2005/02/08 21:35:21 +++ sys/sys/jail.h 2005/03/11 16:26:07 @@ -46,6 +46,7 @@ #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_PRISON); #endif +#endif /* _KERNEL */ /* * This structure describes a prison. It is pointed to by all struct @@ -59,6 +60,7 @@ * required to read * (d) set only during destruction of jail, no mutex needed */ +#if defined(_KERNEL) || defined(_WANT_PRISON) struct prison { LIST_ENTRY(prison) pr_list; /* (a) all prisons */ int pr_id; /* (c) prison id */ @@ -72,7 +74,9 @@ struct task pr_task; /* (d) destroy task */ struct mtx pr_mtx; }; +#endif /* _KERNEL || _WANT_PRISON */ +#ifdef _KERNEL /* * Sysctl-set variables that determine global jail policy * @@ -105,5 +109,5 @@ int prison_ip(struct ucred *cred, int flag, u_int32_t *ip); void prison_remote_ip(struct ucred *cred, int flags, u_int32_t *ip); -#endif /* !_KERNEL */ +#endif /* _KERNEL */ #endif /* !_SYS_JAIL_H_ */ --- sys/sys/user.h 2005/01/07 02:32:16 +++ sys/sys/user.h 2005/03/14 15:12:40 @@ -74,7 +74,7 @@ * end of kinfo_proc. It may need to be overridden on a platform-specific * basis as new fields are added. */ -#define KI_NSPARE 16 +#define KI_NSPARE 15 #ifdef __alpha__ #define KINFO_PROC_SIZE 912 @@ -84,7 +84,7 @@ #endif #ifdef __arm__ #undef KI_NSPARE /* Fewer spare longs on this arch */ -#define KI_NSPARE 15 +#define KI_NSPARE 13 #define KINFO_PROC_SIZE 648 #endif #ifdef __ia64__ @@ -92,10 +92,12 @@ #endif #ifdef __i386__ #undef KI_NSPARE /* Fewer spare longs on this arch */ -#define KI_NSPARE 15 +#define KI_NSPARE 13 #define KINFO_PROC_SIZE 648 #endif #ifdef __powerpc__ +#undef KI_NSPARE /* Fewer spare longs on this arch */ +#define KI_NSPARE 14 #define KINFO_PROC_SIZE 656 #endif #ifdef __sparc64__ @@ -187,6 +189,8 @@ lwpid_t ki_tid; /* XXXKSE thread id */ int ki_numthreads; /* XXXKSE number of threads in total */ void *ki_udata; /* User convenience pointer */ + int ki_jid; /* Process jail ID */ + int ki_spare_int1; /* unused (just here for alignment) */ long ki_spare[KI_NSPARE]; /* spare room for later growth */ }; void fill_kinfo_proc(struct proc *, struct kinfo_proc *); --- usr.bin/pkill/pkill.1 2004/08/16 05:36:37 +++ usr.bin/pkill/pkill.1 2005/03/12 15:51:12 @@ -44,7 +44,8 @@ .Nd find or signal processes by name .Sh SYNOPSIS .Nm pgrep -.Op Fl flnvx +.Op Fl Sfilnvx +.Op Fl F Ar pidfile .Op Fl G Ar gid .Op Fl M Ar core .Op Fl N Ar system @@ -52,19 +53,22 @@ .Op Fl U Ar uid .Op Fl d Ar delim .Op Fl g Ar pgrp +.Op Fl j Ar jid .Op Fl s Ar sid .Op Fl t Ar tty .Op Fl u Ar euid .Ar pattern ... .Nm pkill .Op Fl Ar signal -.Op Fl fnvx +.Op Fl finvx +.Op Fl F Ar pidfile .Op Fl G Ar gid .Op Fl M Ar core .Op Fl N Ar system .Op Fl P Ar ppid .Op Fl U Ar uid .Op Fl g Ar pgrp +.Op Fl j Ar jid .Op Fl s Ar sid .Op Fl t Ar tty .Op Fl u Ar euid @@ -82,21 +86,27 @@ processes that match the criteria given on the command line. .Pp The following options are available: -.Bl -tag -width ".Fl d Ar delim" +.Bl -tag -width ".Fl F Ar pidfile" +.It Fl F Ar pidfile +Restrict matches to process which pid is stored in +.Ar pidfile +file. .It Fl G Ar gid Restrict matches to processes with a real group ID in the comma-separated list .Ar gid . -.It Fl P Ar ppid -Restrict matches to processes with a parent process ID in the -comma-separated list -.Ar ppid . .It Fl M Ar core Extract values associated with the name list from the specified core instead of the currently running system. .It Fl N Ar system Extract the name list from the specified system instead of the default, which is the kernel image the system has booted from. +.It Fl P Ar ppid +Restrict matches to processes with a parent process ID in the +comma-separated list +.Ar ppid . +.It Fl S +Search also in system processes (kernel threads). .It Fl U Ar uid Restrict matches to processes with a real user ID in the comma-separated list @@ -119,6 +129,13 @@ or .Nm pkill command. +.It Fl i +Ignore case distinctions in both the process table and the supplied pattern. +.It Fl j Ar jid +Restrict matches to processes inside jails with a jail ID in the comma-separated +list +.Ar jid . +The value zero is taken to mean any jail ID. .It Fl l Long output. Print the process name in addition to the process ID for each matching @@ -130,7 +147,9 @@ .Nm pgrep command. .It Fl n -Match only the most recently created process, if any. +Select only the newest (most recently started) of the matching processes. +.It Fl o +Select only the oldest (least recently started) of the matching processes. .It Fl s Ar sid Restrict matches to processes with a session ID in the comma-separated list --- usr.bin/pkill/pkill.c 2005/03/03 02:37:14 +++ usr.bin/pkill/pkill.c 2005/03/14 15:02:14 @@ -69,8 +69,12 @@ #define STATUS_BADUSAGE 2 #define STATUS_ERROR 3 -/* Check for system-processes which should always be ignored. */ -#define IS_KERNPROC(kp) ((kp)->ki_flag & P_KTHREAD) +#define MIN_PID 5 +#define MAX_PID 99999 + +/* Ignore system-processes (if '-S' flag is not specified) and myself. */ +#define PSKIP(kp) ((kp)->ki_pid == mypid || \ + (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0)) enum listtype { LT_GENERIC, @@ -95,10 +99,13 @@ 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; @@ -109,12 +116,14 @@ 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 main(int argc, char **argv) @@ -124,12 +133,11 @@ char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q; const char *execf, *coref; int debug_opt; - int i, ch, bestidx, rv, criteria; + int i, ch, rv, criteria, pidfromfile; size_t jsz; void (*action)(struct kinfo_proc *); struct kinfo_proc *kp; struct list *li; - struct timeval best_tval; regex_t reg; regmatch_t regmatch; @@ -166,13 +174,18 @@ criteria = 0; debug_opt = 0; + pidfromfile = -1; execf = coref = _PATH_DEVNULL; - while ((ch = getopt(argc, argv, "DG:M:N:P:U:d:fg:lns:t:u:vx")) != -1) + while ((ch = getopt(argc, argv, "DF:G:M:N:P:SU:d:fg:ij:lnos:t:u:vx")) != -1) switch (ch) { case 'D': debug_opt++; break; + case 'F': + pidfromfile = takepid(optarg); + criteria = 1; + break; case 'G': makelist(&rgidlist, LT_GROUP, optarg); criteria = 1; @@ -187,6 +200,11 @@ makelist(&ppidlist, LT_GENERIC, optarg); criteria = 1; break; + case 'S': + if (!pgrep) + usage(); + kthreads = 1; + break; case 'U': makelist(&ruidlist, LT_USER, optarg); criteria = 1; @@ -203,6 +221,13 @@ makelist(&pgrplist, LT_PGRP, optarg); criteria = 1; break; + case 'i': + cflags |= REG_ICASE; + break; + case 'j': + makelist(&jidlist, LT_GENERIC, optarg); + criteria = 1; + break; case 'l': if (!pgrep) usage(); @@ -212,6 +237,10 @@ newest = 1; criteria = 1; break; + case 'o': + oldest = 1; + criteria = 1; + break; case 's': makelist(&sidlist, LT_SID, optarg); criteria = 1; @@ -241,6 +270,8 @@ criteria = 1; if (!criteria) usage(); + if (newest && oldest) + errx(STATUS_ERROR, "-n and -o are mutually exclusive"); mypid = getpid(); @@ -271,23 +302,21 @@ * Refine the selection. */ for (; *argv != NULL; argv++) { - if ((rv = regcomp(®, *argv, REG_EXTENDED)) != 0) { + if ((rv = regcomp(®, *argv, cflags)) != 0) { regerror(rv, ®, buf, sizeof(buf)); errx(STATUS_BADUSAGE, "bad expression: %s", buf); } for (i = 0, kp = plist; i < nproc; i++, kp++) { - if (IS_KERNPROC(kp) != 0) { + if (PSKIP(kp)) { if (debug_opt > 0) fprintf(stderr, "* Skipped %5d %3d %s\n", kp->ki_pid, kp->ki_uid, kp->ki_comm); continue; } - if (matchargs) { - if ((pargv = kvm_getargv(kd, kp, 0)) == NULL) - continue; - + if (matchargs && + (pargv = kvm_getargv(kd, kp, 0)) != NULL) { jsz = 0; while (jsz < sizeof(buf) && *pargv != NULL) { jsz += snprintf(buf + jsz, @@ -296,7 +325,6 @@ pargv[0]); pargv++; } - mstr = buf; } else mstr = kp->ki_comm; @@ -327,8 +355,13 @@ } for (i = 0, kp = plist; i < nproc; i++, kp++) { - if (IS_KERNPROC(kp) != 0) + if (PSKIP(kp)) + continue; + + if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { + selected[i] = 0; continue; + } SLIST_FOREACH(li, &ruidlist, li_chain) if (kp->ki_ruid == (uid_t)li->li_number) @@ -390,27 +423,46 @@ continue; } + SLIST_FOREACH(li, &jidlist, li_chain) { + if (kp->ki_jid > 0) { + if (li->li_number == 0) + break; + if (kp->ki_jid == (int)li->li_number) + break; + } + } + if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } + if (argc == 0) selected[i] = 1; } - if (newest) { + if (newest || oldest) { + struct timeval best_tval; + int bestidx; + best_tval.tv_sec = 0; best_tval.tv_usec = 0; bestidx = -1; +#define PNEWER(kp) ((kp)->ki_start.tv_sec > best_tval.tv_sec || \ + ((kp)->ki_start.tv_sec == best_tval.tv_sec && \ + (kp)->ki_start.tv_usec > best_tval.tv_usec)) for (i = 0, kp = plist; i < nproc; i++, kp++) { if (!selected[i]) continue; - - if (kp->ki_start.tv_sec > best_tval.tv_sec || - (kp->ki_start.tv_sec == best_tval.tv_sec - && kp->ki_start.tv_usec > best_tval.tv_usec)) { + if (bestidx == -1 || + (newest && PNEWER(kp)) || + (oldest && !PNEWER(kp))) { best_tval.tv_sec = kp->ki_start.tv_sec; best_tval.tv_usec = kp->ki_start.tv_usec; bestidx = i; } } +#undef PNEWER memset(selected, 0, nproc); if (bestidx != -1) @@ -421,17 +473,13 @@ * Take the appropriate action for each matched process, if any. */ for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { - if (kp->ki_pid == mypid) + if (PSKIP(kp)) continue; if (selected[i]) { if (inverse) continue; } else if (!inverse) continue; - - if (IS_KERNPROC(kp) != 0) - continue; - rv = 1; (*action)(kp); } @@ -445,14 +493,15 @@ const char *ustr; if (pgrep) - ustr = "[-flnvx] [-d delim]"; + ustr = "[-Sfilnovx] [-d delim]"; else - ustr = "[-signal] [-fnvx]"; + ustr = "[-signal] [-finovx]"; fprintf(stderr, - "usage: %s %s [-G gid] [-M core] [-N system]\n" - " [-P ppid] [-U uid] [-g pgrp] [-s sid] [-t tty]\n" - " [-u euid] pattern ...\n", getprogname(), ustr); + "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" + " [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n" + " [-t tty] [-u euid] pattern ...\n", getprogname(), + ustr); exit(STATUS_ERROR); } @@ -470,10 +519,8 @@ { char **argv; - if (longfmt && matchargs) { - if ((argv = kvm_getargv(kd, kp, 0)) == NULL) - return; - + if (longfmt && matchargs && + (argv = kvm_getargv(kd, kp, 0)) != NULL) { printf("%d ", (int)kp->ki_pid); for (; *argv != NULL; argv++) { printf("%s", *argv); @@ -578,3 +625,33 @@ if (empty) usage(); } + +int +takepid(const char *pidfile) +{ + char *endp, line[BUFSIZ]; + FILE *fh; + long rval; + + fh = fopen(pidfile, "r"); + if (fh == NULL) + err(STATUS_ERROR, "can't open pid file `%s'", pidfile); + + if (fgets(line, sizeof(line), fh) == NULL) { + if (feof(fh)) { + (void)fclose(fh); + errx(STATUS_ERROR, "pid file `%s' is empty", pidfile); + } + (void)fclose(fh); + err(STATUS_ERROR, "can't read from pid file `%s'", pidfile); + } + (void)fclose(fh); + + errno = 0; + rval = strtol(line, &endp, 10); + if (*endp != '\0' && !isspace((unsigned char)*endp)) + errx(STATUS_ERROR, "invalid pid in file `%s'", pidfile); + else if (rval < MIN_PID || rval > MAX_PID) + errx(STATUS_ERROR, "invalid pid in file `%s'", pidfile); + return (rval); +}