Get more help from gcc, add -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2...
[sysvinit.git] / src / killall5.c
index 6696119f391946295ce95d39c4095ba261f7ee3f..187255598df3030a7fce410788d6aa6e30ecf5e4 100644 (file)
@@ -43,6 +43,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <getopt.h>
+#include <limits.h>
 #include <mntent.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl";
 
+#ifndef PATH_MAX
+#  ifdef MAXPATHLEN
+#    define PATH_MAX MAXPATHLEN
+#  else
+#    define PATH_MAX 2048
+#  endif
+#endif
+
 #define STATNAMELEN    15
 #define DO_NETFS 2
 #define DO_STAT 1
@@ -66,6 +75,7 @@ char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl";
 
 /* Info about a process. */
 typedef struct proc {
+       char *pathname;         /* full path to executable        */
        char *argv0;            /* Name as found out from argv[0] */
        char *argv0base;        /* `basename argv[1]`             */
        char *argv1;            /* Name as found out from argv[1] */
@@ -112,8 +122,8 @@ 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;
+       char * name;
 } NFS;
 
 /* List of processes. */
@@ -197,8 +207,8 @@ int mount_proc(void)
                }
                if (pid == 0) {
                        /* Try a few mount binaries. */
-                       execv("/sbin/mount", args);
                        execv("/bin/mount", args);
+                       execv("/sbin/mount", args);
 
                        /* Okay, I give up. */
                        nsyslog(LOG_ERR, "cannot execute mount");
@@ -346,7 +356,7 @@ static void clear_mnt(void)
 }
 
 /*
- *     Check if path is ia shadow off a NFS partition.
+ *     Check if path is a shadow off a NFS partition.
  */
 static int shadow(SHADOW *restrict this, const char *restrict name, const size_t nlen)
 {
@@ -366,6 +376,20 @@ out:
        return 0;
 }
 
+/*
+ * Get the maximal number of symlinks to follow.  Use sysconf() on
+ * Hurd where the hardcoded value MAXSYMLINKS is not available.
+ */
+static int maxsymlinks(void)
+{
+       int v = sysconf(_SC_SYMLOOP_MAX);
+#ifdef MAXSYMLINKS
+       if (v == -1)
+               return MAXSYMLINKS;
+#endif
+       return v;
+}
+
 /*
  *     Check path is located on a network based partition.
  */
@@ -373,7 +397,7 @@ int check4nfs(const char * path, char * real)
 {
        char buf[PATH_MAX+1];
        const char *curr;
-       int deep = MAXSYMLINKS;
+       int deep = maxsymlinks();
 
        if (!nlist) return 0;
 
@@ -454,11 +478,12 @@ int readproc(int do_stat)
        PROC            *p, *n;
        struct dirent   *d;
        struct stat     st;
-       char            path[256];
-       char            buf[256];
+       char            path[PATH_MAX+1];
+       char            buf[PATH_MAX+1];
        char            *s, *q;
        unsigned long   startcode, endcode;
        int             pid, f;
+       ssize_t         len;
 
        /* Open the /proc directory. */
        if (chdir("/proc") == -1) {
@@ -477,6 +502,7 @@ int readproc(int do_stat)
                if (p->argv0) free(p->argv0);
                if (p->argv1) free(p->argv1);
                if (p->statname) free(p->statname);
+               free(p->pathname);
                free(p);
        }
        plist = NULL;
@@ -496,13 +522,23 @@ int readproc(int do_stat)
 
                /* Read SID & statname from it. */
                if ((fp = fopen(path, "r")) != NULL) {
-                       buf[0] = 0;
-                       fgets(buf, sizeof(buf), fp);
+                       size_t len;
+
+                       len = fread(buf, sizeof(char), sizeof(buf)-1, fp);
+                       buf[len] = '\0';
+
+                       if (buf[0] == '\0') {
+                               nsyslog(LOG_ERR,
+                                       "can't read from %s\n", path);
+                               fclose(fp);
+                               free(p);
+                               continue;
+                       }
 
                        /* See if name starts with '(' */
                        s = buf;
-                       while (*s != ' ') s++;
-                       s++;
+                       while (*s && *s != ' ') s++;
+                       if (*s) s++;
                        if (*s == '(') {
                                /* Read program name. */
                                q = strrchr(buf, ')');
@@ -511,18 +547,20 @@ int readproc(int do_stat)
                                        nsyslog(LOG_ERR,
                                        "can't get program name from /proc/%s\n",
                                                path);
+                                       fclose(fp);
                                        if (p->argv0) free(p->argv0);
                                        if (p->argv1) free(p->argv1);
                                        if (p->statname) free(p->statname);
+                                       free(p->pathname);
                                        free(p);
                                        continue;
                                }
                                s++;
                        } else {
                                q = s;
-                               while (*q != ' ') q++;
+                               while (*q && *q != ' ') q++;
                        }
-                       *q++ = 0;
+                       if (*q) *q++ = 0;
                        while (*q == ' ') q++;
                        p->statname = (char *)xmalloc(strlen(s)+1);
                        strcpy(p->statname, s);
@@ -537,9 +575,11 @@ int readproc(int do_stat)
                                p->sid = 0;
                                nsyslog(LOG_ERR, "can't read sid from %s\n",
                                        path);
+                               fclose(fp);
                                if (p->argv0) free(p->argv0);
                                if (p->argv1) free(p->argv1);
                                if (p->statname) free(p->statname);
+                               free(p->pathname);
                                free(p);
                                continue;
                        }
