changeset 962:194acfd68755

pgrep and pkill by Madhur Verma,
author Rob Landley <rob@landley.net>
date Thu, 25 Jul 2013 13:32:06 -0500
parents d80750c9321f
children 86470ea03bc5
files toys/pending/pgrep.c
diffstat 1 files changed, 164 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/pending/pgrep.c	Thu Jul 25 13:32:06 2013 -0500
@@ -0,0 +1,164 @@
+/* pgrep.c - pgrep and pkill implementation
+ *
+ * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
+ *
+
+USE_PGREP(NEWTOY(pgrep, "?P# s# xvonlf[!sP]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_PGREP(OLDTOY(pkill, pgrep, "?P# s# xvonlf[!sP]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config PGREP
+  bool "pgrep"
+  default n
+  help
+    usage: pgrep [-flnovx] [-s SID|-P PPID|PATTERN]
+           pkill [-l|-SIGNAL] [-fnovx] [-s SID|-P PPID|PATTERN]
+
+    -l  Show command name too / List all signals
+    -f  Match against entire command line
+    -n  Show/Signal the newest process only
+    -o  Show/Signal the oldest process only
+    -v  Negate the match
+    -x  Match whole name (not substring)
+    -s  Match session ID (0 for current)
+    -P  Match parent process ID
+*/
+
+#define FOR_pgrep
+#include "toys.h"
+#include <regex.h>
+
+#define flag_get(f,v,d)   ((toys.optflags & f) ? v : d)
+#define flag_chk(f)       ((toys.optflags & f) ? 1 : 0)
+
+GLOBALS(
+  long sid;       //-s
+  long ppid;      //-P
+  char *signame;
+)
+
+static int exec_action(unsigned pid, char *name, int signal)
+{
+  if (toys.which->name[1] == 'g') {
+    printf("%d", pid);
+    if (flag_chk(FLAG_l)) printf(" %s", name);
+    printf("\n");
+  } else {
+    kill(pid, signal);
+  }
+  return 0;
+}
+
+static int regex_match(regex_t *rp, char *tar, char *patt)
+{
+  regmatch_t rm[1];
+  int len = strlen(tar);
+  if (regexec(rp, tar, 1, rm, 0) == 0) {
+    if (flag_chk(FLAG_x)) {
+      if ((rm[0].rm_so == 0) && ((rm[0].rm_eo - rm[0].rm_so) == len)) return 1;
+    } else return 1;
+  }
+  return 0;
+}
+
+void pgrep_main(void)
+{
+  int signum=0, eval=0, ret=1;
+  DIR *dp=NULL;
+  struct dirent *entry=NULL;
+  regex_t rp;
+  unsigned  pid=0, ppid=0, sid=0, latest_pid=0;
+  char *cmdline=NULL, *latest_cmdline = NULL;
+  pid_t self = getpid();
+
+  if (!(dp = opendir("/proc"))) perror_exit("OPENDIR: failed to open /proc");
+  setlinebuf(stdout);
+
+  if (toys.which->name[1] == 'k') {
+    if (flag_chk(FLAG_l)) {
+      sig_to_num(NULL);
+      return;
+    }
+    if (!TT.signame && *toys.optargs && **toys.optargs == '-') {
+      TT.signame = *(toys.optargs++) + 1;
+    }
+    if (TT.signame) {
+      char *arg;
+      int i = strtol(TT.signame, &arg, 10);
+      if (!*arg) arg = num_to_sig(i);
+      else arg = TT.signame;
+      if (!arg || (signum = sig_to_num(arg)) == -1)
+        error_exit("Unknown signal '%s'", arg);
+    } else signum = SIGTERM;
+  }
+  if (!(flag_chk(FLAG_s) || flag_chk(FLAG_P)) && !*toys.optargs) {
+    toys.exithelp++;
+    error_exit("missing argument");
+  }
+  if (*(toys.optargs+1) && !(flag_chk(FLAG_s) || flag_chk(FLAG_P))) {
+    toys.exithelp++;
+    error_exit("max argument > 1");
+  }
+  if (*toys.optargs) { /* compile regular expression(PATTERN) */
+    if ((eval = regcomp(&rp, *toys.optargs, REG_EXTENDED | REG_NOSUB)) != 0) {
+      char errbuf[256];
+      (void) regerror(eval, &rp, errbuf, sizeof(errbuf));
+      error_exit("%s", errbuf);
+    }
+  }
+  if (flag_chk(FLAG_s)&&(TT.sid==0)) TT.sid = getsid(0);
+  while ((entry = readdir(dp))) {
+    int fd = -1, n = 0;
+    if (!isdigit(*entry->d_name)) continue;
+
+    pid = strtol(entry->d_name, NULL, 10);
+    if (pid == self) continue;
+
+    snprintf(toybuf, sizeof(toybuf), "/proc/%s/cmdline", entry->d_name);
+    if ((fd = open(toybuf, O_RDONLY)) == -1) goto cmdline_fail;
+    n = read(fd, toybuf, sizeof(toybuf));
+    close(fd);
+    toybuf[n--] = '\0';
+    if (n < 0) {
+cmdline_fail:
+      snprintf(toybuf, sizeof(toybuf), "/proc/%s/comm", entry->d_name);
+      if ((fd = open(toybuf, O_RDONLY)) == -1) continue;
+      n = read(fd, toybuf, sizeof(toybuf));
+      close(fd);
+      toybuf[--n] = '\0';
+      if (n < 1) continue;
+    }
+    if (flag_chk(FLAG_f)) {
+      while (--n)
+        if (toybuf[n] < ' ') toybuf[n] = ' ';
+    }
+    if (cmdline) free(cmdline);
+    cmdline = xstrdup(toybuf);
+    if (flag_chk(FLAG_s) || flag_chk(FLAG_P)) {
+      snprintf(toybuf, sizeof(toybuf), "/proc/%s/stat", entry->d_name);
+      if ((fd = open(toybuf, O_RDONLY)) == -1) continue;
+      n = read(fd, toybuf, sizeof(toybuf));
+      close(fd);
+      if (n<1) continue;
+      n = sscanf(toybuf, "%*u %*s %*c %u %*u %u", &ppid, &sid);
+      if (flag_chk(FLAG_s)) if (sid != TT.sid) continue;
+      if (flag_chk(FLAG_P)) if (ppid != TT.ppid) continue;
+    }
+    if (!*toys.optargs || (regex_match(&rp, cmdline, *toys.optargs)^flag_chk(FLAG_v))) {
+      if (flag_chk(FLAG_n)) {
+        if (latest_cmdline) free(latest_cmdline);
+        latest_cmdline = xstrdup(cmdline);
+        latest_pid = pid;
+      } else exec_action(pid, cmdline, signum);
+      ret = 0;
+      if (flag_chk(FLAG_o)) break;
+    }
+  }
+  if (cmdline) free(cmdline);
+  if (latest_cmdline) {
+    exec_action(latest_pid, latest_cmdline, signum);
+    free(latest_cmdline);
+  }
+  if (*toys.optargs) regfree(&rp);
+  closedir(dp);
+  toys.exitval = ret;
+}