extend fractional duration support to "top -d N.N" and "timeout"
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 3 Aug 2018 16:17:12 +0000 (18:17 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 3 Aug 2018 16:17:12 +0000 (18:17 +0200)
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 <vda.linux@googlemail.com>
coreutils/sleep.c
coreutils/timeout.c
include/libbb.h
libbb/duration.c [new file with mode: 0644]
procps/top.c

index 9b9581ca9a68b30799bc76fe987c3464536ace38..126665839a2a6dea284e0357c76c29d98dfe15d1 100644 (file)
 //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))
 
 #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;
 }
index 4a6117f5942414d5193012869ee8b8bd40a6f993..663303c2de37d4c8adba57b007f7cba48a367267 100644 (file)
@@ -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:
index 94caba2bb2a81e16d823daa7c84153f8379f55c5..7cad12c448559e0072274201484c44796d878259 100644 (file)
@@ -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 (file)
index 0000000..765a1e9
--- /dev/null
@@ -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
index 1b49a5e6b855e74a9338c60ab07230503ea66e4f..f016f55010624eddb11f02e74267f80e87aa9b8a 100644 (file)
@@ -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 </dev/null") */
-               sleep(interval);
+               sleep_for_duration(interval);
                return scan_mask;
        }
 
@@ -1092,9 +1092,9 @@ static unsigned handle_input(unsigned scan_mask, unsigned interval)
 int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int top_main(int argc UNUSED_PARAM, char **argv)
 {
+       duration_t interval;
        int iterations;
        unsigned col;
-       unsigned interval;
        char *str_interval, *str_iterations;
        unsigned scan_mask = TOP_MASK;
 
@@ -1120,8 +1120,10 @@ int top_main(int argc UNUSED_PARAM, char **argv)
                /* work around for "-d 1" -> "-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)