From eee28e7b5851a6eb16f7969393d8c6292b1f8754 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 3 May 2018 15:09:14 -0700 Subject: Support fractional seconds (and other time units) in `top -d`. LTP uses `top -d 0.1`, which isn't convincingly useful, but general support for other time units might be useful, and switching to xparsetime addresses both at once. Also fix 3169d948c049664bcf7216d4c4ae751881099d3e where I mistakenly treated `rev` and `toys.optflags&FLAG_b` as interchangeable. (Without this second fix, `top -b` looks fine but `top` is broken!) Also fix xparsetime to reject input such as "monkey" or "1monkey". --- lib/xwrap.c | 10 +++++++--- tests/top.test | 6 ++++++ toys/posix/ps.c | 23 +++++++++++++++-------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/lib/xwrap.c b/lib/xwrap.c index 54985db3..26383c92 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -792,15 +792,19 @@ long xparsetime(char *arg, long units, long *fraction) { double d; long l; + char *end; + + if (CFG_TOYBOX_FLOAT) d = strtod(arg, &end); + else l = strtoul(arg, &end, 10); - if (CFG_TOYBOX_FLOAT) d = strtod(arg, &arg); - else l = strtoul(arg, &arg, 10); + if (end == arg) error_exit("Not a number '%s'", arg); + arg = end; // Parse suffix if (*arg) { int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *arg); - if (i == -1) error_exit("Unknown suffix '%c'", *arg); + if (i == -1 || *(arg+1)) error_exit("Unknown suffix '%s'", arg); if (CFG_TOYBOX_FLOAT) d *= ismhd[i]; else l *= ismhd[i]; } diff --git a/tests/top.test b/tests/top.test index 11eea33b..3c3b5977 100755 --- a/tests/top.test +++ b/tests/top.test @@ -5,3 +5,9 @@ #testing "name" "command" "result" "infile" "stdin" testing "batch termination" "top -b -n1 | tail -c 1" "\n" "" "" +testing "fractional seconds" "top -b -d 8.5 -n1 | tail -c 1" "\n" "" "" + +# These are unit tests of xparsetime. +testing "-d invalid input" "top -b -d monkey -n1 2>&1 >/dev/null" "top: Not a number 'monkey'\n" "" "" +testing "-d unknown suffix" "top -b -d 1u -n1 2>&1 >/dev/null" "top: Unknown suffix 'u'\n" "" "" +testing "-d suffix trailing junk" "top -b -d 1monkey -n1 2>&1 >/dev/null" "top: Unknown suffix 'monkey'\n" "" "" diff --git a/toys/posix/ps.c b/toys/posix/ps.c index c5c0f790..c5d487f5 100644 --- a/toys/posix/ps.c +++ b/toys/posix/ps.c @@ -48,8 +48,8 @@ USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][ // stayroot because iotop needs root to read other process' proc/$$/io // TOP and IOTOP have a large common option block used for common processing, // the default values are different but the flags are in the same order. -USE_TOP(NEWTOY(top, ">0O*" "Hk*o*p*u*s#<1d#=3<1m#n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) -USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d#=3<1m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE)) +USE_TOP(NEWTOY(top, ">0O*" "Hk*o*p*u*s#<1d:m#n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) +USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d:m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE)) USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN)) USE_PKILL(NEWTOY(pkill, "?Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN)) @@ -249,13 +249,15 @@ GLOBALS( struct { long n; long m; - long d; + char *d; long s; struct arg_list *u; struct arg_list *p; struct arg_list *o; struct arg_list *k; struct arg_list *O; + + long d_ms; } top; struct { char *L; @@ -1359,9 +1361,9 @@ static int header_line(int line, int rev) if (toys.optflags&FLAG_b) rev = 0; - printf("%s%*.*s%s\n", rev ? "\033[7m" : "", + printf("%s%*.*s%s%s\n", rev ? "\033[7m" : "", (toys.optflags&FLAG_b) ? 0 : -TT.width, TT.width, toybuf, - rev ? "\033[0m\r" : ""); + rev ? "\033[0m" : "", (toys.optflags&FLAG_b) ? "" : "\r"); return line-1; } @@ -1566,8 +1568,8 @@ static void top_common( } now = millitime(); - if (timeout<=now) timeout = new.whence+TT.top.d; - if (timeout<=now || timeout>now+TT.top.d) timeout = now+TT.top.d; + if (timeout<=now) timeout = new.whence+TT.top.d_ms; + if (timeout<=now || timeout>now+TT.top.d_ms) timeout = now+TT.top.d_ms; // In batch mode, we ignore the keyboard. if (toys.optflags&FLAG_b) { @@ -1621,7 +1623,12 @@ static void top_common( static void top_setup(char *defo, char *defk) { - TT.top.d *= 1000; + if (TT.top.d) { + long frac; + + TT.top.d_ms = xparsetime(TT.top.d, 1000, &frac) * 1000; + TT.top.d_ms += frac; + } else TT.top.d_ms = 3000; TT.ticks = sysconf(_SC_CLK_TCK); // units for starttime/uptime TT.tty = tty_fd() != -1; -- cgit v1.2.3