* pidof/killall5 - make omit pid list a dynamic one.
authorDr. Werner Fink <werner@suse.de>
Tue, 23 Feb 2010 16:51:18 +0000 (16:51 +0000)
committerDr. Werner Fink <werner@suse.de>
Tue, 23 Feb 2010 16:51:18 +0000 (16:51 +0000)
  * pidof - provide '-n' to skip stat(2) syscall on network based FS.

git-svn-id: svn://svn.sv.gnu.org/sysvinit/sysvinit/trunk@38 456724a4-4300-0410-8514-c89748c515a2

doc/Changelog
man/killall5.8
man/pidof.8
src/killall5.c

index e800bea1d9d35f3c8812cb73b371b5aadd22674d..8ec2f7aa07536e67f534e88cc1ad0aa1ff047917 100644 (file)
@@ -11,6 +11,8 @@
   * Flush block devices on halt/reboot if not done by the kernel.
   * Set SHELL to /bin/sh in the environmant of shutdown.
   * Retry to write out shutdown messages if interrupted.
+  * pidof/killall5 - make omit pid list a dynamic one.
+  * pidof - provide '-n' to skip stat(2) syscall on network based FS.
 
 sysvinit (2.88dsf) UNRELEASED; urgency=low
 
index 5a3009f287fc816f01deb03d5c90baf0ec2efc7b..24b819fa8fe982c08faf0dad2b5e6400f24eca87 100644 (file)
@@ -22,9 +22,9 @@ killall5 -- send a signal to all processes.
 .B killall5
 .RB -signalnumber
 .RB [ \-o
-.IR omitpid ]
+.IR omitpid[,omitpid..]]
 .RB [ \-o
-.IR omitpid.. ]
+.IR omitpid[,omitpid..].. ]
 .SH DESCRIPTION
 .B killall5
 is the SystemV killall command. It sends a signal to all processes except
index 0385514b271b2002454b14328084314758ac76e4..28db5c170c558540aacbef9c8029e52f3d8f1dbb 100644 (file)
@@ -22,11 +22,12 @@ pidof -- find the process ID of a running program.
 .B pidof
 .RB [ \-s ]
 .RB [ \-c ]
+.RB [ \-n ]
 .RB [ \-x ]
 .RB [ \-o
-.IR omitpid ]
+.IR omitpid[,omitpid..] ]
 .RB [ \-o
-.IR omitpid.. ]
+.IR omitpid[,omitpid..].. ]
 .B program
 .RB [ program.. ]
 .SH DESCRIPTION
@@ -40,13 +41,22 @@ a
 .B start-stop-daemon
 (8) program that should be used instead.
 .SH OPTIONS
-.IP -s
+.IP \-s
 Single shot - this instructs the program to only return one \fIpid\fP.
-.IP -c
+.IP \-c
 Only return process ids that are running with the same root directory.
 This option is ignored for non-root users, as they will be unable to check
 the current root directory of processes they do not own.
-.IP -x
+.IP \-n
+Avoid
+.BR stat (2)
+system function call on all binaries which are located on network
+based file systems like
+.BR NFS .
+Instead of using this option the the variable
+.B PIDOF_NETFS
+may be set and exported.
+.IP \-x
 Scripts too - this causes the program to also return process id's of
 shells running the named scripts.
 .IP "-o \fIomitpid\fP"
index 1f9dbb0c71519b1b22fb6dcb8236bb8e7a73cfe6..3a3dec31aec56403e010b8e07a9749482e9dff0f 100644 (file)
  *             - syslog() only if not a connected to controlling terminal
  *             - swapped out programs pids are caught now
  *
+ *             Werner Fink
+ *             - make omit dynamic
+ *             - provide '-n' to skip stat(2) syscall on network based FS
+ *
  *             This file is part of the sysvinit suite,
  *             Copyright (C) 1991-2004 Miquel van Smoorenburg.
  *
  *             along with this program; if not, write to the Free Software
  *             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
-#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
+#include <dirent.h>
 #include <errno.h>
+#include <getopt.h>
+#include <mntent.h>
+#include <stdarg.h>
+#include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
 #include <signal.h>
-#include <dirent.h>
+#include <string.h>
 #include <syslog.h>
-#include <getopt.h>
-#include <stdarg.h>
 #include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
 char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl";
 
 #define STATNAMELEN    15
+#define DO_NETFS 2
 #define DO_STAT 1
 #define NO_STAT 0
 
