Before this patch, we're effectively doing `pidof -x` all the time. This
patch changes names_to_pid() to allow us to say whether or not we want to
include scripts, and adjusts the callers appropriately.

Also add tests for `pidof` versus `pidof -x` which pass after this
patch, without regressing the existing killall tests.
---
 lib/lib.c                 | 21 ++++++++++++---------
 lib/lib.h                 |  3 ++-
 tests/pidof.test          | 33 +++++++++++++++++++++++++++++++++
 toys/lsb/killall.c        |  2 +-
 toys/lsb/pidof.c          |  5 +++--
 toys/pending/bootchartd.c | 38 ++++++++++++--------------------------
 6 files changed, 63 insertions(+), 39 deletions(-)
 create mode 100644 tests/pidof.test
From 809705c6846e550dbaa96f2515bd45bb772e24d0 Mon Sep 17 00:00:00 2001
From: Elliott Hughes <[email protected]>
Date: Thu, 11 Jul 2019 14:00:07 -0700
Subject: [PATCH] pidof: fix default behavior, add -x.

Before this patch, we're effectively doing `pidof -x` all the time. This
patch changes names_to_pid() to allow us to say whether or not we want to
include scripts, and adjusts the callers appropriately.

Also add tests for `pidof` versus `pidof -x` which pass after this
patch, without regressing the existing killall tests.
---
 lib/lib.c                 | 21 ++++++++++++---------
 lib/lib.h                 |  3 ++-
 tests/pidof.test          | 33 +++++++++++++++++++++++++++++++++
 toys/lsb/killall.c        |  2 +-
 toys/lsb/pidof.c          |  5 +++--
 toys/pending/bootchartd.c | 38 ++++++++++++--------------------------
 6 files changed, 63 insertions(+), 39 deletions(-)
 create mode 100644 tests/pidof.test

diff --git a/lib/lib.c b/lib/lib.c
index e00278c5..47e5ca21 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -1041,7 +1041,8 @@ char *fileunderdir(char *file, char *dir)
 }
 
 // Execute a callback for each PID that matches a process name from a list.
