aboutsummaryrefslogtreecommitdiff
path: root/toys
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2016-01-14 23:18:15 -0600
committerRob Landley <rob@landley.net>2016-01-14 23:18:15 -0600
commit7d4d0421b8e57bd6d9a9cb3dee04130b43bc53a0 (patch)
treedeed9e3333128f5364719cfdde96b9095ca4495f /toys
parent192155553c01f39a774d169cb3b28dc5c7417c08 (diff)
downloadtoybox-7d4d0421b8e57bd6d9a9cb3dee04130b43bc53a0.tar.gz
Implement most of pgrep and pkill.
Needs testing and a few more options connected up.
Diffstat (limited to 'toys')
-rw-r--r--toys/pending/pgrep.c159
-rw-r--r--toys/posix/ps.c161
2 files changed, 145 insertions, 175 deletions
diff --git a/toys/pending/pgrep.c b/toys/pending/pgrep.c
deleted file mode 100644
index 8c115fff..00000000
--- a/toys/pending/pgrep.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/* 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, 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"
-
-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 (toys.optflags&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 (toys.optflags&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 = 0;
- struct dirent *entry = 0;
- regex_t rp;
- unsigned pid = 0, ppid = 0, sid = 0, latest_pid = 0;
- char *cmdline = 0, *latest_cmdline = 0;
- pid_t self = getpid();
-
- if (!(dp = opendir("/proc"))) perror_exit("OPENDIR: failed to open /proc");
- setlinebuf(stdout);
-
- // pkill
- if (toys.which->name[1] == 'k') {
- if (toys.optflags&FLAG_l) {
- sig_to_num(0);
-
- return;
- }
-// note: "pkill -" on ubuntu uses "-" as the pattern, this would error instead
- if (*toys.optargs && **toys.optargs == '-') {
- char *arg;
- int i = strtol(TT.signame = *(toys.optargs++)+1, &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 (!(toys.optflags&(FLAG_s|FLAG_P)) && !*toys.optargs)
- help_exit("missing argument");
- if (toys.optargs[1] && !(toys.optflags&(FLAG_s|FLAG_P)))
- help_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 ((toys.optflags&FLAG_s) && !TT.sid) 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 (toys.optflags & FLAG_f) {
- while (--n)
- if (toybuf[n] < ' ') toybuf[n] = ' ';
- }
- if (cmdline) free(cmdline);
- cmdline = xstrdup(toybuf);
- if (toys.optflags&(FLAG_s|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 ((toys.optflags&FLAG_s) && sid != TT.sid) continue;
- if ((toys.optflags&FLAG_P) && ppid != TT.ppid) continue;
- }
- if (!*toys.optargs || (regex_match(&rp, cmdline, *toys.optargs)^!!(toys.optflags&FLAG_v))) {
- if (toys.optflags&FLAG_n) {
- if (latest_cmdline) free(latest_cmdline);
- latest_cmdline = xstrdup(cmdline);
- latest_pid = pid;
- } else exec_action(pid, cmdline, signum);
- ret = 0;
- if (toys.optflags&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;
-}
diff --git a/toys/posix/ps.c b/toys/posix/ps.c
index cc07042e..8dbc0984 100644
--- a/toys/posix/ps.c
+++ b/toys/posix/ps.c
@@ -32,13 +32,15 @@
* TODO: ps aux (att & bsd style "ps -ax" vs "ps ax" behavior difference)
* TODO: switch -fl to -y
* TODO: thread support /proc/$d/task/%d/stat (and -o stat has "l")
- * TODO: iotop: TID PRIO USER DISK_READ DISK_WRITE SWAPIN IO% COMMAND
- * DISK_READ in B/s, K/s..., length 11
- * Total DISK READ: | Total DISK WRITE:
+ * TODO: iotop: Window size change: respond immediately. Why not padding
+ * at right edge? (Not adjusting to screen size at all? Header wraps?)
+ * TODO: utf8 fontmetrics
USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflno*p(pid)*s*t*u*U*g*G*wZ[!ol][+Ae]", TOYFLAG_USR|TOYFLAG_BIN))
USE_TTOP(NEWTOY(ttop, ">0d#=3n#<1mb", TOYFLAG_USR|TOYFLAG_BIN))
USE_IOTOP(NEWTOY(iotop, "Aabkoqp*u*d#n#", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
+USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:", TOYFLAG_USR|TOYFLAG_BIN))
+USE_PKILL(NEWTOY(pkill, "u*U*t*s*P*g*G*fnovxl:", TOYFLAG_USR|TOYFLAG_BIN))
config PS
bool "ps"
@@ -167,6 +169,48 @@ config IOTOP
-p Show these PIDs
-q Quiet (no header lines)
-u Show these USERs
+
+config PGREP
+ bool "pgrep"
+ default n
+ depends on PGKILL_COMMON
+ help
+ usage: pgrep [-cL] [-d DELIM] [-L SIGNAL] [PATTERN]
+
+ Search for process(es). PATTERN is an extended regular expression checked
+ against command names.
+
+ -c Show only count of matches
+ -d Use DELIM instead of newline
+ -L Send SIGNAL instead of printing name
+ -l Show command name
+
+config PGKILL_COMMON
+ bool
+ default y
+ help
+ usage: pgrep [-fnovx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
+
+ -f Check full command line for PATTERN
+ -G Match real Group ID(s)
+ -g Match Process Group(s) (0 is current user)
+ -n Newest match only
+ -o Oldest match only
+ -P Match Parent Process ID(s)
+ -s Match Session ID(s) (0 for current)
+ -t Match Terminal(s)
+ -U Match real User ID(s)
+ -u Match effective User ID(s)
+ -v Negate the match
+ -x Match whole command (not substring)
+
+config PKILL
+ bool "pkill"
+ default n
+ help
+ usage: pkill [-l SIGNAL] [PATTERN]
+
+ -l SIGNAL to send
*/
#define FOR_ps
@@ -196,6 +240,20 @@ GLOBALS(
struct arg_list *u;
struct arg_list *p;
} iotop;
+ struct{
+ char *L;
+ struct arg_list *G;
+ struct arg_list *g;
+ struct arg_list *P;
+ struct arg_list *s;
+ struct arg_list *t;
+ struct arg_list *U;
+ struct arg_list *u;
+ char *d;
+
+ void *regexes;
+ int signal;
+ } pgrep;
};
struct sysinfo si;
@@ -205,8 +263,9 @@ GLOBALS(
void *fields, *kfields;
long long ticks, bits, ioread, iowrite, aioread, aiowrite;
size_t header_len;
- int kcount, ksave, forcek, sortpos;
+ int kcount, forcek, sortpos;
int (*match_process)(long long *slot);
+ void (*show_process)(void *tb);
)
struct strawberry {
@@ -487,7 +546,8 @@ static int get_ps(struct dirtree *new)
off_t len;
// Recurse one level into /proc children, skip non-numeric entries
- if (!new->parent) return DIRTREE_RECURSE|DIRTREE_SHUTUP|TT.ksave;
+ if (!new->parent)
+ return DIRTREE_RECURSE|DIRTREE_SHUTUP|(DIRTREE_SAVE*!TT.show_process);
memset(slot, 0, sizeof(tb->slot));
if (!(*slot = atol(new->name))) return 0;
@@ -673,17 +733,19 @@ static int get_ps(struct dirtree *new)
buf += strlen(buf)+1;
}
- // If we need to sort the output, add it to the list and return.
- if (TT.ksave) {
- s = xmalloc(buf-toybuf);
- new->extra = (long)s;
- memcpy(s, toybuf, buf-toybuf);
- TT.kcount++;
+ if (TT.show_process) {
+ TT.show_process(tb);
+
+ return 0;
+ }
- // Otherwise display it now
- } else show_ps(tb);
+ // If we need to sort the output, add it to the list and return.
+ s = xmalloc(buf-toybuf);
+ new->extra = (long)s;
+ memcpy(s, toybuf, buf-toybuf);
+ TT.kcount++;
- return TT.ksave;
+ return DIRTREE_SAVE;
}
static char *parse_ko(void *data, char *type, int length)
@@ -971,7 +1033,7 @@ void ps_main(void)
}
}
- TT.ksave = DIRTREE_SAVE*!!(toys.optflags&FLAG_k);
+ if (!(toys.optflags&FLAG_k)) TT.show_process = (void *)show_ps;
TT.match_process = ps_match_process;
dt = dirtree_read("/proc", get_ps);
@@ -1072,7 +1134,6 @@ void iotop_main(void)
dlist_terminate(TT.kfields);
setsort(6);
- TT.ksave = DIRTREE_SAVE;
TT.match_process = shared_match_process;
memset(plist, 0, sizeof(plist));
do {
@@ -1191,3 +1252,71 @@ void iotop_main(void)
} while (!done);
if (!(toys.optflags&FLAG_b)) tty_reset();
}
+
+#define CLEANUP_iotop
+#define FOR_pgrep
+#include "generated/flags.h"
+
+struct regex_list {
+ struct regex_list *next;
+ regex_t reg;
+};
+
+static void show_pgrep(struct carveup *tb)
+{
+ regmatch_t match;
+ struct regex_list *reg;
+ char *name = tb->str;
+
+ if (toys.optflags&FLAG_f) name += tb->offset[4];
+
+ if (TT.pgrep.regexes) {
+ for (reg = TT.pgrep.regexes; reg; reg = reg->next) {
+ if (regexec(&reg->reg, name, 1, &match, 0)) continue;
+ if (toys.optflags&FLAG_x)
+ if (match.rm_so || match.rm_eo!=strlen(name)) continue;
+ break;
+ }
+ if (!reg) return;
+ }
+
+ printf("%lld%s", *tb->slot, TT.pgrep.d ? TT.pgrep.d : "\n");
+}
+
+void pgrep_main(void)
+{
+ char **arg;
+ struct regex_list *reg;
+
+ comma_args(TT.pgrep.G, &TT.GG, "bad -G", parse_rest);
+ comma_args(TT.pgrep.g, &TT.gg, "bad -g", parse_rest);
+ comma_args(TT.pgrep.P, &TT.PP, "bad -P", parse_rest);
+ comma_args(TT.pgrep.s, &TT.ss, "bad -s", parse_rest);
+ comma_args(TT.pgrep.t, &TT.tt, "bad -t", parse_rest);
+ comma_args(TT.pgrep.U, &TT.UU, "bad -U", parse_rest);
+ comma_args(TT.pgrep.u, &TT.uu, "bad -u", parse_rest);
+
+ if ((toys.optflags&(FLAG_x|FLAG_f)) ||
+ !(toys.optflags&(FLAG_G|FLAG_g|FLAG_P|FLAG_s|FLAG_t|FLAG_U|FLAG_u)))
+ if (!toys.optc) help_exit("No PATTERN");
+
+ if (toys.optflags&FLAG_f) TT.bits |= _PS_CMDLINE;
+
+ for (arg = toys.optargs; *arg; arg++) {
+ reg = xmalloc(sizeof(struct regex_list));
+ xregcomp(&reg->reg, *arg, REG_EXTENDED);
+ reg->next = TT.pgrep.regexes;
+ TT.pgrep.regexes = reg;
+ }
+ TT.match_process = shared_match_process;
+ TT.show_process = (void *)show_pgrep;
+
+ dirtree_read("/proc", get_ps);
+ if (TT.pgrep.d) xputc('\n');
+}
+
+void pkill_main(void)
+{
+ if (!TT.pgrep.L) TT.pgrep.signal = SIGTERM;
+ pgrep_main();
+}