udhcpc: code shrink
[oweals/busybox.git] / procps / pgrep.c
index 327f6a934a5021b81d52c886dad0dfee6fbae262..a16a6e959ccce1b6ebd075d780ec3dda24350126 100644 (file)
 //config:      help
 //config:      Send signals to processes by name.
 
-//applet:IF_PGREP(APPLET(pgrep, BB_DIR_USR_BIN, BB_SUID_DROP))
+//applet:IF_PGREP(APPLET_ODDNAME(pgrep, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pgrep))
 //                APPLET_ODDNAME:name   main   location        suid_type     help
 //applet:IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill))
+/* can't be noexec: can find _itself_ under wrong name, since after fork only,
+ * /proc/PID/cmdline and comm are wrong! Can fix comm (prctl(PR_SET_NAME)),
+ * but cmdline?
+ */
 
 //kbuild:lib-$(CONFIG_PGREP) += pgrep.o
 //kbuild:lib-$(CONFIG_PKILL) += pgrep.o
@@ -155,15 +159,18 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv)
        proc = NULL;
        while ((proc = procps_scan(proc, scan_mask)) != NULL) {
                char *cmd;
-               int cmdlen;
+               int cmdlen, match;
 
                if (proc->pid == pid)
                        continue;
 
-               if (ppid2match >= 0 && ppid2match != proc->ppid)
-                       continue;
-               if (sid2match >= 0 && sid2match != proc->sid)
-                       continue;
+               if (!OPT_INVERT) {
+                       /* Quickly reject -sN -PN mismatches... unless -v */
+                       if (ppid2match >= 0 && ppid2match != proc->ppid)
+                               continue;
+                       if (sid2match >= 0 && sid2match != proc->sid)
+                               continue;
+               }
 
                cmdlen = -1;
                cmd = proc->argv0;
@@ -186,12 +193,36 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv)
                        }
                }
 
+               if (OPT_INVERT) {
+                       /* "pgrep -v -P1 firefox" means "not (ppid=1 AND name=firefox)"
+                        * or equivalently "ppid!=1 OR name!=firefox".
+                        * Check the first condition and if true, skip matching.
+                        */
+                       if (ppid2match >= 0 && ppid2match != proc->ppid)
+                               goto got_it;
+                       if (sid2match >= 0 && sid2match != proc->sid)
+                               goto got_it;
+               }
+
+               match = !argv[0]; /* if no PATTERN, then it's a match, else... */
+               if (!match) {
+ again:
+                       match = (regexec(&re_buffer, cmd, 1, re_match, 0) == 0);
+                       if (!match && cmd != proc->comm) {
+                               /* if argv[] did not match, try comm */
+                               cmdlen = -1;
+                               cmd = proc->comm;
+                               goto again;
+                       }
+                       if (match && OPT_ANCHOR) {
+                               /* -x requires full string match */
+                               match = (re_match[0].rm_so == 0 && cmd[re_match[0].rm_eo] == '\0');
+                       }
+               }
+
                /* NB: OPT_INVERT is always 0 or 1 */
-               if (!argv[0]
-                || (regexec(&re_buffer, cmd, 1, re_match, 0) == 0 /* match found */
-                   && (!OPT_ANCHOR || (re_match[0].rm_so == 0 && re_match[0].rm_eo == (regoff_t)strlen(cmd)))
-                   ) ^ OPT_INVERT
-               ) {
+               if (match ^ OPT_INVERT) {
+ got_it:
                        matched_pid = proc->pid;
                        if (OPT_LAST) {
                                free(cmd_last);