@@ -67,8 +74,9 @@ typedef struct proc {
        ino_t ino;              /* Inode number                   */
        dev_t dev;              /* Device it is on                */
        pid_t pid;              /* Process ID.                    */
-       int sid;                /* Session ID.                    */
-       int kernel;             /* Kernel thread or zombie.       */
+       pid_t sid;              /* Session ID.                    */
+       char kernel;            /* Kernel thread or zombie.       */
+       char nfs;               /* Name found on network FS.      */
        struct proc *next;      /* Pointer to next struct.        */
 } PROC;
 
@@ -85,9 +93,38 @@ typedef struct {
        PIDQ            *next;
 } PIDQ_HEAD;
 
+typedef struct _s_omit {
+       struct _s_omit *next;
+       struct _s_omit *prev;
+       pid_t pid;
+} OMIT;
+
+typedef struct _s_shadow
+{
+       struct _s_shadow *next;
+       struct _s_shadow *prev;
+       size_t nlen;
+       char * name;
+} SHADOW;
+
+typedef struct _s_nfs
+{
+       struct _s_nfs *next;    /* Pointer to next struct. */
+       struct _s_nfs *prev;    /* Pointer to previous st. */
+       SHADOW *shadow;         /* Pointer to shadows      */
+       char * name;
+       size_t nlen;
+} NFS;
+
 /* List of processes. */
 PROC *plist;
 
+/* List of processes to omit. */
+OMIT *omit;
+
+/* List of NFS mountes partitions. */
+NFS *nlist;
+
 /* Did we stop all processes ? */
 int sent_sigstop;
 
@@ -99,10 +136,23 @@ __attribute__ ((format (printf, 2, 3)))
 #endif
 void nsyslog(int pri, char *fmt, ...);
 
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+# ifndef  inline
+#  define inline       __inline__
+# endif
+# ifndef  restrict
+#  define restrict     __restrict__
+# endif
+#endif
+#define alignof(type)  ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
+
 /*
  *     Malloc space, barf if out of memory.
  */
-void *xmalloc(int bytes)
+#ifdef __GNUC__
+static void *xmalloc(size_t) __attribute__ ((__malloc__));
+#endif
+static void *xmalloc(size_t bytes)
 {
        void *p;
 
@@ -114,6 +164,18 @@ void *xmalloc(int bytes)
        return p;
 }
 
+#ifdef __GNUC__
+static inline void xmemalign(void **, size_t, size_t) __attribute__ ((__nonnull__ (1)));
+#endif
+static inline void xmemalign(void **memptr, size_t alignment, size_t size)
+{
+       if ((posix_memalign(memptr, alignment, size)) < 0) {
+               if (sent_sigstop) kill(-1, SIGCONT);
+               nsyslog(LOG_ERR, "out of memory");
+               exit(1);
+       }
+}
+
 /*
  *     See if the proc filesystem is there. Mount if needed.
  */
@@ -164,6 +226,212 @@ int mount_proc(void)
        return did_mount;
 }
 
