Default to returning only this user's processes (unless root), and
[sgt/utils] / pid / pid.c
index a43274e..9d5c901 100644 (file)
--- a/pid/pid.c
+++ b/pid/pid.c
@@ -247,11 +247,9 @@ static struct pidset get_processes(void)
         }
 
         sprintf(filename, "/proc/%d/exe", pid);
-        if ((exe = get_link_dest(filename)) == NULL) {
-            free(cmdline);
-            free(status);
-            continue;
-        }
+        exe = get_link_dest(filename);
+        /* This may fail, if the process isn't ours, but we continue
+         * anyway. */
 
         /*
          * Now we've got all our raw data out of /proc. Process it
@@ -414,6 +412,18 @@ static int find_command(int pid_argc, const char *const *pid_argv,
     return -1;                         /* no match */
 }
 
+static int strnullcmp(const char *a, const char *b)
+{
+    /*
+     * Like strcmp, but cope with NULL inputs by making them compare
+     * identical to each other and before any non-null string.
+     */
+    if (!a || !b)
+        return (b != 0) - (a != 0);
+    else
+        return strcmp(a, b);
+}
+
 static int argcmp(const char *const *a, const char *const *b)
 {
     while (*a && *b) {
@@ -445,6 +455,23 @@ static struct pidset filter_out_self(struct pidset in)
     return ret;
 }
 
+static struct pidset filter_by_uid(struct pidset in, int uid)
+{
+    /*
+     * Return only those processes with a given uid.
+     */
+    struct pidset ret;
+    int pid;
+
+    pidset_init(&ret);
+    for (pid = pidset_first(&in); pid >= 0; pid = pidset_next(&in)) {
+        const struct procdata *proc = get_proc(pid);
+        if (proc->uid == uid)
+            pidset_add(&ret, pid);
+    }
+    return ret;
+}
+
 static struct pidset filter_by_command(struct pidset in, const char **words)
 {
     /*
@@ -498,7 +525,7 @@ static struct pidset filter_out_forks(struct pidset in)
         if (pidset_in(&in, proc->ppid)) {
             /* The parent is in our set too. Is it similar? */
             const struct procdata *parent = get_proc(proc->ppid);
-            if (!strcmp(parent->exe, proc->exe) &&
+            if (!strnullcmp(parent->exe, proc->exe) &&
                 !argcmp(parent->argv, proc->argv)) {
                 /* Yes; don't list it. */
                 continue;
@@ -517,6 +544,7 @@ static struct pidset filter_out_forks(struct pidset in)
 const char usagemsg[] =
     "usage: pid [options] <search-cmd> [<search-arg>...]\n"
     "where: -a                 report all matching pids, not just one\n"
+    "       -U                 report pids of any user, not just ours\n"
     " also: pid --version      report version number\n"
     "       pid --help         display this help text\n"
     "       pid --licence      display the (MIT) licence text\n"
@@ -577,7 +605,7 @@ int main(int argc, char **argv)
 {
     const char **searchwords;
     int nsearchwords;
-    int all = 0;
+    int all = 0, all_uids = 0;
     int doing_opts = 1;
 
     /*
@@ -596,6 +624,8 @@ int main(int argc, char **argv)
         if (doing_opts && *p == '-') {
             if (!strcmp(p, "-a") || !strcmp(p, "--all")) {
                 all = 1;
+            } else if (!strcmp(p, "-U") || !strcmp(p, "--all-uids")) {
+                all_uids = 1;
             } else if (!strcmp(p, "--version")) {
                 version();
                 return 0;
@@ -626,11 +656,14 @@ int main(int argc, char **argv)
 
     {
         struct pidset procs;
-        int pid, npids;
+        int uid, pid, npids;
         /*
          * Construct our list of processes.
          */
         procs = get_processes();
+        uid = getuid();
+        if (uid > 0 && !all_uids)
+            procs = filter_by_uid(procs, uid);
         procs = filter_out_self(procs);
         procs = filter_by_command(procs, searchwords);
         if (!all)