summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/Makefile8
-rw-r--r--usr.bin/pkill/Makefile14
-rw-r--r--usr.bin/pkill/pkill.1198
-rw-r--r--usr.bin/pkill/pkill.c548
4 files changed, 764 insertions, 4 deletions
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index 75034224245..59b116d7e18 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.87 2004/01/05 01:27:22 mickey Exp $
+# $OpenBSD: Makefile,v 1.88 2004/01/06 20:07:49 millert Exp $
.include <bsd.own.mk>
@@ -12,9 +12,9 @@ SUBDIR= apply apropos arch asa asn1_compile at aucat audioctl awk banner \
kdump keynote ktrace lam last lastcomm leave less lex lndir locate \
lock logger login logname look lorder m4 mail make man mesg mg \
midiplay mixerctl mkdep mkstr mktemp modstat msgs nc netstat newsyslog \
- nfsstat nice nohup oldrdist pagesize passwd paste patch pctr pmdb pr \
- printenv printf quota radioctl rdist rdistd readlink renice rev rpcgen \
- rpcinfo rs rsh \
+ nfsstat nice nohup oldrdist pagesize passwd paste patch pctr pkill \
+ pmdb pr printenv printf quota radioctl rdist rdistd readlink renice \
+ rev rpcgen rpcinfo rs rsh \
rup ruptime rusers rwall rwho script sectok sed shar showmount skey \
skeyaudit skeyinfo skeyinit sort spell split ssh su sup systat sudo \
tail talk tcopy tee telnet tftp tic time tip tn3270 top touch tput tr \
diff --git a/usr.bin/pkill/Makefile b/usr.bin/pkill/Makefile
new file mode 100644
index 00000000000..908f9d6196b
--- /dev/null
+++ b/usr.bin/pkill/Makefile
@@ -0,0 +1,14 @@
+# $OpenBSD: Makefile,v 1.1 2004/01/06 20:07:49 millert Exp $
+# $NetBSD: Makefile,v 1.1 2002/03/01 11:21:58 ad Exp $
+
+PROG= pkill
+SRCS= pkill.c
+MAN= pkill.1
+
+LDADD+= -lkvm
+DPADD+= ${LIBKVM}
+
+LINKS+= ${BINDIR}/pkill ${BINDIR}/pgrep
+MLINKS+=pkill.1 pgrep.1
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/pkill/pkill.1 b/usr.bin/pkill/pkill.1
new file mode 100644
index 00000000000..26099915c79
--- /dev/null
+++ b/usr.bin/pkill/pkill.1
@@ -0,0 +1,198 @@
+.\" $OpenBSD: pkill.1,v 1.1 2004/01/06 20:07:49 millert Exp $
+.\" $NetBSD: pkill.1,v 1.8 2003/02/14 15:59:18 grant Exp $
+.\"
+.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Andrew Doran.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd March 1, 2002
+.Dt PKILL 1
+.Os
+.Sh NAME
+.Nm pkill
+.Nd find or signal processes by name
+.Sh SYNOPSIS
+.Nm pgrep
+.Op Fl flnvx
+.Op Fl G Ar gid
+.Op Fl P Ar ppid
+.Op Fl U Ar uid
+.Op Fl d Ar delim
+.Op Fl g Ar pgrp
+.Op Fl s Ar sid
+.Op Fl t Ar tty
+.Op Fl u Ar euid
+.Op Ar pattern Op ...
+.Nm pkill
+.Op Fl signal
+.Op Fl fnvx
+.Op Fl G Ar gid
+.Op Fl P Ar ppid
+.Op Fl U Ar uid
+.Op Fl g Ar pgrp
+.Op Fl s Ar sid
+.Op Fl t Ar tty
+.Op Fl u Ar euid
+.Op Ar pattern Op ...
+.Sh DESCRIPTION
+The
+.Nm pgrep
+command searches the process table on the running system and prints the
+process IDs of all processes that match the criteria given on the command
+line.
+.Pp
+The
+.Nm pkill
+command searches the process table on the running system and signals all
+processes that match the criteria given on the command line.
+.Pp
+The following options are available:
+.Bl -tag -width xxxxxxxx
+.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 U Ar uid
+Restrict matches to processes with a real user ID in the comma-separated
+list
+.Ar uid .
+.It Fl d Ar delim
+Specify a delimiter to be printed between each process ID.
+The default is a newline.
+This option can only be used with the
+.Nm pgrep
+command.
+.It Fl f
+Match against full argument lists.
+The default is to match against process names.
+.It Fl g Ar pgrp
+Restrict matches to processes with a process group ID in the comma-separated
+list
+.Ar pgrp .
+The value zero is taken to mean the process group ID of the running
+.Nm pgrep
+or
+.Nm pkill
+command.
+.It Fl l
+Long output.
+Print the process name in addition to the process ID for each matching
+process.
+If used in conjunction with
+.Fl f ,
+print the process ID and the full argument list for each matching process.
+This option can only be used with the
+.Nm pgrep
+command.
+.It Fl n
+Match only the most recently created process, if any.
+.It Fl s Ar sid
+Restrict matches to processes with a session ID in the comma-separated
+list
+.Ar sid .
+The value zero is taken to mean the session ID of the running
+.Nm pgrep
+or
+.Nm pkill
+command.
+.It Fl t Ar tty
+Restrict matches to processes associated with a terminal in the
+comma-separated list
+.Ar tty .
+Terminal names may be of the form
+.Sq ttyxx
+or the shortened form
+.Sq xx .
+A single dash (`-') matches processes not associated with a terminal.
+.It Fl u Ar euid
+Restrict matches to processes with an effective user ID in the
+comma-separated list
+.Ar euid .
+.It Fl v
+Reverse the sense of the matching; display processes that do not match the
+given criteria.
+.It Fl x
+Require an exact match of the process name, or argument list if
+.Fl f
+is given.
+The default is to match any substring.
+.It Fl signal
+A non-negative decimal number or symbolic signal name specifying the signal
+to be sent instead of the default TERM.
+This option is valid only when given as the first argument to
+.Nm pkill .
+.El
+.Pp
+Note that a running
+.Nm pgrep
+or
+.Nm pkill
+process will never consider itself nor system processes (kernel threads) as
+a potential match.
+.Sh EXIT STATUS
+.Nm pgrep
+and
+.Nm pkill
+return one of the following values upon exit:
+.Bl -tag -width foo
+.It 0
+One or more processes were matched.
+.It 1
+No processes were matched.
+.It 2
+Invalid options were specified on the command line.
+.It 3
+An internal error occurred.
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr ps 1 ,
+.Xr kill 2 ,
+.Xr sigaction 2 ,
+.Xr re_format 7 ,
+.Xr signal 7
+.Sh HISTORY
+.Nm pkill
+and
+.Nm pgrep
+first appeared in
+.Ox 3.5 .
+They are modelled after utilities of the same name that appeared in Sun
+Solaris 7.
+.Sh AUTHORS
+.An Andrew Doran
+.Aq ad@NetBSD.org .
diff --git a/usr.bin/pkill/pkill.c b/usr.bin/pkill/pkill.c
new file mode 100644
index 00000000000..35c1faa65ad
--- /dev/null
+++ b/usr.bin/pkill/pkill.c
@@ -0,0 +1,548 @@
+/* $OpenBSD: pkill.c,v 1.1 2004/01/06 20:07:49 millert Exp $ */
+/* $NetBSD: pkill.c,v 1.5 2002/10/27 11:49:34 kleink Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$OpenBSD: pkill.c,v 1.1 2004/01/06 20:07:49 millert Exp $";
+#endif /* !lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <regex.h>
+#include <ctype.h>
+#include <kvm.h>
+#include <err.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+
+#define STATUS_MATCH 0
+#define STATUS_NOMATCH 1
+#define STATUS_BADUSAGE 2
+#define STATUS_ERROR 3
+
+enum listtype {
+ LT_GENERIC,
+ LT_USER,
+ LT_GROUP,
+ LT_TTY,
+ LT_PGRP,
+ LT_SID
+};
+
+struct list {
+ SLIST_ENTRY(list) li_chain;
+ long li_number;
+};
+
+SLIST_HEAD(listhead, list);
+
+struct kinfo_proc *plist;
+char *selected;
+char *delim = "\n";
+int nproc;
+int pgrep;
+int signum = SIGTERM;
+int newest;
+int inverse;
+int longfmt;
+int matchargs;
+int fullmatch;
+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);
+
+int main(int, char **);
+void usage(void);
+void killact(struct kinfo_proc *);
+void grepact(struct kinfo_proc *);
+void makelist(struct listhead *, enum listtype, char *);
+
+extern char *__progname;
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *cp, *q;
+ int i, j, ch, bestidx, rv, criteria;
+ void (*action)(struct kinfo_proc *);
+ struct kinfo_proc *kp;
+ struct list *li;
+ struct timeval besttime;
+ regex_t reg;
+ regmatch_t regmatch;
+
+ if (strcmp(__progname, "pgrep") == 0) {
+ action = grepact;
+ pgrep = 1;
+ } else {
+ action = killact;
+ cp = argv[1];
+
+ if (argc > 1 && *cp == '-') {
+ cp++;
+ i = (int)strtol(cp, &q, 10);
+ if (*q == '\0') {
+ signum = i;
+ argv++;
+ argc--;
+ } else {
+ if (strncasecmp(cp, "sig", 3) == 0)
+ cp += 3;
+ for (i = 1; i < NSIG; i++)
+ if (strcasecmp(sys_signame[i], cp) == 0)
+ break;
+ if (i != NSIG) {
+ signum = i;
+ argv++;
+ argc--;
+ }
+ }
+ }
+ }
+
+ criteria = 0;
+
+ while ((ch = getopt(argc, argv, "G:P:U:d:fg:lns:t:u:vx")) != -1)
+ switch (ch) {
+ case 'G':
+ makelist(&rgidlist, LT_GROUP, optarg);
+ criteria = 1;
+ break;
+ case 'P':
+ makelist(&ppidlist, LT_GENERIC, optarg);
+ criteria = 1;
+ break;
+ case 'U':
+ makelist(&ruidlist, LT_USER, optarg);
+ criteria = 1;
+ break;
+ case 'd':
+ if (!pgrep)
+ usage();
+ delim = optarg;
+ break;
+ case 'f':
+ matchargs = 1;
+ break;
+ case 'g':
+ makelist(&pgrplist, LT_PGRP, optarg);
+ criteria = 1;
+ break;
+ case 'l':
+ if (!pgrep)
+ usage();
+ longfmt = 1;
+ break;
+ case 'n':
+ newest = 1;
+ criteria = 1;
+ break;
+ case 's':
+ makelist(&sidlist, LT_SID, optarg);
+ criteria = 1;
+ break;
+ case 't':
+ makelist(&tdevlist, LT_TTY, optarg);
+ criteria = 1;
+ break;
+ case 'u':
+ makelist(&euidlist, LT_USER, optarg);
+ criteria = 1;
+ break;
+ case 'v':
+ inverse = 1;
+ break;
+ case 'x':
+ fullmatch = 1;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc != 0)
+ criteria = 1;
+ if (!criteria)
+ usage();
+
+ mypid = getpid();
+
+ /*
+ * Retrieve the list of running processes from the kernel.
+ */
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf);
+ if (kd == NULL)
+ errx(STATUS_ERROR, "kvm_openfiles(): %s", buf);
+
+ plist = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
+ if (plist == NULL)
+ errx(STATUS_ERROR, "kvm_getprocs() failed");
+
+ /*
+ * Allocate memory which will be used to keep track of the
+ * selection.
+ */
+ if ((selected = malloc(nproc)) == NULL)
+ errx(STATUS_ERROR, "memory allocation failure");
+ memset(selected, 0, nproc);
+
+ /*
+ * Refine the selection.
+ */
+ for (; *argv != NULL; argv++) {
+ if ((rv = regcomp(&reg, *argv, REG_EXTENDED)) != 0) {
+ regerror(rv, &reg, buf, sizeof(buf));
+ errx(STATUS_BADUSAGE, "bad expression: %s", buf);
+ }
+
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+ struct proc *p = &kp->kp_proc;
+
+ if ((p->p_flag & P_SYSTEM) != 0 || p->p_pid == mypid)
+ continue;
+
+ if (matchargs) {
+ if ((pargv = kvm_getargv(kd, kp, 0)) == NULL)
+ continue;
+
+ j = 0;
+ while (j < sizeof(buf) && *pargv != NULL) {
+ j += snprintf(buf + j, sizeof(buf) - j,
+ pargv[1] != NULL ? "%s " : "%s",
+ pargv[0]);
+ pargv++;
+ }
+
+ mstr = buf;
+ } else
+ mstr = p->p_comm;
+
+ rv = regexec(&reg, mstr, 1, &regmatch, 0);
+ if (rv == 0) {
+ if (fullmatch) {
+ if (regmatch.rm_so == 0 &&
+ regmatch.rm_eo == strlen(mstr))
+ selected[i] = 1;
+ } else
+ selected[i] = 1;
+ } else if (rv != REG_NOMATCH) {
+ regerror(rv, &reg, buf, sizeof(buf));
+ errx(STATUS_ERROR, "regexec(): %s", buf);
+ }
+ }
+
+ regfree(&reg);
+ }
+
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+ struct eproc *ep = &kp->kp_eproc;
+ struct proc *p = &kp->kp_proc;
+
+ if ((p->p_flag & P_SYSTEM) != 0)
+ continue;
+
+ SLIST_FOREACH(li, &ruidlist, li_chain)
+ if (ep->e_pcred.p_ruid == (uid_t)li->li_number)
+ break;
+ if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &rgidlist, li_chain)
+ if (ep->e_pcred.p_rgid == (gid_t)li->li_number)
+ break;
+ if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &euidlist, li_chain)
+ if (ep->e_ucred.cr_uid == (uid_t)li->li_number)
+ break;
+ if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &ppidlist, li_chain)
+ if (ep->e_ppid == (uid_t)li->li_number)
+ break;
+ if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &pgrplist, li_chain)
+ if (ep->e_pgid == (uid_t)li->li_number)
+ break;
+ if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &tdevlist, li_chain) {
+ if (li->li_number == -1 &&
+ (p->p_flag & P_CONTROLT) == 0)
+ break;
+ if (ep->e_tdev == (uid_t)li->li_number)
+ break;
+ }
+ if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+#if 0 /* XXX - where is session id in kernel? */
+ SLIST_FOREACH(li, &sidlist, li_chain)
+ if (ep->p_sid == (uid_t)li->li_number)
+ break;
+ if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+#endif
+
+ if (argc == 0)
+ selected[i] = 1;
+ }
+
+ if (newest) {
+ timerclear(&besttime);
+ bestidx = -1;
+
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+ struct timeval *tv = &kp->kp_eproc.e_pstats.p_start;
+
+ if (!selected[i])
+ continue;
+
+ if (timercmp(tv, &besttime, >)) {
+ besttime = *tv;
+ bestidx = i;
+ }
+ }
+
+ memset(selected, 0, nproc);
+ if (bestidx != -1)
+ selected[bestidx] = 1;
+ }
+
+ /*
+ * Take the appropriate action for each matched process, if any.
+ */
+ for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) {
+ struct proc *p = &kp->kp_proc;
+
+ if (p->p_pid == mypid)
+ continue;
+ if (selected[i]) {
+ if (inverse)
+ continue;
+ } else if (!inverse)
+ continue;
+
+ if ((p->p_flag & P_SYSTEM) != 0)
+ continue;
+
+ rv = 1;
+ (*action)(kp);
+ }
+
+ exit(rv ? STATUS_MATCH : STATUS_NOMATCH);
+}
+
+void
+usage(void)
+{
+ const char *ustr;
+
+ if (pgrep)
+ ustr = "[-flnvx] [-d delim]";
+ else
+ ustr = "[-signal] [-fnvx]";
+
+ fprintf(stderr, "usage: %s %s [-G gid] [-P ppid] [-U uid] [-g pgrp] "
+ "[-s sid] [-t tty] [-u euid] pattern ...\n", __progname, ustr);
+
+ exit(STATUS_ERROR);
+}
+
+void
+killact(struct kinfo_proc *kp)
+{
+
+ if (kill(kp->kp_proc.p_pid, signum) == -1)
+ err(STATUS_ERROR, "signalling pid %d", (int)kp->kp_proc.p_pid);
+}
+
+void
+grepact(struct kinfo_proc *kp)
+{
+ char **argv;
+
+ if (longfmt && matchargs) {
+ if ((argv = kvm_getargv(kd, kp, 0)) == NULL)
+ return;
+
+ printf("%d ", (int)kp->kp_proc.p_pid);
+ for (; *argv != NULL; argv++) {
+ printf("%s", *argv);
+ if (argv[1] != NULL)
+ putchar(' ');
+ }
+ } else if (longfmt)
+ printf("%d %s", (int)kp->kp_proc.p_pid, kp->kp_proc.p_comm);
+ else
+ printf("%d", (int)kp->kp_proc.p_pid);
+
+ printf("%s", delim);
+}
+
+void
+makelist(struct listhead *head, enum listtype type, char *src)
+{
+ struct list *li;
+ struct passwd *pw;
+ struct group *gr;
+ struct stat st;
+ char *sp, *p, buf[MAXPATHLEN];
+ int empty;
+
+ empty = 1;
+
+ while ((sp = strsep(&src, ",")) != NULL) {
+ if (*sp == '\0')
+ usage();
+
+ if ((li = malloc(sizeof(*li))) == NULL)
+ errx(STATUS_ERROR, "memory allocation failure");
+ SLIST_INSERT_HEAD(head, li, li_chain);
+ empty = 0;
+
+ li->li_number = (uid_t)strtol(sp, &p, 0);
+ if (*p == '\0') {
+ switch (type) {
+ case LT_PGRP:
+ if (li->li_number == 0)
+ li->li_number = getpgrp();
+ break;
+ case LT_SID:
+ if (li->li_number == 0)
+ li->li_number = getsid(mypid);
+ break;
+ case LT_TTY:
+ usage();
+ default:
+ break;
+ }
+ continue;
+ }
+
+ switch (type) {
+ case LT_USER:
+ if ((pw = getpwnam(sp)) == NULL)
+ errx(STATUS_BADUSAGE, "unknown user `%s'",
+ optarg);
+ li->li_number = pw->pw_uid;
+ break;
+ case LT_GROUP:
+ if ((gr = getgrnam(sp)) == NULL)
+ errx(STATUS_BADUSAGE, "unknown group `%s'",
+ optarg);
+ li->li_number = gr->gr_gid;
+ break;
+ case LT_TTY:
+ if (strcmp(sp, "-") == 0) {
+ li->li_number = -1;
+ break;
+ } else if (strcmp(sp, "co") == 0)
+ p = "console";
+ else if (strncmp(sp, "tty", 3) == 0)
+ p = sp;
+ else
+ p = NULL;
+
+ if (p == NULL)
+ snprintf(buf, sizeof(buf), "/dev/tty%s", sp);
+ else
+ snprintf(buf, sizeof(buf), "/dev/%s", p);
+
+ if (stat(buf, &st) < 0) {
+ if (errno == ENOENT)
+ errx(STATUS_BADUSAGE,
+ "no such tty: `%s'", sp);
+ err(STATUS_ERROR, "stat(%s)", sp);
+ }
+
+ if ((st.st_mode & S_IFCHR) == 0)
+ errx(STATUS_BADUSAGE, "not a tty: `%s'", sp);
+
+ li->li_number = st.st_rdev;
+ break;
+ default:
+ usage();
+ };
+ }
+
+ if (empty)
+ usage();
+}