+static inline int isnetfs(const char * type)
+{
+       static const char* netfs[] = {"nfs", "nfs4", "smbfs", "cifs", "afs", "ncpfs", (char*)0};
+       int n;
+       for (n = 0; netfs[n]; n++) {
+               if (!strcasecmp(netfs[n], type))
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ *     Remember all NFS typed partitions.
+ */
+void init_nfs(void)
+{
+        struct stat st;
+        struct mntent * ent;
+       FILE * mnt;
+       nlist = (NFS*)0;
+       if (stat("/proc/version", &st) < 0)
+               return;
+       if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
+               return;
+       while ((ent = getmntent(mnt))) {
+               if (isnetfs(ent->mnt_type)) {
+                       size_t nlen = strlen(ent->mnt_dir);
+                       NFS *restrict p;
+                       xmemalign((void*)&p, sizeof(void*), alignof(NFS)+(nlen+1));
+                       p->name = ((char*)p)+alignof(NFS);
+                       p->nlen = nlen;
+                       p->shadow = (SHADOW*)0;
+                       strcpy(p->name, ent->mnt_dir);
+                       if (nlist)
+                               nlist->prev = p;
+                       p->next = nlist;
+                       p->prev = (NFS*)0;
+                       nlist = p;
+               }
+       }
+       endmntent(mnt);
+       if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
+               return;
+       while ((ent = getmntent(mnt))) {
+               NFS *p;
+               for (p = nlist; p; p = p->next) {
+                       SHADOW * restrict s;
+                       size_t nlen;
+                       if (strcmp(ent->mnt_dir, p->name) == 0)
+                               continue;
+                       if (strncmp(ent->mnt_dir, p->name, p->nlen) != 0)
+                               continue;
+                       nlen = strlen(ent->mnt_dir);
+                       xmemalign((void*)&s, sizeof(void*), alignof(SHADOW)+(nlen+1));
+                       s->name = ((char*)s)+alignof(SHADOW);
+                       s->nlen = nlen;
+                       strcpy(s->name, ent->mnt_dir);
+                       if (p->shadow)
+                           p->shadow->prev = s;
+                       s->next = p->shadow;
+                       s->prev = (SHADOW*)0;
+                       p->shadow = s;
+               }
+       }
+       endmntent(mnt);
+}
+
+static void clear_shadow(SHADOW *restrict shadow)
+{
+       SHADOW *s, *n, *l;
+       n = shadow;
+       l = (SHADOW*)0;
+       for (s = shadow; n; s = n) {
+               l = s->prev;
+               n = s->next;
+               if (s == shadow) {
+                       if (n) n->prev = (SHADOW*)0;
+                       shadow = n;
+               } else if (l) {
+                       if (n) n->prev = l;
+                       l->next = n;
+               }
+               free(s);
+       }
+}
+
+static void clear_mnt(void)
+{
+       NFS *p, *n, *l;
+       n = nlist;
+       l = (NFS*)0;
+       for (p = nlist; n; p = n) {
+               l = p->prev;
+               n = p->next;
+               if (p == nlist) {
+                       if (n) n->prev = (NFS*)0;
+                       nlist = n;
+               } else if (l) {
+                       if (n) n->prev = l;
+                       l->next = n;
+               }
+               if (p->shadow)
+                       clear_shadow(p->shadow);
+               free(p);
+       }
+}
+
+/*
+ *     Check if path is ia shadow off a NFS partition.
+ */
+static int shadow(SHADOW *restrict this, const char *restrict name, const size_t nlen)
+{
+       SHADOW *s;
+       if (!this)
+               goto out;
+       for (s = this; s; s = s->next) {
+               if (nlen < s->nlen)
+                       continue;
+               if (name[s->nlen] != '\0' && name[s->nlen] != '/')
+                       continue;
+               if (strncmp(name, s->name, s->nlen) == 0)
+                       return 1;
+       }
+out:
+       return 0;
+}
+
+/*
+ *     Check path is located on a network based partition.
+ */
+int check4nfs(const char * path, char * real)
+{
+       char buf[PATH_MAX+1];
+       const char *curr;
+       int deep = MAXSYMLINKS;
+       if (!nlist) return 0;
+       curr = path;
+       do {
+               const char *prev;
+               int len;
+               if ((prev = strdupa(curr)) == NULL) {
+                       nsyslog(LOG_ERR, "strdupa(): %s\n", strerror(errno));
+                       return 0;
+               }
+               errno = 0;
+               if ((len = readlink(curr, buf, PATH_MAX)) < 0)
+                       break;
+               buf[len] = '\0';
+               if (buf[0] != '/') {
+                       const char *slash;
+                       if ((slash = strrchr(prev, '/'))) {
+                               size_t off = slash - prev + 1;
+                               if (off + len > PATH_MAX)
+                                       len = PATH_MAX - off;
+                               memmove(&buf[off], &buf[0], len + 1);
+                               memcpy(&buf[0], prev, off);
+                       }
+               }
+               curr = &buf[0];
+               if (deep-- <= 0) return 0;
+       } while (1);
+       if (real) strcpy(real, curr);
+       if (errno == EINVAL) {
+               const size_t nlen = strlen(curr);
+               NFS *p;
+               for (p = nlist; p; p = p->next) {
+                       if (nlen < p->nlen)
+                               continue;
+                       if (curr[p->nlen] != '\0' && curr[p->nlen] != '/')
+                               continue;
+                       if (!strncmp(curr, p->name, p->nlen)) {
+                               if (shadow(p->shadow, curr, nlen))
+                                       continue;
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
 int readarg(FILE *fp, char *buf, int sz)
 {
        int             c = 0, f = 0;
@@ -208,6 +476,7 @@ int readproc(int do_stat)
                n = p->next;
                if (p->argv0) free(p->argv0);
                if (p->argv1) free(p->argv1);
+               if (p->statname) free(p->statname);
                free(p);
        }
        plist = NULL;
@@ -242,6 +511,9 @@ int readproc(int do_stat)
                                        nsyslog(LOG_ERR,
                                        "can't get program name from /proc/%s\n",
                                                path);
+                                       if (p->argv0) free(p->argv0);
+                                       if (p->argv1) free(p->argv1);
+                                       if (p->statname) free(p->statname);
                                        free(p);
                                        continue;
                                }
@@ -265,6 +537,9 @@ int readproc(int do_stat)
                                p->sid = 0;
                                nsyslog(LOG_ERR, "can't read sid from %s\n",
                                        path);
+                               if (p->argv0) free(p->argv0);
+                               if (p->argv1) free(p->argv1);
+                               if (p->statname) free(p->statname);
                                free(p);
                                continue;
                        }
@@ -273,6 +548,9 @@ int readproc(int do_stat)
                        fclose(fp);
                } else {
                        /* Process disappeared.. */
+                       if (p->argv0) free(p->argv0);
+                       if (p->argv1) free(p->argv1);
+                       if (p->statname) free(p->statname);
                        free(p);
                        continue;
                }
@@ -317,15 +595,29 @@ int readproc(int do_stat)
 
                } else {
                        /* Process disappeared.. */
+                       if (p->argv0) free(p->argv0);
+                       if (p->argv1) free(p->argv1);
+                       if (p->statname) free(p->statname);
                        free(p);
                        continue;
                }
 
                /* Try to stat the executable. */
                snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name);
-               if (do_stat && stat(path, &st) == 0) {
+
+               p->nfs = 0;
+
+               switch (do_stat) {
+               case DO_NETFS:
+                       if ((p->nfs = check4nfs(path, buf)))
+                               break;
+               case DO_STAT:
+                       if (stat(path, &st) != 0)
+                               break;
                        p->dev = st.st_dev;
                        p->ino = st.st_ino;
+               default:
+                       break;
                }
 
                /* Link it into the list. */
@@ -391,13 +683,29 @@ PIDQ_HEAD *pidof(char *prog)
        PIDQ_HEAD       *q;
        struct stat     st;
        char            *s;
+       int             nfs = 0;
        int             dostat = 0;
        int             foundone = 0;
        int             ok = 0;
+       char            real[PATH_MAX+1];
 
        if (! prog)
                return NULL;
 
+       /* Try to stat the executable. */
+       if (prog[0] == '/') {
+               memset(&real[0], 0, sizeof(real));
+
+               if (check4nfs(prog, real))
+                       nfs++;
+
+               if (real[0] != '\0')
+                       prog = &real[0];        /* Binary located on network FS. */
+
+               if ((nfs == 0) && (stat(prog, &st) == 0))
+                       dostat++;               /* Binary located on a local FS. */
+       }
+
        /* Get basename of program. */
        if ((s = strrchr(prog, '/')) == NULL)
                s = prog;
@@ -410,13 +718,11 @@ PIDQ_HEAD *pidof(char *prog)
        q = (PIDQ_HEAD *)xmalloc(sizeof(PIDQ_HEAD));
        q = init_pid_q(q);
 
-       /* Try to stat the executable. */
-       if (prog[0] == '/' && stat(prog, &st) == 0)
-               dostat++;
-
        /* First try to find a match based on dev/ino pair. */
-       if (dostat) {
+       if (dostat && !nfs) {
                for (p = plist; p; p = p->next) {
+                       if (p->nfs)
+                               continue;
                        if (p->dev == st.st_dev && p->ino == st.st_ino) {
                                add_pid_to_q(q, p);
                                foundone++;
@@ -424,6 +730,25 @@ PIDQ_HEAD *pidof(char *prog)
                }
        }
 
+       /* Second try to find a match based on full path name on
+        * network FS located binaries */
+       if (!foundone && nfs) {
+               for (p = plist; p; p = p->next) {
+                       char exe [PATH_MAX+1];
+                       char path[PATH_MAX+1];
+                       int len;
+
+                       snprintf(exe, sizeof(exe), "/proc/%d/exe", p->pid);
+                       if ((len = readlink(exe, path, PATH_MAX)) < 0)
+                                   continue;
+                       path[len] = '\0';
+                       if (strcmp(prog, path) != 0)
+                               continue;
+                       add_pid_to_q(q, p);
+                       foundone++;
+               }
+       }
+
        /* If we didn't find a match based on dev/ino, try the name. */
        if (!foundone) for (p = plist; p; p = p->next) {
                ok = 0;
@@ -469,10 +794,22 @@ PIDQ_HEAD *pidof(char *prog)
                     strchr(p->argv0, ' '))) {
                        ok |= (strcmp(p->statname, s) == 0);
                }
+
+               /*
+                *      if we have a `-' as the first character, process
+                *      probably used as a login shell
+                */
+               if (strlen(s) <= STATNAMELEN &&
+                   p->argv1 == NULL &&
+                   (p->argv0 != NULL &&
+                    p->argv0[0] == '-')) {
+                       ok |= (strcmp(p->statname, s) == 0);
+               }
+
                if (ok) add_pid_to_q(q, p);
        }
 
-        return q;
+       return q;
 }
 
 /* Give usage message and exit. */
@@ -506,8 +843,7 @@ void nsyslog(int pri, char *fmt, ...)
 
 #define PIDOF_SINGLE   0x01
 #define PIDOF_OMIT     0x02
-
-#define PIDOF_OMITSZ   5
+#define PIDOF_NETFS    0x04
 
 /*
  *     Pidof functionality.
@@ -516,19 +852,22 @@ int main_pidof(int argc, char **argv)
 {
        PIDQ_HEAD       *q;
        PROC            *p;
-       pid_t           opid[PIDOF_OMITSZ], spid;
+       char            *token, *here;
        int             f;
        int             first = 1;
-       int             i, oind, opt, flags = 0;
+       int             opt, flags = 0;
        int             chroot_check = 0;
        struct stat     st;
        char            tmp[512];
 
-       for (oind = PIDOF_OMITSZ-1; oind > 0; oind--)
-               opid[oind] = 0;
+       omit = (OMIT*)0;
+       nlist = (NFS*)0;
        opterr = 0;
 
-       while ((opt = getopt(argc,argv,"hco:sx")) != EOF) switch (opt) {
+       if ((token = getenv("PIDOF_NETFS")) && (strcmp(token,"no") != 0))
+               flags |= PIDOF_NETFS;
+
+       while ((opt = getopt(argc,argv,"hco:sxn")) != EOF) switch (opt) {
                case '?':
                        nsyslog(LOG_ERR,"invalid options on command line!\n");
                        closelog();
@@ -537,22 +876,28 @@ int main_pidof(int argc, char **argv)
                        if (geteuid() == 0) chroot_check = 1;
                        break;
                case 'o':
-                       if (oind >= PIDOF_OMITSZ -1) {
-                               nsyslog(LOG_ERR,"omit pid buffer size %d "
-                                       "exceeded!\n", PIDOF_OMITSZ);
-                               closelog();
-                               exit(1);
-                       }
-                       if (strcmp("%PPID",optarg) == 0)
-                               opid[oind] = getppid();
-                       else if ((opid[oind] = atoi(optarg)) < 1) {
-                               nsyslog(LOG_ERR,
-                                       "illegal omit pid value (%s)!\n",
-                                       optarg);
-                               closelog();
-                               exit(1);
+                       here = optarg;
+                       while ((token = strsep(&here, ",;:"))) {
+                               OMIT *restrict optr;
+                               pid_t opid;
+
+                               if (strcmp("%PPID", token) == 0)
+                                       opid = getppid();
+                               else
+                                       opid = (pid_t)atoi(token);
+
+                               if (opid < 1) {
+                                       nsyslog(LOG_ERR,
+                                               "illegal omit pid value "
+                                               "(%s)!\n", token);
+                                       continue;
+                               }
+                               xmemalign((void*)&optr, sizeof(void*), alignof(OMIT));
+                               optr->next = omit;
+                               optr->prev = (OMIT*)0;
+                               optr->pid  = opid;
+                               omit = optr;
                        }
-                       oind++;
                        flags |= PIDOF_OMIT;
                        break;
                case 's':
@@ -561,6 +906,9 @@ int main_pidof(int argc, char **argv)
                case 'x':
                        scripts_too++;
                        break;
+               case 'n':
+                       flags |= PIDOF_NETFS;
+                       break;
                default:
                        /* Nothing */
                        break;
@@ -578,21 +926,28 @@ int main_pidof(int argc, char **argv)
                }
        }
 
