From 4c20d9f2b0223874e2b5ac1235d5f33fdd02589b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 3 Aug 2018 18:17:12 +0200 Subject: extend fractional duration support to "top -d N.N" and "timeout" function old new delta parse_duration_str - 168 +168 sleep_for_duration - 157 +157 top_main 885 928 +43 timeout_main 269 312 +43 handle_input 571 614 +43 duration_suffixes - 40 +40 sfx 40 - -40 sleep_main 364 79 -285 ------------------------------------------------------------------------------ (add/remove: 4/1 grow/shrink: 3/1 up/down: 494/-325) Total: 169 bytes Signed-off-by: Denys Vlasenko --- coreutils/sleep.c | 78 ++++------------------------------------------------- coreutils/timeout.c | 6 +++-- include/libbb.h | 8 ++++++ libbb/duration.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ procps/top.c | 14 +++++----- 5 files changed, 101 insertions(+), 81 deletions(-) create mode 100644 libbb/duration.c diff --git a/coreutils/sleep.c b/coreutils/sleep.c index 9b9581ca9..126665839 100644 --- a/coreutils/sleep.c +++ b/coreutils/sleep.c @@ -32,13 +32,6 @@ //config: depends on SLEEP //config: help //config: Allow sleep to pause for specified minutes, hours, and days. -//config: -//config:config FEATURE_FLOAT_SLEEP -//config: bool "Enable fractional arguments" -//config: default y -//config: depends on FEATURE_FANCY_SLEEP -//config: help -//config: Allow for fractional numeric parameters. /* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */ //applet:IF_SLEEP(APPLET(sleep, BB_DIR_BIN, BB_SUID_DROP)) @@ -66,89 +59,28 @@ #include "libbb.h" -#if ENABLE_FEATURE_FANCY_SLEEP || ENABLE_FEATURE_FLOAT_SLEEP -static const struct suffix_mult sfx[] = { - { "s", 1 }, - { "m", 60 }, - { "h", 60*60 }, - { "d", 24*60*60 }, - { "", 0 } -}; -#endif - int sleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sleep_main(int argc UNUSED_PARAM, char **argv) { -#if ENABLE_FEATURE_FLOAT_SLEEP - double duration; - struct timespec ts; -#else - unsigned duration; -#endif + duration_t duration; ++argv; if (!*argv) bb_show_usage(); -#if ENABLE_FEATURE_FLOAT_SLEEP - -# if ENABLE_LOCALE_SUPPORT +#if ENABLE_FEATURE_FANCY_SLEEP +# if ENABLE_FLOAT_DURATION /* undo busybox.c setlocale */ setlocale(LC_NUMERIC, "C"); # endif duration = 0; do { - char *arg = *argv; - if (strchr(arg, '.')) { - double d; - char *pp; - int len = strspn(arg, "0123456789."); - char sv = arg[len]; - arg[len] = '\0'; - errno = 0; - d = strtod(arg, &pp); - if (errno || *pp) - bb_show_usage(); - arg += len; - *arg-- = sv; - sv = *arg; - *arg = '1'; - duration += d * xatoul_sfx(arg, sfx); - *arg = sv; - } else { - duration += xatoul_sfx(arg, sfx); - } + duration += parse_duration_str(*argv); } while (*++argv); - - ts.tv_sec = MAXINT(typeof(ts.tv_sec)); - ts.tv_nsec = 0; - if (duration >= 0 && duration < ts.tv_sec) { - ts.tv_sec = duration; - ts.tv_nsec = (duration - ts.tv_sec) * 1000000000; - } - do { - errno = 0; - nanosleep(&ts, &ts); - } while (errno == EINTR); - -#elif ENABLE_FEATURE_FANCY_SLEEP - - duration = 0; - do { - duration += xatou_range_sfx(*argv, 0, UINT_MAX - duration, sfx); - } while (*++argv); - sleep(duration); - + sleep_for_duration(duration); #else /* simple */ - duration = xatou(*argv); sleep(duration); - // Off. If it's really needed, provide example why - //if (sleep(duration)) { - // bb_perror_nomsg_and_die(); - //} - #endif - return EXIT_SUCCESS; } diff --git a/coreutils/timeout.c b/coreutils/timeout.c index 4a6117f59..663303c2d 100644 --- a/coreutils/timeout.c +++ b/coreutils/timeout.c @@ -52,7 +52,8 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) int signo; int status; int parent = 0; - int timeout = 10; + unsigned timeout; + const char *timeout_s = "10"; pid_t pid; #if !BB_MMU char *sv1, *sv2; @@ -63,11 +64,12 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) /* -t SECONDS; -p PARENT_PID */ /* '+': stop at first non-option */ - getopt32(argv, "+s:t:+" USE_FOR_NOMMU("p:+"), &opt_s, &timeout, &parent); + getopt32(argv, "+s:t:" USE_FOR_NOMMU("p:+"), &opt_s, &timeout_s, &parent); /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ signo = get_signum(opt_s); if (signo < 0) bb_error_msg_and_die("unknown signal '%s'", opt_s); + timeout = parse_duration_str((char*)timeout_s); /* We want to create a grandchild which will watch * and kill the grandparent. Other methods: diff --git a/include/libbb.h b/include/libbb.h index 94caba2bb..7cad12c44 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1018,6 +1018,14 @@ int xatoi_positive(const char *numstr) FAST_FUNC; /* Useful for reading port numbers */ uint16_t xatou16(const char *numstr) FAST_FUNC; +#if ENABLE_FLOAT_DURATION +typedef double duration_t; +void sleep_for_duration(duration_t duration) FAST_FUNC; +#else +typedef unsigned duration_t; +#define sleep_for_duration(duration) sleep(duration) +#endif +duration_t parse_duration_str(char *str) FAST_FUNC; /* These parse entries in /etc/passwd and /etc/group. This is desirable * for BusyBox since we want to avoid using the glibc NSS stuff, which diff --git a/libbb/duration.c b/libbb/duration.c new file mode 100644 index 000000000..765a1e9fe --- /dev/null +++ b/libbb/duration.c @@ -0,0 +1,76 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 2018 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config FLOAT_DURATION +//config: bool "Enable fractional duration arguments" +//config: default y +//config: help +//config: Allow sleep N.NNN, top -d N.NNN etc. + +//kbuild:lib-$(CONFIG_SLEEP) += duration.o +//kbuild:lib-$(CONFIG_TOP) += duration.o +//kbuild:lib-$(CONFIG_TIMEOUT) += duration.o + +#include "libbb.h" + +static const struct suffix_mult duration_suffixes[] = { + { "s", 1 }, + { "m", 60 }, + { "h", 60*60 }, + { "d", 24*60*60 }, + { "", 0 } +}; + +#if ENABLE_FLOAT_DURATION +duration_t FAST_FUNC parse_duration_str(char *str) +{ + duration_t duration; + + if (strchr(str, '.')) { + double d; + char *pp; + int len = strspn(str, "0123456789."); + char sv = str[len]; + str[len] = '\0'; + errno = 0; + d = strtod(str, &pp); + if (errno || *pp) + bb_show_usage(); + str += len; + *str-- = sv; + sv = *str; + *str = '1'; + duration = d * xatoul_sfx(str, duration_suffixes); + *str = sv; + } else { + duration = xatoul_sfx(str, duration_suffixes); + } + + return duration; +} +void FAST_FUNC sleep_for_duration(duration_t duration) +{ + struct timespec ts; + + ts.tv_sec = MAXINT(typeof(ts.tv_sec)); + ts.tv_nsec = 0; + if (duration >= 0 && duration < ts.tv_sec) { + ts.tv_sec = duration; + ts.tv_nsec = (duration - ts.tv_sec) * 1000000000; + } + do { + errno = 0; + nanosleep(&ts, &ts); + } while (errno == EINTR); +} +#else +duration_t FAST_FUNC parse_duration_str(char *str) +{ + return xatou_range_sfx(*argv, 0, UINT_MAX, duration_suffixes); +} +#endif diff --git a/procps/top.c b/procps/top.c index 1b49a5e6b..f016f5501 100644 --- a/procps/top.c +++ b/procps/top.c @@ -901,11 +901,11 @@ enum { }; #if ENABLE_FEATURE_TOP_INTERACTIVE -static unsigned handle_input(unsigned scan_mask, unsigned interval) +static unsigned handle_input(unsigned scan_mask, duration_t interval) { if (option_mask32 & OPT_EOF) { /* EOF on stdin ("top "-d -1" done by make_all_argv_opts() */ if (str_interval[0] == '-') str_interval++; + interval = parse_duration_str(str_interval); /* Need to limit it to not overflow poll timeout */ - interval = xatou16(str_interval); + if (interval > INT_MAX / 1000) + interval = INT_MAX / 1000; } if (col & OPT_n) { if (str_iterations[0] == '-') @@ -1169,7 +1171,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) /* We output to stdout, we need size of stdout (not stdin)! */ get_terminal_width_height(STDOUT_FILENO, &col, &G.lines); if (G.lines < 5 || col < 10) { - sleep(interval); + sleep_for_duration(interval); continue; } if (col > LINE_BUF_SIZE - 2) @@ -1254,7 +1256,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) break; #if !ENABLE_FEATURE_TOP_INTERACTIVE clearmems(); - sleep(interval); + sleep_for_duration(interval); #else new_mask = handle_input(scan_mask, interval); if (new_mask == NO_RESCAN_MASK) -- cgit v1.2.3