@@ -551,6 +591,7 @@ int readproc(int do_stat)
                        if (p->argv0) free(p->argv0);
                        if (p->argv1) free(p->argv1);
                        if (p->statname) free(p->statname);
+                       free(p->pathname);
                        free(p);
                        continue;
                }
@@ -598,6 +639,7 @@ int readproc(int do_stat)
                        if (p->argv0) free(p->argv0);
                        if (p->argv1) free(p->argv1);
                        if (p->statname) free(p->statname);
+                       free(p->pathname);
                        free(p);
                        continue;
                }
@@ -610,13 +652,46 @@ int readproc(int do_stat)
                switch (do_stat) {
                case DO_NETFS:
                        if ((p->nfs = check4nfs(path, buf)))
-                               break;
+                               goto link;
                case DO_STAT:
-                       if (stat(path, &st) != 0)
+                       if (stat(path, &st) != 0) {
+                               char * ptr;
+
+                               len = readlink(path, buf, PATH_MAX);
+                               if (len <= 0)
+                                       break;
+                               buf[len] = '\0';
+
+                               ptr = strstr(buf, " (deleted)");
+                               if (!ptr)
+                                       break;
+                               *ptr = '\0';
+                               len -= strlen(" (deleted)");
+
+                               if (stat(buf, &st) != 0)
+                                       break;
+                               p->dev = st.st_dev;
+                               p->ino = st.st_ino;
+                               p->pathname = (char *)xmalloc(len + 1);
+                               memcpy(p->pathname, buf, len);
+                               p->pathname[len] = '\0';
+
+                               /* All done */
                                break;
+                       }
+
                        p->dev = st.st_dev;
                        p->ino = st.st_ino;
+
+                       /* Fall through */
                default:
+               link:
+                       len = readlink(path, buf, PATH_MAX);
+                       if (len > 0) {
+                               p->pathname = (char *)xmalloc(len + 1);
+                               memcpy(p->pathname, buf, len);
+                               p->pathname[len] = '\0';
+                       }
                        break;
                }
 
@@ -687,6 +762,7 @@ PIDQ_HEAD *pidof(char *prog)
        int             dostat = 0;
        int             foundone = 0;
        int             ok = 0;
+       const int       root = (getuid() == 0);
        char            real[PATH_MAX+1];
 
        if (! prog)
@@ -734,16 +810,11 @@ PIDQ_HEAD *pidof(char *prog)
         * 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;
+                       if (!p->pathname)
+                               continue;
                        if (!p->nfs)
                                continue;
-                       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)
+                       if (strcmp(prog, p->pathname) != 0)
                                continue;
                        add_pid_to_q(q, p);
                        foundone++;
@@ -752,6 +823,32 @@ PIDQ_HEAD *pidof(char *prog)
 
        /* If we didn't find a match based on dev/ino, try the name. */
        if (!foundone) for (p = plist; p; p = p->next) {
+               if (prog[0] == '/') {
+                       if (!p->pathname) {
+                               if (root)
+                                       continue;
+                               goto fallback; 
+                       }
+                       if (strcmp(prog, p->pathname)) {
+                               int len = strlen(prog);
+                               if (strncmp(prog, p->pathname, len))
+                               {
+                                       if (scripts_too)
+                                               goto fallback;
+                                       continue;
+                               }
+                               if (strcmp(" (deleted)", p->pathname + len))
+                               {
+                                       if (scripts_too)
+                                               goto fallback;
+                                       continue;
+                               }
+                       }
+                       add_pid_to_q(q, p);
+                       continue;
+               }
+
+       fallback:
                ok = 0;
 
                /*             matching        nonmatching