1fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley/* pgrep.c - pgrep and pkill implementation
2fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley *
3fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
41c8b0090a6529ce35f877973778e7814387c1e3fRob Landley * Copyright 2013 Kyungwan Han <asura321@gmail.com>
5fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley *
6fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
7fe850691155be9a23cc1480e7afdb77028d87e78Rob LandleyUSE_PGREP(NEWTOY(pgrep, "?P# s# xvonlf[!sP]", TOYFLAG_USR|TOYFLAG_BIN))
8f3e56f4e4ff773de95fa2c9daf979734d826fc33Rob LandleyUSE_PGREP(OLDTOY(pkill, pgrep, TOYFLAG_USR|TOYFLAG_BIN))
9fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
10fe850691155be9a23cc1480e7afdb77028d87e78Rob Landleyconfig PGREP
11fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  bool "pgrep"
12fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  default n
13fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  help
14fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    usage: pgrep [-flnovx] [-s SID|-P PPID|PATTERN]
15fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley           pkill [-l|-SIGNAL] [-fnovx] [-s SID|-P PPID|PATTERN]
16fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
17fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    -l  Show command name too / List all signals
18fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    -f  Match against entire command line
19fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    -n  Show/Signal the newest process only
20fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    -o  Show/Signal the oldest process only
21fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    -v  Negate the match
22fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    -x  Match whole name (not substring)
23fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    -s  Match session ID (0 for current)
24fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    -P  Match parent process ID
25fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley*/
26fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
27fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley#define FOR_pgrep
28fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley#include "toys.h"
29fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley#include <regex.h>
30fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
31fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley#define flag_get(f,v,d)   ((toys.optflags & f) ? v : d)
32fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley#define flag_chk(f)       ((toys.optflags & f) ? 1 : 0)
33fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
34fe850691155be9a23cc1480e7afdb77028d87e78Rob LandleyGLOBALS(
35fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  long sid;       //-s
36fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  long ppid;      //-P
37fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  char *signame;
38fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley)
39fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
40fe850691155be9a23cc1480e7afdb77028d87e78Rob Landleystatic int exec_action(unsigned pid, char *name, int signal)
41fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley{
42fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (toys.which->name[1] == 'g') {
43fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    printf("%d", pid);
44fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (flag_chk(FLAG_l)) printf(" %s", name);
45fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    printf("\n");
46fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  } else {
47fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    kill(pid, signal);
48fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  }
49fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  return 0;
50fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley}
51fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
52fe850691155be9a23cc1480e7afdb77028d87e78Rob Landleystatic int regex_match(regex_t *rp, char *tar, char *patt)
53fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley{
54fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  regmatch_t rm[1];
55fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  int len = strlen(tar);
56fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (regexec(rp, tar, 1, rm, 0) == 0) {
57fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (flag_chk(FLAG_x)) {
58fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if ((rm[0].rm_so == 0) && ((rm[0].rm_eo - rm[0].rm_so) == len)) return 1;
59fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    } else return 1;
60fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  }
61fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  return 0;
62fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley}
63fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
64fe850691155be9a23cc1480e7afdb77028d87e78Rob Landleyvoid pgrep_main(void)
65fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley{
66fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  int signum=0, eval=0, ret=1;
67fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  DIR *dp=NULL;
68fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  struct dirent *entry=NULL;
69fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  regex_t rp;
70fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  unsigned  pid=0, ppid=0, sid=0, latest_pid=0;
71fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  char *cmdline=NULL, *latest_cmdline = NULL;
72fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  pid_t self = getpid();
73fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
74fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (!(dp = opendir("/proc"))) perror_exit("OPENDIR: failed to open /proc");
75fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  setlinebuf(stdout);
76fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
77fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (toys.which->name[1] == 'k') {
78fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (flag_chk(FLAG_l)) {
79fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      sig_to_num(NULL);
80fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      return;
81fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    }
82fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (!TT.signame && *toys.optargs && **toys.optargs == '-') {
83fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      TT.signame = *(toys.optargs++) + 1;
84fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    }
85fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (TT.signame) {
86fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      char *arg;
87fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      int i = strtol(TT.signame, &arg, 10);
88fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if (!*arg) arg = num_to_sig(i);
89fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      else arg = TT.signame;
90fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if (!arg || (signum = sig_to_num(arg)) == -1)
91fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley        error_exit("Unknown signal '%s'", arg);
92fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    } else signum = SIGTERM;
93fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  }
94fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (!(flag_chk(FLAG_s) || flag_chk(FLAG_P)) && !*toys.optargs) {
95fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    toys.exithelp++;
96fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    error_exit("missing argument");
97fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  }
98fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (*(toys.optargs+1) && !(flag_chk(FLAG_s) || flag_chk(FLAG_P))) {
99fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    toys.exithelp++;
100fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    error_exit("max argument > 1");
101fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  }
102fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (*toys.optargs) { /* compile regular expression(PATTERN) */
103fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if ((eval = regcomp(&rp, *toys.optargs, REG_EXTENDED | REG_NOSUB)) != 0) {
104fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      char errbuf[256];
105fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      (void) regerror(eval, &rp, errbuf, sizeof(errbuf));
106fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      error_exit("%s", errbuf);
107fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    }
108fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  }
109fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (flag_chk(FLAG_s)&&(TT.sid==0)) TT.sid = getsid(0);
110fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  while ((entry = readdir(dp))) {
111fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    int fd = -1, n = 0;
112fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (!isdigit(*entry->d_name)) continue;
113fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
114fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    pid = strtol(entry->d_name, NULL, 10);
115fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (pid == self) continue;
116fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley
117fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    snprintf(toybuf, sizeof(toybuf), "/proc/%s/cmdline", entry->d_name);
118fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if ((fd = open(toybuf, O_RDONLY)) == -1) goto cmdline_fail;
119fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    n = read(fd, toybuf, sizeof(toybuf));
120fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    close(fd);
121fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    toybuf[n--] = '\0';
122fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (n < 0) {
123fe850691155be9a23cc1480e7afdb77028d87e78Rob Landleycmdline_fail:
124fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      snprintf(toybuf, sizeof(toybuf), "/proc/%s/comm", entry->d_name);
125fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if ((fd = open(toybuf, O_RDONLY)) == -1) continue;
126fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      n = read(fd, toybuf, sizeof(toybuf));
127fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      close(fd);
128fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      toybuf[--n] = '\0';
129fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if (n < 1) continue;
130fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    }
131fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (flag_chk(FLAG_f)) {
132fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      while (--n)
133fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley        if (toybuf[n] < ' ') toybuf[n] = ' ';
134fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    }
135fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (cmdline) free(cmdline);
136fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    cmdline = xstrdup(toybuf);
137fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (flag_chk(FLAG_s) || flag_chk(FLAG_P)) {
138fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      snprintf(toybuf, sizeof(toybuf), "/proc/%s/stat", entry->d_name);
139fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if ((fd = open(toybuf, O_RDONLY)) == -1) continue;
140fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      n = read(fd, toybuf, sizeof(toybuf));
141fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      close(fd);
142fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if (n<1) continue;
143fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      n = sscanf(toybuf, "%*u %*s %*c %u %*u %u", &ppid, &sid);
144fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if (flag_chk(FLAG_s)) if (sid != TT.sid) continue;
145fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if (flag_chk(FLAG_P)) if (ppid != TT.ppid) continue;
146fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    }
147fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    if (!*toys.optargs || (regex_match(&rp, cmdline, *toys.optargs)^flag_chk(FLAG_v))) {
148fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if (flag_chk(FLAG_n)) {
149fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley        if (latest_cmdline) free(latest_cmdline);
150fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley        latest_cmdline = xstrdup(cmdline);
151fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley        latest_pid = pid;
152fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      } else exec_action(pid, cmdline, signum);
153fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      ret = 0;
154fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley      if (flag_chk(FLAG_o)) break;
155fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    }
156fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  }
157fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (cmdline) free(cmdline);
158fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (latest_cmdline) {
159fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    exec_action(latest_pid, latest_cmdline, signum);
160fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley    free(latest_cmdline);
161fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  }
162fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  if (*toys.optargs) regfree(&rp);
163fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  closedir(dp);
164fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley  toys.exitval = ret;
165fe850691155be9a23cc1480e7afdb77028d87e78Rob Landley}
166