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