+       if (flags & PIDOF_NETFS)
+               init_nfs();             /* Which network based FS are online? */
+
        /* Print out process-ID's one by one. */
-       readproc(DO_STAT);
+       readproc((flags & PIDOF_NETFS) ? DO_NETFS : DO_STAT);
+
        for(f = 0; f < argc; f++) {
                if ((q = pidof(argv[f])) != NULL) {
-                       spid = 0;
+                       pid_t spid = 0;
                        while ((p = get_next_from_pid_q(q))) {
-                               if (flags & PIDOF_OMIT) {
-                                       for (i = 0; i < oind; i++)
-                                               if (opid[i] == p->pid)
+                               if ((flags & PIDOF_OMIT) && omit) {
+                                       OMIT * optr;
+                                       for (optr = omit; optr; optr = optr->next) {
+                                               if (optr->pid == p->pid)
                                                        break;
+                                       }
+
                                        /*
                                         *      On a match, continue with
                                         *      the for loop above.
                                         */
-                                       if (i < oind)
+                                       if (optr)
                                                continue;
                                }
                                if (flags & PIDOF_SINGLE) {
@@ -620,22 +975,20 @@ int main_pidof(int argc, char **argv)
        }
        if (!first)
                printf("\n");
+
+       clear_mnt();
+
        closelog();
        return(first ? 1 : 0);
 }
 
-
-
-#define KILLALL_OMITSZ 16
-
 /* Main for either killall or pidof. */
 int main(int argc, char **argv)
 {
        PROC            *p;
        int             pid, sid = -1;
-       pid_t           opid[KILLALL_OMITSZ];
-       int             i, oind, omit = 0;
        int             sig = SIGKILL;
+       int             c;
 
        /* return non-zero if no process was killed */
        int             retval = 2;
@@ -654,30 +1007,34 @@ int main(int argc, char **argv)
                return main_pidof(argc, argv);
 
        /* Right, so we are "killall". */
-       for (oind = KILLALL_OMITSZ-1; oind > 0; oind--)
-               opid[oind] = 0;
+       omit = (OMIT*)0;
 
        if (argc > 1) {
-               for (i = 1; i < argc; i++) {
-                       if (argv[i][0] == '-') (argv[i])++;
-                       if (argv[i][0] == 'o') {
-                               if (++i >= argc) usage();
-                               if (oind >= KILLALL_OMITSZ -1) {
-                                       nsyslog(LOG_ERR,"omit pid buffer size "
-                                               "%d exceeded!\n",
-                                               KILLALL_OMITSZ);
-                                       closelog();
-                                       exit(1);
-                               }
-                               if ((opid[oind] = atoi(argv[i])) < 1) {
-                                       nsyslog(LOG_ERR,
-                                               "illegal omit pid value "
-                                               "(%s)!\n", argv[i]);
-                                       closelog();
-                                       exit(1);
+               for (c = 1; c < argc; c++) {
+                       if (argv[c][0] == '-') (argv[c])++;
+                       if (argv[c][0] == 'o') {
+                               char * token, * here;
+
+                               if (++c >= argc)
+                                       usage();
+
+                               here = argv[c];
+                               while ((token = strsep(&here, ",;:"))) {
+                                       OMIT *restrict optr;
+                                       pid_t opid = (pid_t)atoi(token);
+
+                                       if (opid < 1) {
+                                               nsyslog(LOG_ERR,
+                                                       "illegal omit pid value "
+                                                       "(%s)!\n", token);
+                                               continue;
+                                       }
+                                       xmemalign((void*)&optr, sizeof(void*), alignof(OMIT));
+                                       optr->next = omit;
+                                       optr->prev = (OMIT*)0;
+                                       optr->pid  = opid;
+                                       omit = optr;
                                }
-                               oind++;
-                               omit = 1;
                        }
                        else if ((sig = atoi(argv[1])) <= 0 || sig > 31)
                                usage();
@@ -716,14 +1073,19 @@ int main(int argc, char **argv)
        for (p = plist; p; p = p->next) {
                if (p->pid == 1 || p->pid == pid || p->sid == sid || p->kernel)
                        continue;
+
                if (omit) {
-                       for (i = 0; i < oind; i++)
-                               if (opid[i] == p->pid)
+                       OMIT * optr;
+                       for (optr = omit; optr; optr = optr->next) {
+                               if (optr->pid == p->pid)
                                        break;
+                       }
+
                        /* On a match, continue with the for loop above. */
-                       if (i < oind)
+                       if (optr)
                                continue;
                }
+
                kill(p->pid, sig);
                retval = 0;
        }