-void names_to_pid(char **names, int (*callback)(pid_t pid, char *name))
+void names_to_pid(char **names, int (*callback)(pid_t pid, char *name),
+    int scripts)
 {
   DIR *dp;
   struct dirent *entry;
@@ -1050,18 +1051,20 @@ void names_to_pid(char **names, int (*callback)(pid_t pid, char *name))
 
   while ((entry = readdir(dp))) {
     unsigned u = atoi(entry->d_name);
-    char *cmd = 0, *comm, **cur;
+    char *cmd = 0, *comm = 0, **cur;
     off_t len;
 
     if (!u) continue;
 
     // Comm is original name of executable (argv[0] could be #! interpreter)
     // but it's limited to 15 characters
-    sprintf(libbuf, "/proc/%u/comm", u);
-    len = sizeof(libbuf);
-    if (!(comm = readfileat(AT_FDCWD, libbuf, libbuf, &len)) || !len)
-      continue;
-    if (libbuf[len-1] == '\n') libbuf[--len] = 0;
+    if (scripts) {
+      sprintf(libbuf, "/proc/%u/comm", u);
+      len = sizeof(libbuf);
+      if (!(comm = readfileat(AT_FDCWD, libbuf, libbuf, &len)) || !len)
+        continue;
+      if (libbuf[len-1] == '\n') libbuf[--len] = 0;
+    }
 
     for (cur = names; *cur; cur++) {
       struct stat st1, st2;
@@ -1071,7 +1074,7 @@ void names_to_pid(char **names, int (*callback)(pid_t pid, char *name))
       // Fast path: only matching a filename (no path) that fits in comm.
       // `len` must be 14 or less because with a full 15 bytes we don't
       // know whether the name fit or was truncated.
-      if (len<=14 && bb==*cur && !strcmp(comm, bb)) goto match;
+      if (scripts && len<=14 && bb==*cur && !strcmp(comm, bb)) goto match;
 
       // If we have a path to existing file only match if same inode
       if (bb!=*cur && !stat(*cur, &st1)) {
@@ -1093,7 +1096,7 @@ void names_to_pid(char **names, int (*callback)(pid_t pid, char *name))
         cmd[len] = 0;
       }
       if (!strcmp(bb, getbasename(cmd))) goto match;
-      if (!strcmp(bb, getbasename(cmd+strlen(cmd)+1))) goto match;
+      if (scripts && !strcmp(bb, getbasename(cmd+strlen(cmd)+1))) goto match;
       continue;
 match:
       if (callback(u, *cur)) break;
diff --git a/lib/lib.h b/lib/lib.h
index e354a82a..5b48d997 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -399,7 +399,8 @@ void mode_to_string(mode_t mode, char *buf);
 char *getdirname(char *name);
 char *getbasename(char *name);
 char *fileunderdir(char *file, char *dir);
-void names_to_pid(char **names, int (*callback)(pid_t pid, char *name));
+void names_to_pid(char **names, int (*callback)(pid_t pid, char *name),
+    int scripts);
 
 pid_t __attribute__((returns_twice)) xvforkwrap(pid_t pid);
 #define XVFORK() xvforkwrap(vfork())
diff --git a/tests/pidof.test b/tests/pidof.test
new file mode 100644
index 00000000..7de31fc2
--- /dev/null
+++ b/tests/pidof.test
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+#
+# pidof (unlike killall) doesn't match argv[1] unless you supply -x.
+#
+
+echo "#!$(which sh)
+while true; do
+  sleep 0.1
+done" > toybox.pidof.test.script
+chmod a+x toybox.pidof.test.script
+cp toybox.pidof.test.script pidof.test
+
+./pidof.test &
+pid=$!
+testcmd "short argv[1]" "pidof.test" "" "" ""
+testcmd "short argv[1] -x" "-x pidof.test" "$pid\n" "" ""
+kill $pid
+
+./toybox.pidof.test.script &
+pid=$!
+testcmd "long argv[1]" "toybox.pidof.test.script" "" "" ""
+testcmd "long argv[1] -x" "-x toybox.pidof.test.script" "$pid\n" "" ""
+kill $pid
+
+rm -f toybox.pidof.test.script toybox.test
+
+# pidof (unlike killall) will match itself.
+testcmd "pidof pidof" "pidof > /dev/null && echo found" "found\n" "" ""
diff --git a/toys/lsb/killall.c b/toys/lsb/killall.c
index 47aea23d..c81360b1 100644
--- a/toys/lsb/killall.c
+++ b/toys/lsb/killall.c
@@ -89,7 +89,7 @@ void killall_main(void)
 
   TT.err = xmalloc(2*toys.optc);
   for (i=0; i<toys.optc; i++) TT.err[i] = ESRCH;
-  names_to_pid(TT.names, kill_process);
+  names_to_pid(TT.names, kill_process, 1);
   for (i=0; i<toys.optc; i++) {
     if (TT.err[i]) {
       toys.exitval = 1;
diff --git a/toys/lsb/pidof.c b/toys/lsb/pidof.c
index 4f266b84..cd705a7c 100644
--- a/toys/lsb/pidof.c
+++ b/toys/lsb/pidof.c
@@ -5,7 +5,7 @@
  *
  * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/pidof.html
 
-USE_PIDOF(NEWTOY(pidof, "<1so:", TOYFLAG_BIN))
+USE_PIDOF(NEWTOY(pidof, "<1so:x", TOYFLAG_BIN))
 
 config PIDOF
   bool "pidof"
@@ -17,6 +17,7 @@ config PIDOF
 
     -s	Single shot, only return one pid
     -o	Omit PID(s)
+    -x	Match shell scripts too
 */
 
 #define FOR_pidof
@@ -39,6 +40,6 @@ static int print_pid(pid_t pid, char *name)
 void pidof_main(void)
 {
   toys.exitval = 1;
-  names_to_pid(toys.optargs, print_pid);
+  names_to_pid(toys.optargs, print_pid, FLAG(x));
   if (!toys.exitval) xputc('\n');
 }
diff --git a/toys/pending/bootchartd.c b/toys/pending/bootchartd.c
index 7e5a136f..1fe6aff6 100644
--- a/toys/pending/bootchartd.c
+++ b/toys/pending/bootchartd.c
@@ -34,24 +34,9 @@ GLOBALS(
   int proc_accounting;
   int is_login;
 
-  void *head;
+  pid_t cur_pid;
 )
 
-struct pid_list {
-  struct pid_list *next, *prev;
-  int pid;
-};
-
-static int push_pids_in_list(pid_t pid, char *name)
-{
-  struct pid_list *new = xzalloc(sizeof(struct pid_list));
-
-  new->pid = pid;
-  dlist_add_nomalloc((void *)&TT.head, (void *)new);
-
-  return 0;
-}
-
 static void dump_data_in_file(char *fname, int wfd)
 {
   int rfd = open(fname, O_RDONLY);
@@ -253,13 +238,21 @@ static void stop_logging(char *tmp_dir, char *prog)
   }
 }
 
+static int signal_pid(pid_t pid, char *name)
+{
+  if (pid != TT.cur_pid) kill(pid, SIGUSR1);
+  return 0;
+}
+
 void bootchartd_main()
 {
-  pid_t lgr_pid, self_pid = getpid();
+  pid_t lgr_pid;
   int bchartd_opt = 0; // 0=PID1, 1=start, 2=stop, 3=init
+
+  TT.cur_pid = getpid();
   TT.smpl_period_usec = 200 * 1000;
 
-  TT.is_login = (self_pid == 1);
+  TT.is_login = (TT.cur_pid == 1);
   if (*toys.optargs) {
     if (!strcmp("start", *toys.optargs)) bchartd_opt = 1;
     else if (!strcmp("stop", *toys.optargs)) bchartd_opt = 2;
@@ -267,16 +260,9 @@ void bootchartd_main()
     else error_exit("Unknown option '%s'", *toys.optargs);
 
     if (bchartd_opt == 2) {
-      struct pid_list *temp;
       char *process_name[] = {"bootchartd", NULL};
 
-      names_to_pid(process_name, push_pids_in_list);
-      temp = TT.head;
-      if (temp) temp->prev->next = 0;
-      for (; temp; temp = temp->next) 
-        if (temp->pid != self_pid) kill(temp->pid, SIGUSR1);
-      llist_traverse(TT.head, free);
-
+      names_to_pid(process_name, signal_pid, 0);
       return;
     }
   } else if (!TT.is_login) error_exit("not PID 1");
-- 
2.22.0.410.gd8fdbe21b5-goog

_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to