"Fossies" - the Fresh Open Source Software Archive

Member "sysvinit-2.99/src/killall5.c" (21 Feb 2021, 27653 Bytes) of package /linux/misc/sysvinit-2.99.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "killall5.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.98_vs_2.99.

    1 /*
    2  * killall5.c   Kill all processes except processes that have the
    3  *      same session id, so that the shell that called us
    4  *      won't be killed. Typically used in shutdown scripts.
    5  *
    6  * pidof.c  Tries to get the pid of the process[es] named.
    7  *
    8  * Version: 2.86 30-Jul-2004 MvS
    9  *
   10  * Usage:   killall5 [-][signal]
   11  *      pidof [-s] [-o omitpid [-o omitpid]] program [program..]
   12  *
   13  * Authors: Miquel van Smoorenburg, miquels@cistron.nl
   14  *
   15  *      Riku Meskanen, <mesrik@jyu.fi>
   16  *      - return all running pids of given program name
   17  *      - single shot '-s' option for backwards compatibility
   18  *      - omit pid '-o' option and %PPID (parent pid metavariable)
   19  *      - syslog() only if not a connected to controlling terminal
   20  *      - swapped out programs pids are caught now
   21  *
   22  *      Werner Fink
   23  *      - make omit dynamic
   24  *      - provide '-n' to skip stat(2) syscall on network based FS
   25  *
   26  *      This file is part of the sysvinit suite,
   27  *      Copyright (C) 1991-2004 Miquel van Smoorenburg.
   28  *
   29  *      This program is free software; you can redistribute it and/or modify
   30  *      it under the terms of the GNU General Public License as published by
   31  *      the Free Software Foundation; either version 2 of the License, or
   32  *      (at your option) any later version.
   33  *
   34  *      This program is distributed in the hope that it will be useful,
   35  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
   36  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   37  *      GNU General Public License for more details.
   38  *
   39  *      You should have received a copy of the GNU General Public License
   40  *      along with this program; if not, write to the Free Software
   41  *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   42  */
   43 #include <dirent.h>
   44 #include <errno.h>
   45 #include <getopt.h>
   46 #include <limits.h>
   47 #include <mntent.h>
   48 #include <stdarg.h>
   49 #include <stdio.h>
   50 #include <stdlib.h>
   51 #include <signal.h>
   52 #include <string.h>
   53 #include <syslog.h>
   54 #include <sys/mman.h>
   55 #include <sys/param.h>
   56 #include <sys/stat.h>
   57 #include <sys/types.h>
   58 #include <sys/wait.h>
   59 #include <unistd.h>
   60 
   61 #ifndef PATH_MAX
   62 #  ifdef MAXPATHLEN
   63 #    define PATH_MAX MAXPATHLEN
   64 #  else
   65 #    define PATH_MAX 2048
   66 #  endif
   67 #endif
   68 
   69 #define STATNAMELEN 15
   70 #define DO_NETFS 2
   71 #define DO_STAT 1
   72 #define NO_STAT 0
   73 
   74 /* Info about a process. */
   75 typedef struct proc {
   76     char *pathname;     /* full path to executable        */
   77     char *argv0;        /* Name as found out from argv[0] */
   78     char *argv0base;    /* `basename argv[1]`         */
   79     char *argv1;        /* Name as found out from argv[1] */
   80     char *argv1base;    /* `basename argv[1]`         */
   81     char *statname;     /* the statname without braces    */
   82     ino_t ino;      /* Inode number           */
   83     dev_t dev;      /* Device it is on        */
   84     pid_t pid;      /* Process ID.            */
   85     pid_t sid;      /* Session ID.            */
   86     char kernel;        /* Kernel thread or zombie.   */
   87     char nfs;       /* Name found on network FS.      */
   88     struct proc *next;  /* Pointer to next struct.    */
   89 } PROC;
   90 
   91 /* pid queue */
   92 
   93 typedef struct pidq {
   94     PROC        *proc;
   95     struct pidq *next;
   96 } PIDQ;
   97 
   98 typedef struct {
   99     PIDQ        *head;
  100     PIDQ        *tail;
  101     PIDQ        *next;
  102 } PIDQ_HEAD;
  103 
  104 typedef struct _s_omit {
  105     struct _s_omit *next;
  106     struct _s_omit *prev;
  107     pid_t pid;
  108 } OMIT;
  109 
  110 typedef struct _s_shadow
  111 {
  112     struct _s_shadow *next;
  113     struct _s_shadow *prev;
  114     size_t nlen;
  115     char * name;
  116 } SHADOW;
  117 
  118 typedef struct _s_nfs
  119 {
  120     struct _s_nfs *next;    /* Pointer to next struct. */
  121     struct _s_nfs *prev;    /* Pointer to previous st. */
  122     SHADOW *shadow;     /* Pointer to shadows      */
  123     size_t nlen;
  124     char * name;
  125 } NFS;
  126 
  127 /* List of processes. */
  128 PROC *plist;
  129 
  130 /* List of processes to omit. */
  131 OMIT *omit;
  132 
  133 /* List of NFS mountes partitions. */
  134 NFS *nlist;
  135 
  136 /* Did we stop all processes ? */
  137 int sent_sigstop;
  138 int scripts_too = 0;
  139 
  140 /* Should pidof try to list processes in I/O wait (D) and zombie (Z) states? */
  141 #ifndef FALSE
  142 #define FALSE 0
  143 #endif
  144 #ifndef TRUE
  145 #define TRUE 1
  146 #endif
  147 int list_dz_processes = FALSE;
  148 
  149 char *progname; /* the name of the running program */
  150 #ifdef __GNUC__
  151 __attribute__ ((format (printf, 2, 3)))
  152 #endif
  153 void nsyslog(int pri, char *fmt, ...);
  154 
  155 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
  156 # ifndef  inline
  157 #  define inline    __inline__
  158 # endif
  159 # ifndef  restrict
  160 #  define restrict  __restrict__
  161 # endif
  162 #endif
  163 #define alignof(type)   ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
  164 
  165 /*
  166  *  Malloc space, barf if out of memory.
  167  */
  168 #ifdef __GNUC__
  169 static void *xmalloc(size_t) __attribute__ ((__malloc__));
  170 #endif
  171 static void *xmalloc(size_t bytes)
  172 {
  173     void *p;
  174 
  175     if ((p = malloc(bytes)) == NULL) {
  176         if (sent_sigstop) kill(-1, SIGCONT);
  177         nsyslog(LOG_ERR, "out of memory");
  178         exit(1);
  179     }
  180     return p;
  181 }
  182 
  183 #ifdef __GNUC__
  184 static inline void xmemalign(void **, size_t, size_t) __attribute__ ((__nonnull__ (1)));
  185 #endif
  186 static inline void xmemalign(void **memptr, size_t alignment, size_t size)
  187 {
  188     if ((posix_memalign(memptr, alignment, size)) < 0) {
  189         if (sent_sigstop) kill(-1, SIGCONT);
  190         nsyslog(LOG_ERR, "out of memory");
  191         exit(1);
  192     }
  193 }
  194 
  195 /*
  196  *  See if the proc filesystem is there. Mount if needed.
  197  */
  198 int mount_proc(void)
  199 {
  200     struct stat st;
  201     char        *args[] = { "mount", "-t", "proc", "proc", "/proc", 0 };
  202     pid_t       pid, rc;
  203     int     wst;
  204     int     did_mount = 0;
  205 
  206     /* Stat /proc/version to see if /proc is mounted. */
  207     if (stat("/proc/version", &st) < 0 && errno == ENOENT) {
  208 
  209         /* It's not there, so mount it. */
  210         if ((pid = fork()) < 0) {
  211             nsyslog(LOG_ERR, "cannot fork");
  212             exit(1);
  213         }
  214         if (pid == 0) {
  215             /* Try a few mount binaries. */
  216             execv("/bin/mount", args);
  217             execv("/sbin/mount", args);
  218 
  219             /* Okay, I give up. */
  220             nsyslog(LOG_ERR, "cannot execute mount");
  221             exit(1);
  222         }
  223         /* Wait for child. */
  224         while ((rc = wait(&wst)) != pid)
  225             if (rc < 0 && errno == ECHILD)
  226                 break;
  227         if (rc != pid || WEXITSTATUS(wst) != 0)
  228             nsyslog(LOG_ERR, "mount returned non-zero exit status");
  229 
  230         did_mount = 1;
  231     }
  232 
  233     /* See if mount succeeded. */
  234     if (stat("/proc/version", &st) < 0) {
  235         if (errno == ENOENT)
  236             nsyslog(LOG_ERR, "/proc not mounted, failed to mount.");
  237         else
  238             nsyslog(LOG_ERR, "/proc unavailable.");
  239         exit(1);
  240     }
  241 
  242     return did_mount;
  243 }
  244 
  245 static inline int isnetfs(const char * type)
  246 {
  247     static const char* netfs[] = {"nfs", "nfs4", "smbfs", "cifs", "afs", "ncpfs", (char*)0};
  248     int n;
  249     for (n = 0; netfs[n]; n++) {
  250         if (!strcasecmp(netfs[n], type))
  251             return 1;
  252     }
  253     return 0;
  254 }
  255 
  256 /*
  257  *     Remember all NFS typed partitions.
  258  */
  259 void init_nfs(void)
  260 {
  261         struct stat st;
  262         struct mntent * ent;
  263     FILE * mnt;
  264 
  265     nlist = (NFS*)0;
  266 
  267     if (stat("/proc/version", &st) < 0)
  268         return;
  269     if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
  270         return;
  271 
  272     while ((ent = getmntent(mnt))) {
  273         if (isnetfs(ent->mnt_type)) {
  274             size_t nlen = strlen(ent->mnt_dir);
  275             NFS *restrict p;
  276             xmemalign((void*)&p, sizeof(void*), alignof(NFS)+(nlen+1));
  277             p->name = ((char*)p)+alignof(NFS);
  278             p->nlen = nlen;
  279             p->shadow = (SHADOW*)0;
  280 
  281             strcpy(p->name, ent->mnt_dir);
  282             if (nlist)
  283                 nlist->prev = p;
  284             p->next = nlist;
  285             p->prev = (NFS*)0;
  286             nlist = p;
  287         }
  288     }
  289     endmntent(mnt);
  290 
  291     if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
  292         return;
  293 
  294     while ((ent = getmntent(mnt))) {
  295         NFS *p;
  296 
  297         for (p = nlist; p; p = p->next) {
  298             SHADOW * restrict s;
  299             size_t nlen;
  300 
  301             if (strcmp(ent->mnt_dir, p->name) == 0)
  302                 continue;
  303             if (strncmp(ent->mnt_dir, p->name, p->nlen) != 0)
  304                 continue;
  305 
  306             nlen = strlen(ent->mnt_dir);
  307             xmemalign((void*)&s, sizeof(void*), alignof(SHADOW)+(nlen+1));
  308             s->name = ((char*)s)+alignof(SHADOW);
  309             s->nlen = nlen;
  310 
  311             strcpy(s->name, ent->mnt_dir);
  312             if (p->shadow)
  313                 p->shadow->prev = s;
  314             s->next = p->shadow;
  315             s->prev = (SHADOW*)0;
  316             p->shadow = s;
  317         }
  318     }
  319     endmntent(mnt);
  320 }
  321 
  322 static void clear_shadow(SHADOW *restrict shadow)
  323 {
  324     SHADOW *s, *n, *l;
  325 
  326     n = shadow;
  327     l = (SHADOW*)0;
  328     for (s = shadow; n; s = n) {
  329         l = s->prev;
  330         n = s->next;
  331         if (s == shadow) {
  332             if (n) n->prev = (SHADOW*)0;
  333             shadow = n;
  334         } else if (l) {
  335             if (n) n->prev = l;
  336             l->next = n;
  337         }
  338         free(s);
  339     }
  340 }
  341 
  342 static void clear_mnt(void)
  343 {
  344     NFS *p, *n, *l;
  345 
  346     n = nlist;
  347     l = (NFS*)0;
  348     for (p = nlist; n; p = n) {
  349         l = p->prev;
  350         n = p->next;
  351         if (p == nlist) {
  352             if (n) n->prev = (NFS*)0;
  353             nlist = n;
  354         } else if (l) {
  355             if (n) n->prev = l;
  356             l->next = n;
  357         }
  358         if (p->shadow)
  359             clear_shadow(p->shadow);
  360         free(p);
  361     }
  362 }
  363 
  364 /*
  365  *     Check if path is a shadow off a NFS partition.
  366  */
  367 static int shadow(SHADOW *restrict this, const char *restrict name, const size_t nlen)
  368 {
  369     SHADOW *s;
  370 
  371     if (!this)
  372         goto out;
  373     for (s = this; s; s = s->next) {
  374         if (nlen < s->nlen)
  375             continue;
  376         if (name[s->nlen] != '\0' && name[s->nlen] != '/')
  377             continue;
  378         if (strncmp(name, s->name, s->nlen) == 0)
  379             return 1;
  380     }
  381 out:
  382     return 0;
  383 }
  384 
  385 /*
  386  * Get the maximal number of symlinks to follow.  Use sysconf() on
  387  * Hurd where the hardcoded value MAXSYMLINKS is not available.
  388  */
  389 static int maxsymlinks(void)
  390 {
  391     int v = sysconf(_SC_SYMLOOP_MAX);
  392 #ifdef MAXSYMLINKS
  393     if (v == -1)
  394         return MAXSYMLINKS;
  395 #endif
  396     return v;
  397 }
  398 
  399 /*
  400  *     Check path is located on a network based partition.
  401  */
  402 int check4nfs(const char * path, char * real)
  403 {
  404     char buf[PATH_MAX+1];
  405     const char *curr;
  406     int deep = maxsymlinks();
  407 
  408     if (!nlist) return 0;
  409 
  410     curr = path;
  411     do {
  412         const char *prev;
  413         int len;
  414 
  415         if ((prev = strdupa(curr)) == NULL) {
  416             nsyslog(LOG_ERR, "strdupa(): %s\n", strerror(errno));
  417             return 0;
  418         }
  419 
  420         errno = 0;
  421         if ((len = readlink(curr, buf, PATH_MAX)) < 0)
  422             break;
  423         buf[len] = '\0';
  424 
  425         if (buf[0] != '/') {
  426             const char *slash;
  427 
  428             if ((slash = strrchr(prev, '/'))) {
  429                 size_t off = slash - prev + 1;
  430 
  431                 if (off + len > PATH_MAX)
  432                     len = PATH_MAX - off;
  433 
  434                 memmove(&buf[off], &buf[0], len + 1);
  435                 memcpy(&buf[0], prev, off);
  436             }
  437         }
  438         curr = &buf[0];
  439 
  440         if (deep-- <= 0) return 0;
  441 
  442     } while (1);
  443 
  444     if (real)     /* real is defined elsewhere as being PATH_MAX + 1 */
  445         {
  446            memset(real, '\0', PATH_MAX + 1);
  447            strncpy(real, curr, PATH_MAX);
  448         }
  449 
  450     if (errno == EINVAL) {
  451         const size_t nlen = strlen(curr);
  452         NFS *p;
  453         for (p = nlist; p; p = p->next) {
  454             if (nlen < p->nlen)
  455                 continue;
  456             if (curr[p->nlen] != '\0' && curr[p->nlen] != '/')
  457                 continue;
  458             if (!strncmp(curr, p->name, p->nlen)) {
  459                 if (shadow(p->shadow, curr, nlen))
  460                     continue;
  461                 return 1;
  462             }
  463         }
  464     }
  465 
  466     return 0;
  467 }
  468 
  469 int readarg(FILE *fp, char *buf, int sz)
  470 {
  471     int     c = 0, f = 0;
  472 
  473     while (f < (sz-1) && (c = fgetc(fp)) != EOF && c)
  474         buf[f++] = c;
  475     buf[f] = 0;
  476 
  477     return (c == EOF && f == 0) ? c : f;
  478 }
  479 
  480 /*
  481  *  Read the proc filesystem.
  482  *  CWD must be /proc to avoid problems if / is affected by the killing (ie depend on fuse).
  483  */
  484 int readproc(int do_stat)
  485 {
  486     DIR     *dir;
  487     FILE        *fp;
  488     PROC        *p, *n;
  489     struct dirent   *d;
  490     struct stat st;
  491     char        path[PATH_MAX+1];
  492     char        buf[PATH_MAX+1];
  493     char        *s, *q;
  494     unsigned long   startcode, endcode;
  495     int     pid, f;
  496     ssize_t     len;
  497         char            process_status[11];
  498 
  499     /* Open the /proc directory. */
  500     if (chdir("/proc") == -1) {
  501         nsyslog(LOG_ERR, "chdir /proc failed");
  502         return -1;
  503     }
  504     if ((dir = opendir(".")) == NULL) {
  505         nsyslog(LOG_ERR, "cannot opendir(/proc)");
  506         return -1;
  507     }
  508 
  509     /* Free the already existing process list. */
  510     n = plist;
  511     for (p = plist; n; p = n) {
  512         n = p->next;
  513         if (p->argv0) free(p->argv0);
  514         if (p->argv1) free(p->argv1);
  515         if (p->statname) free(p->statname);
  516         if (p->pathname) free(p->pathname);
  517         free(p);
  518     }
  519     plist = NULL;
  520 
  521     /* Walk through the directory. */
  522     while ((d = readdir(dir)) != NULL) {
  523 
  524         /* See if this is a process */
  525         if ((pid = atoi(d->d_name)) == 0) continue;
  526 
  527         /* Get a PROC struct . */
  528         p = (PROC *)xmalloc(sizeof(PROC));
  529         memset(p, 0, sizeof(PROC));
  530 
  531         /* Open the status file. */
  532         snprintf(path, sizeof(path), "%s/stat", d->d_name);
  533 
  534         /* Read SID & statname from it. */
  535         if ((fp = fopen(path, "r")) != NULL) {
  536             size_t len;
  537 
  538             len = fread(buf, sizeof(char), sizeof(buf)-1, fp);
  539             buf[len] = '\0';
  540 
  541             if (buf[0] == '\0') {
  542                 nsyslog(LOG_ERR,
  543                     "can't read from %s\n", path);
  544                 fclose(fp);
  545                 free(p);
  546                 continue;
  547             }
  548 
  549             /* See if name starts with '(' */
  550             s = buf;
  551             while (*s && *s != ' ') s++;
  552             if (*s) s++;
  553             if (*s == '(') {
  554                 /* Read program name. */
  555                 q = strrchr(buf, ')');
  556                 if (q == NULL) {
  557                     p->sid = 0;
  558                     nsyslog(LOG_ERR,
  559                     "can't get program name from /proc/%s\n",
  560                         path);
  561                     fclose(fp);
  562                     if (p->argv0) free(p->argv0);
  563                     if (p->argv1) free(p->argv1);
  564                     if (p->statname) free(p->statname);
  565                     if (p->pathname) free(p->pathname);
  566                     free(p);
  567                     continue;
  568                 }
  569                 s++;
  570             } else {
  571                 q = s;
  572                 while (*q && *q != ' ') q++;
  573             }
  574             if (*q) *q++ = 0;
  575             while (*q == ' ') q++;
  576             p->statname = (char *)xmalloc(strlen(s)+1);
  577             strcpy(p->statname, s);
  578 
  579             /* Get session, startcode, endcode. */
  580             startcode = endcode = 0;
  581             if (sscanf(q,   "%10s %*d %*d %d %*d %*d %*u %*u "
  582                     "%*u %*u %*u %*u %*u %*d %*d "
  583                     "%*d %*d %*d %*d %*u %*u %*d "
  584                     "%*u %lu %lu",
  585                     process_status, 
  586                     &p->sid, &startcode, &endcode) != 4) {
  587 
  588                 p->sid = 0;
  589                 nsyslog(LOG_ERR, "can't read sid from %s\n",
  590                     path);
  591                 fclose(fp);
  592                 if (p->argv0) free(p->argv0);
  593                 if (p->argv1) free(p->argv1);
  594                 if (p->statname) free(p->statname);
  595                 free(p->pathname);
  596                 free(p);
  597                 continue;
  598             }
  599             if (startcode == 0 && endcode == 0)
  600                 p->kernel = 1;
  601             fclose(fp);
  602                         if ( (! list_dz_processes) &&
  603                              ( (strchr(process_status, 'D') != NULL) ||
  604                                (strchr(process_status, 'Z') != NULL) ) ){
  605                            /* Ignore zombie processes or processes in
  606                               disk sleep, as attempts
  607                               to access the stats of these will
  608                               sometimes fail. */
  609                               if (p->argv0) free(p->argv0);
  610                               if (p->argv1) free(p->argv1);
  611                               if (p->statname) free(p->statname);
  612                              free(p);
  613                              continue;
  614                         }
  615         } else {
  616             /* Process disappeared.. */
  617             if (p->argv0) free(p->argv0);
  618             if (p->argv1) free(p->argv1);
  619             if (p->statname) free(p->statname);
  620             if (p->pathname) free(p->pathname);
  621             free(p);
  622             continue;
  623         }
  624 
  625         snprintf(path, sizeof(path), "%s/cmdline", d->d_name);
  626         if ((fp = fopen(path, "r")) != NULL) {
  627 
  628             /* Now read argv[0] */
  629             f = readarg(fp, buf, sizeof(buf));
  630 
  631             if (buf[0]) {
  632                 /* Store the name into malloced memory. */
  633                 p->argv0 = (char *)xmalloc(f + 1);
  634                 strcpy(p->argv0, buf);
  635 
  636                 /* Get a pointer to the basename. */
  637                 p->argv0base = strrchr(p->argv0, '/');
  638                 if (p->argv0base != NULL)
  639                     p->argv0base++;
  640                 else
  641                     p->argv0base = p->argv0;
  642             }
  643 
  644             /* And read argv[1] */
  645             while ((f = readarg(fp, buf, sizeof(buf))) != EOF)
  646                 if (buf[0] != '-') break;
  647 
  648             if (buf[0]) {
  649                 /* Store the name into malloced memory. */
  650                 p->argv1 = (char *)xmalloc(f + 1);
  651                 strcpy(p->argv1, buf);
  652 
  653                 /* Get a pointer to the basename. */
  654                 p->argv1base = strrchr(p->argv1, '/');
  655                 if (p->argv1base != NULL)
  656                     p->argv1base++;
  657                 else
  658                     p->argv1base = p->argv1;
  659             }
  660 
  661             fclose(fp);
  662 
  663         } else {
  664             /* Process disappeared.. */
  665             if (p->argv0) free(p->argv0);
  666             if (p->argv1) free(p->argv1);
  667             if (p->statname) free(p->statname);
  668             if (p->pathname) free(p->pathname);
  669             free(p);
  670             continue;
  671         }
  672 
  673         /* Try to stat the executable. */
  674         snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name);
  675 
  676         p->nfs = 0;
  677 
  678         switch (do_stat) {
  679         case DO_NETFS:
  680             if ((p->nfs = check4nfs(path, buf)))
  681                 goto link;
  682                         /* else fall through */
  683         case DO_STAT:
  684             if (stat(path, &st) != 0) {
  685                 char * ptr;
  686 
  687                 len = readlink(path, buf, PATH_MAX);
  688                 if (len <= 0)
  689                     break;
  690                 buf[len] = '\0';
  691 
  692                 ptr = strstr(buf, " (deleted)");
  693                 if (!ptr)
  694                     break;
  695                 *ptr = '\0';
  696                 len -= strlen(" (deleted)");
  697 
  698                 if (stat(buf, &st) != 0)
  699                     break;
  700                 p->dev = st.st_dev;
  701                 p->ino = st.st_ino;
  702                 p->pathname = (char *)xmalloc(len + 1);
  703                 memcpy(p->pathname, buf, len);
  704                 p->pathname[len] = '\0';
  705 
  706                 /* All done */
  707                 break;
  708             }
  709 
  710             p->dev = st.st_dev;
  711             p->ino = st.st_ino;
  712 
  713             /* Fall through */
  714         default:
  715         link:
  716             len = readlink(path, buf, PATH_MAX);
  717             if (len > 0) {
  718                 p->pathname = (char *)xmalloc(len + 1);
  719                 memcpy(p->pathname, buf, len);
  720                 p->pathname[len] = '\0';
  721             }
  722             break;
  723         }
  724 
  725         /* Link it into the list. */
  726         p->next = plist;
  727         plist = p;
  728         p->pid = pid;
  729     }
  730     closedir(dir);
  731 
  732     /* Done. */
  733     return 0;
  734 }
  735 
  736 PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q)
  737 {
  738     q->head =  q->next = q->tail = NULL;
  739     return q;
  740 }
  741 
  742 int empty_q(PIDQ_HEAD *q)
  743 {
  744     return (q->head == NULL);
  745 }
  746 
  747 int add_pid_to_q(PIDQ_HEAD *q, PROC *p)
  748 {
  749     PIDQ *tmp;
  750 
  751     tmp = (PIDQ *)xmalloc(sizeof(PIDQ));
  752 
  753     tmp->proc = p;
  754     tmp->next = NULL;
  755 
  756     if (empty_q(q)) {
  757         q->head = tmp;
  758         q->tail  = tmp;
  759     } else {
  760         q->tail->next = tmp;
  761         q->tail = tmp;
  762     }
  763     return 0;
  764 }
  765 
  766 PROC *get_next_from_pid_q(PIDQ_HEAD *q)
  767 {
  768     PROC        *p;
  769     PIDQ        *tmp = q->head;
  770 
  771     if (!empty_q(q)) {
  772         p = q->head->proc;
  773         q->head = tmp->next;
  774         free(tmp);
  775         return p;
  776     }
  777 
  778     return NULL;
  779 }
  780 
  781 /* Try to get the process ID of a given process. */
  782 PIDQ_HEAD *pidof(char *prog)
  783 {
  784     PROC        *p;
  785     PIDQ_HEAD   *q;
  786     struct stat st;
  787     char        *s;
  788     int     nfs = 0;
  789     int     dostat = 0;
  790     int     foundone = 0;
  791     int     ok = 0;
  792     const int   root = (getuid() == 0);
  793     char        real[PATH_MAX+1];
  794 
  795     if (! prog)
  796         return NULL;
  797 
  798     /* Try to stat the executable. */
  799     if (prog[0] == '/') {
  800         memset(&real[0], 0, sizeof(real));
  801 
  802         if (check4nfs(prog, real))
  803             nfs++;
  804 
  805         if (real[0] != '\0')
  806             prog = &real[0];    /* Binary located on network FS. */
  807 
  808         if ((nfs == 0) && (stat(prog, &st) == 0))
  809             dostat++;       /* Binary located on a local FS. */
  810     }
  811 
  812     /* Get basename of program. */
  813     if ((s = strrchr(prog, '/')) == NULL)
  814         s = prog;
  815     else
  816         s++;
  817 
  818     if (! *s)
  819         return NULL;
  820 
  821     q = (PIDQ_HEAD *)xmalloc(sizeof(PIDQ_HEAD));
  822     q = init_pid_q(q);
  823 
  824     /* First try to find a match based on dev/ino pair. */
  825     if (dostat && !nfs) {
  826         for (p = plist; p; p = p->next) {
  827             if (p->nfs)
  828                 continue;
  829             if (p->dev == st.st_dev && p->ino == st.st_ino) {
  830                 add_pid_to_q(q, p);
  831                 foundone++;
  832             }
  833         }
  834     }
  835 
  836     /* Second try to find a match based on full path name on
  837      * network FS located binaries */
  838     if (!foundone && nfs) {
  839         for (p = plist; p; p = p->next) {
  840             if (!p->pathname)
  841                 continue;
  842             if (!p->nfs)
  843                 continue;
  844             if (strcmp(prog, p->pathname) != 0)
  845                 continue;
  846             add_pid_to_q(q, p);
  847             foundone++;
  848         }
  849     }
  850 
  851     /* If we didn't find a match based on dev/ino, try the name. */
  852     if (!foundone) for (p = plist; p; p = p->next) {
  853         if (prog[0] == '/') {
  854             if (!p->pathname) {
  855                 if (root)
  856                     continue;
  857                 goto fallback; 
  858             }
  859             if (strcmp(prog, p->pathname)) {
  860                 int len = strlen(prog);
  861                 if (strncmp(prog, p->pathname, len))
  862                 {
  863                     if (scripts_too)
  864                         goto fallback;
  865                     continue;
  866                 }
  867                 if (strcmp(" (deleted)", p->pathname + len))
  868                 {
  869                     if (scripts_too)
  870                         goto fallback;
  871                     continue;
  872                 }
  873             }
  874             add_pid_to_q(q, p);
  875             continue;
  876         }
  877 
  878     fallback:
  879         ok = 0;
  880 
  881         /*             matching        nonmatching
  882          * proc name   prog name       prog name
  883          * ---         -----------     ------------
  884          *   b         b, p/b, q/b
  885          * p/b         b, p/b          q/b
  886          *
  887          * Algorithm: Match if:
  888          *    cmd = arg
  889          * or cmd = base(arg)
  890          * or base(cmd) = arg
  891          *
  892          * Specifically, do not match just because base(cmd) = base(arg)
  893          * as was done in earlier versions of this program, since this
  894          * allows /aaa/foo to match /bbb/foo .
  895          */
  896         ok |=
  897             (p->argv0 && strcmp(p->argv0, prog) == 0)
  898             || (p->argv0 && s != prog && strcmp(p->argv0, s) == 0)
  899             || (p->argv0base && strcmp(p->argv0base, prog) == 0);
  900 
  901         /* For scripts, compare argv[1] as well. */
  902         if (
  903             scripts_too && p->statname && p->argv1base
  904             && !strncmp(p->statname, p->argv1base, STATNAMELEN)
  905         ) {
  906             ok |=
  907                 (p->argv1 && strcmp(p->argv1, prog) == 0)
  908                 || (p->argv1 && s != prog && strcmp(p->argv1, s) == 0)
  909                 || (p->argv1base && strcmp(p->argv1base, prog) == 0);
  910         }
  911 
  912         /*
  913          *  if we have a space in argv0, process probably
  914          *  used setproctitle so try statname.
  915          */
  916         if (strlen(s) <= STATNAMELEN &&
  917             (p->argv0 == NULL ||
  918              p->argv0[0] == 0 ||
  919              strchr(p->argv0, ' '))) {
  920             ok |= (strcmp(p->statname, s) == 0);
  921         }
  922 
  923         /*
  924          *  if we have a `-' as the first character, process
  925          *  probably used as a login shell
  926          */
  927         if (strlen(s) <= STATNAMELEN &&
  928             p->argv1 == NULL &&
  929             (p->argv0 != NULL &&
  930              p->argv0[0] == '-')) {
  931             ok |= (strcmp(p->statname, s) == 0);
  932         }
  933 
  934         if (ok) add_pid_to_q(q, p);
  935     }
  936 
  937     return q;
  938 }
  939 
  940 /* Give usage message and exit. */
  941 void usage(void)
  942 {
  943     nsyslog(LOG_ERR, "only one argument, a signal number, allowed");
  944     closelog();
  945     exit(1);
  946 }
  947 
  948 
  949 void pidof_usage(void)
  950 {
  951    printf("pidof usage: [options] <program-name>\n\n");
  952    printf(" -c           Return PIDs with the same root directory\n");
  953    printf(" -d <sep>     Use the provided character as output separator\n");
  954    printf(" -h           Display this help text\n");
  955    printf(" -n           Avoid using stat system function on network shares\n");
  956    printf(" -o <pid>     Omit results with a given PID\n");
  957    printf(" -q           Quiet mode. Do not display output\n");
  958    printf(" -s           Only return one PID\n");
  959    printf(" -x           Return PIDs of shells running scripts with a matching name\n");
  960    printf(" -z           List zombie and I/O waiting processes. May cause pidof to hang.\n");
  961    printf("\n");
  962 }
  963 
  964 
  965 /* write to syslog file if not open terminal */
  966 #ifdef __GNUC__
  967 __attribute__ ((format (printf, 2, 3)))
  968 #endif
  969 void nsyslog(int pri, char *fmt, ...)
  970 {
  971     va_list  args;
  972 
  973     va_start(args, fmt);
  974 
  975     if (ttyname(0) == NULL) {
  976         vsyslog(pri, fmt, args);
  977     } else {
  978         fprintf(stderr, "%s: ",progname);
  979         vfprintf(stderr, fmt, args);
  980         fprintf(stderr, "\n");
  981     }
  982 
  983     va_end(args);
  984 }
  985 
  986 #define PIDOF_SINGLE    0x01
  987 #define PIDOF_OMIT  0x02
  988 #define PIDOF_NETFS 0x04
  989 #define PIDOF_QUIET     0x08
  990 
  991 /*
  992  *  Pidof functionality.
  993  */
  994 int main_pidof(int argc, char **argv)
  995 {
  996     PIDQ_HEAD   *q;
  997     PROC        *p;
  998     char        *token, *here;
  999     int     f;
 1000     int     first = 1;
 1001     int     opt, flags = 0;
 1002     int     chroot_check = 0;
 1003     struct stat st;
 1004     char        tmp[512];
 1005         char            sep = ' ';
 1006 
 1007     omit = (OMIT*)0;
 1008     nlist = (NFS*)0;
 1009     opterr = 0;
 1010 
 1011     if ((token = getenv("PIDOF_NETFS")) && (strcmp(token,"no") != 0))
 1012         flags |= PIDOF_NETFS;
 1013 
 1014     while ((opt = getopt(argc,argv,"qhco:d:sxzn")) != EOF) switch (opt) {
 1015         case '?':
 1016             nsyslog(LOG_ERR,"invalid options on command line!\n");
 1017             closelog();
 1018             exit(1);
 1019         case 'c':
 1020             if (geteuid() == 0) chroot_check = 1;
 1021             break;
 1022                 case 'h':
 1023                         pidof_usage();
 1024                         exit(0);
 1025                 case 'd':
 1026                         sep = optarg[0];
 1027                         break;
 1028         case 'o':
 1029             here = optarg;
 1030             while ((token = strsep(&here, ",;:"))) {
 1031                 OMIT *restrict optr;
 1032                 pid_t opid;
 1033 
 1034                 if (strcmp("%PPID", token) == 0)
 1035                     opid = getppid();
 1036                 else
 1037                     opid = (pid_t)atoi(token);
 1038 
 1039                 if (opid < 1) {
 1040                     nsyslog(LOG_ERR,
 1041                         "illegal omit pid value "
 1042                         "(%s)!\n", token);
 1043                     continue;
 1044                 }
 1045                 xmemalign((void*)&optr, sizeof(void*), alignof(OMIT));
 1046                 optr->next = omit;
 1047                 optr->prev = (OMIT*)0;
 1048                 optr->pid  = opid;
 1049                 omit = optr;
 1050             }
 1051             flags |= PIDOF_OMIT;
 1052             break;
 1053                 case 'q':
 1054                         flags |= PIDOF_QUIET;
 1055                         break; 
 1056         case 's':
 1057             flags |= PIDOF_SINGLE;
 1058             break;
 1059         case 'x':
 1060             scripts_too++;
 1061             break;
 1062                 case 'z':
 1063                         list_dz_processes = TRUE;
 1064                         break;
 1065         case 'n':
 1066             flags |= PIDOF_NETFS;
 1067             break;
 1068         default:
 1069             /* Nothing */
 1070             break;
 1071     }
 1072     argc -= optind;
 1073     argv += optind;
 1074 
 1075     /* Check if we are in a chroot */
 1076     if (chroot_check) {
 1077         snprintf(tmp, 512, "/proc/%d/root", getpid());
 1078         if (stat(tmp, &st) < 0) {
 1079             nsyslog(LOG_ERR, "stat failed for %s!\n", tmp);
 1080             closelog();
 1081             exit(1);
 1082         }
 1083     }
 1084 
 1085     if (flags & PIDOF_NETFS)
 1086         init_nfs();     /* Which network based FS are online? */
 1087 
 1088     /* Print out process-ID's one by one. */
 1089     readproc((flags & PIDOF_NETFS) ? DO_NETFS : DO_STAT);
 1090 
 1091     for(f = 0; f < argc; f++) {
 1092         if ((q = pidof(argv[f])) != NULL) {
 1093             pid_t spid = 0;
 1094             while ((p = get_next_from_pid_q(q))) {
 1095                 if ((flags & PIDOF_OMIT) && omit) {
 1096                     OMIT * optr;
 1097                     for (optr = omit; optr; optr = optr->next) {
 1098                         if (optr->pid == p->pid)
 1099                             break;
 1100                     }
 1101 
 1102                     /*
 1103                      *  On a match, continue with
 1104                      *  the for loop above.
 1105                      */
 1106                     if (optr)
 1107                         continue;
 1108                 }
 1109                 if (flags & PIDOF_SINGLE) {
 1110                     if (spid)
 1111                         continue;
 1112                     else
 1113                         spid = 1;
 1114                 }
 1115                 if (chroot_check) {
 1116                     struct stat st2;
 1117                     snprintf(tmp, 512, "/proc/%d/root",
 1118                          p->pid);
 1119                     if (stat(tmp, &st2) < 0 ||
 1120                         st.st_dev != st2.st_dev ||
 1121                         st.st_ino != st2.st_ino) {
 1122                         continue;
 1123                     }
 1124                 }
 1125 
 1126                 if ( ~flags & PIDOF_QUIET ) {
 1127                     if (! first)
 1128                         printf("%c", sep);
 1129                     printf("%d", p->pid);
 1130                 }
 1131                 first = 0;
 1132             }
 1133         }
 1134     }
 1135     if (!first)
 1136         {
 1137             if ( ~flags & PIDOF_QUIET ) 
 1138         printf("\n");
 1139         }
 1140 
 1141     clear_mnt();
 1142 
 1143     closelog();
 1144     return(first ? 1 : 0);
 1145 }
 1146 
 1147 /* Main for either killall or pidof. */
 1148 int main(int argc, char **argv)
 1149 {
 1150     PROC        *p;
 1151     int     pid, sid = -1;
 1152     int     sig = SIGKILL;
 1153     int     c;
 1154 
 1155     /* return non-zero if no process was killed */
 1156     int     retval = 2;
 1157 
 1158     /* Get program name. */
 1159     if ((progname = strrchr(argv[0], '/')) == NULL)
 1160         progname = argv[0];
 1161     else
 1162         progname++;
 1163 
 1164     /* Now connect to syslog. */
 1165     openlog(progname, LOG_CONS|LOG_PID, LOG_DAEMON);
 1166 
 1167     /* Were we called as 'pidof' ? */
 1168     if (strcmp(progname, "pidof") == 0)
 1169         return main_pidof(argc, argv);
 1170 
 1171     /* Right, so we are "killall". */
 1172     omit = (OMIT*)0;
 1173 
 1174     if (argc > 1) {
 1175         for (c = 1; c < argc; c++) {
 1176             if (argv[c][0] == '-') (argv[c])++;
 1177             if (argv[c][0] == 'o') {
 1178                 char * token, * here;
 1179 
 1180                 if (++c >= argc)
 1181                     usage();
 1182 
 1183                 here = argv[c];
 1184                 while ((token = strsep(&here, ",;:"))) {
 1185                     OMIT *restrict optr;
 1186                     pid_t opid = (pid_t)atoi(token);
 1187 
 1188                     if (opid < 1) {
 1189                         nsyslog(LOG_ERR,
 1190                             "illegal omit pid value "
 1191                             "(%s)!\n", token);
 1192                         continue;
 1193                     }
 1194                     xmemalign((void*)&optr, sizeof(void*), alignof(OMIT));
 1195                     optr->next = omit;
 1196                     optr->prev = (OMIT*)0;
 1197                     optr->pid  = opid;
 1198                     omit = optr;
 1199                 }
 1200             }
 1201             else if ((sig = atoi(argv[1])) <= 0 || sig > 31)
 1202                 usage();
 1203         }
 1204     }
 1205 
 1206     /* First get the /proc filesystem online. */
 1207     mount_proc();
 1208 
 1209     /*
 1210      *  Ignoring SIGKILL and SIGSTOP do not make sense, but
 1211      *  someday kill(-1, sig) might kill ourself if we don't
 1212      *  do this. This certainly is a valid concern for SIGTERM-
 1213      *  Linux 2.1 might send the calling process the signal too.
 1214      */
 1215     signal(SIGTERM, SIG_IGN);
 1216     signal(SIGSTOP, SIG_IGN);
 1217     signal(SIGKILL, SIG_IGN);
 1218 
 1219     /* lock us into memory */
 1220     mlockall(MCL_CURRENT | MCL_FUTURE);
 1221 
 1222     /* Now stop all processes. */
 1223     kill(-1, SIGSTOP);
 1224     sent_sigstop = 1;
 1225 
 1226     /* Read /proc filesystem */
 1227     if (readproc(NO_STAT) < 0) {
 1228         kill(-1, SIGCONT);
 1229         return(1);
 1230     }
 1231 
 1232     /* Now kill all processes except init (pid 1) and our session. */
 1233     sid = (int)getsid(0);
 1234     pid = (int)getpid();
 1235     for (p = plist; p; p = p->next) {
 1236         if (p->pid == 1 || p->pid == pid || p->sid == sid || p->kernel)
 1237             continue;
 1238 
 1239         if (omit) {
 1240             OMIT * optr;
 1241             for (optr = omit; optr; optr = optr->next) {
 1242                 if (optr->pid == p->pid)
 1243                     break;
 1244             }
 1245 
 1246             /* On a match, continue with the for loop above. */
 1247             if (optr)
 1248                 continue;
 1249         }
 1250 
 1251         kill(p->pid, sig);
 1252         retval = 0;
 1253     }
 1254 
 1255     /* And let them continue. */
 1256     kill(-1, SIGCONT);
 1257 
 1258     /* Done. */
 1259     closelog();
 1260 
 1261     /* Force the kernel to run the scheduler */
 1262     usleep(1);
 1263 
 1264     return retval;
 1265 }