| /* pgrep.c - pgrep and pkill implementation |
| * |
| * Copyright 2012 Madhur Verma <mad.flexi@gmail.com> |
| * Copyright 2013 Kyungwan Han <asura321@gmail.com> |
| * |
| |
| USE_PGREP(NEWTOY(pgrep, "?P# s# xvonlf[!sP]", TOYFLAG_USR|TOYFLAG_BIN)) |
| USE_PGREP(OLDTOY(pkill, pgrep, OPTSTR_pgrep, 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; |
| } |