diff options
-rw-r--r-- | coreutils/sleep.c | 78 | ||||
-rw-r--r-- | coreutils/timeout.c | 6 | ||||
-rw-r--r-- | include/libbb.h | 8 | ||||
-rw-r--r-- | libbb/duration.c | 76 | ||||
-rw-r--r-- | procps/top.c | 14 |
5 files changed, 101 insertions, 81 deletions
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 @@ | |||
32 | //config: depends on SLEEP | 32 | //config: depends on SLEEP |
33 | //config: help | 33 | //config: help |
34 | //config: Allow sleep to pause for specified minutes, hours, and days. | 34 | //config: Allow sleep to pause for specified minutes, hours, and days. |
35 | //config: | ||
36 | //config:config FEATURE_FLOAT_SLEEP | ||
37 | //config: bool "Enable fractional arguments" | ||
38 | //config: default y | ||
39 | //config: depends on FEATURE_FANCY_SLEEP | ||
40 | //config: help | ||
41 | //config: Allow for fractional numeric parameters. | ||
42 | 35 | ||
43 | /* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */ | 36 | /* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */ |
44 | //applet:IF_SLEEP(APPLET(sleep, BB_DIR_BIN, BB_SUID_DROP)) | 37 | //applet:IF_SLEEP(APPLET(sleep, BB_DIR_BIN, BB_SUID_DROP)) |
@@ -66,89 +59,28 @@ | |||
66 | 59 | ||
67 | #include "libbb.h" | 60 | #include "libbb.h" |
68 | 61 | ||
69 | #if ENABLE_FEATURE_FANCY_SLEEP || ENABLE_FEATURE_FLOAT_SLEEP | ||
70 | static const struct suffix_mult sfx[] = { | ||
71 | { "s", 1 }, | ||
72 | { "m", 60 }, | ||
73 | { "h", 60*60 }, | ||
74 | { "d", 24*60*60 }, | ||
75 | { "", 0 } | ||
76 | }; | ||
77 | #endif | ||
78 | |||
79 | int sleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 62 | int sleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
80 | int sleep_main(int argc UNUSED_PARAM, char **argv) | 63 | int sleep_main(int argc UNUSED_PARAM, char **argv) |
81 | { | 64 | { |
82 | #if ENABLE_FEATURE_FLOAT_SLEEP | 65 | duration_t duration; |
83 | double duration; | ||
84 | struct timespec ts; | ||
85 | #else | ||
86 | unsigned duration; | ||
87 | #endif | ||
88 | 66 | ||
89 | ++argv; | 67 | ++argv; |
90 | if (!*argv) | 68 | if (!*argv) |
91 | bb_show_usage(); | 69 | bb_show_usage(); |
92 | 70 | ||
93 | #if ENABLE_FEATURE_FLOAT_SLEEP | 71 | #if ENABLE_FEATURE_FANCY_SLEEP |
94 | 72 | # if ENABLE_FLOAT_DURATION | |
95 | # if ENABLE_LOCALE_SUPPORT | ||
96 | /* undo busybox.c setlocale */ | 73 | /* undo busybox.c setlocale */ |
97 | setlocale(LC_NUMERIC, "C"); | 74 | setlocale(LC_NUMERIC, "C"); |
98 | # endif | 75 | # endif |
99 | duration = 0; | 76 | duration = 0; |
100 | do { | 77 | do { |
101 | char *arg = *argv; | 78 | duration += parse_duration_str(*argv); |
102 | if (strchr(arg, '.')) { | ||
103 | double d; | ||
104 | char *pp; | ||
105 | int len = strspn(arg, "0123456789."); | ||
106 | char sv = arg[len]; | ||
107 | arg[len] = '\0'; | ||
108 | errno = 0; | ||
109 | d = strtod(arg, &pp); | ||
110 | if (errno || *pp) | ||
111 | bb_show_usage(); | ||
112 | arg += len; | ||
113 | *arg-- = sv; | ||
114 | sv = *arg; | ||
115 | *arg = '1'; | ||
116 | duration += d * xatoul_sfx(arg, sfx); | ||
117 | *arg = sv; | ||
118 | } else { | ||
119 | duration += xatoul_sfx(arg, sfx); | ||
120 | } | ||
121 | } while (*++argv); | 79 | } while (*++argv); |
122 | 80 | sleep_for_duration(duration); | |
123 | ts.tv_sec = MAXINT(typeof(ts.tv_sec)); | ||
124 | ts.tv_nsec = 0; | ||
125 | if (duration >= 0 && duration < ts.tv_sec) { | ||
126 | ts.tv_sec = duration; | ||
127 | ts.tv_nsec = (duration - ts.tv_sec) * 1000000000; | ||
128 | } | ||
129 | do { | ||
130 | errno = 0; | ||
131 | nanosleep(&ts, &ts); | ||
132 | } while (errno == EINTR); | ||
133 | |||
134 | #elif ENABLE_FEATURE_FANCY_SLEEP | ||
135 | |||
136 | duration = 0; | ||
137 | do { | ||
138 | duration += xatou_range_sfx(*argv, 0, UINT_MAX - duration, sfx); | ||
139 | } while (*++argv); | ||
140 | sleep(duration); | ||
141 | |||
142 | #else /* simple */ | 81 | #else /* simple */ |
143 | |||
144 | duration = xatou(*argv); | 82 | duration = xatou(*argv); |
145 | sleep(duration); | 83 | sleep(duration); |
146 | // Off. If it's really needed, provide example why | ||
147 | //if (sleep(duration)) { | ||
148 | // bb_perror_nomsg_and_die(); | ||
149 | //} | ||
150 | |||
151 | #endif | 84 | #endif |
152 | |||
153 | return EXIT_SUCCESS; | 85 | return EXIT_SUCCESS; |
154 | } | 86 | } |
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) | |||
52 | int signo; | 52 | int signo; |
53 | int status; | 53 | int status; |
54 | int parent = 0; | 54 | int parent = 0; |
55 | int timeout = 10; | 55 | unsigned timeout; |
56 | const char *timeout_s = "10"; | ||
56 | pid_t pid; | 57 | pid_t pid; |
57 | #if !BB_MMU | 58 | #if !BB_MMU |
58 | char *sv1, *sv2; | 59 | char *sv1, *sv2; |
@@ -63,11 +64,12 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) | |||
63 | 64 | ||
64 | /* -t SECONDS; -p PARENT_PID */ | 65 | /* -t SECONDS; -p PARENT_PID */ |
65 | /* '+': stop at first non-option */ | 66 | /* '+': stop at first non-option */ |
66 | getopt32(argv, "+s:t:+" USE_FOR_NOMMU("p:+"), &opt_s, &timeout, &parent); | 67 | getopt32(argv, "+s:t:" USE_FOR_NOMMU("p:+"), &opt_s, &timeout_s, &parent); |
67 | /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ | 68 | /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ |
68 | signo = get_signum(opt_s); | 69 | signo = get_signum(opt_s); |
69 | if (signo < 0) | 70 | if (signo < 0) |
70 | bb_error_msg_and_die("unknown signal '%s'", opt_s); | 71 | bb_error_msg_and_die("unknown signal '%s'", opt_s); |
72 | timeout = parse_duration_str((char*)timeout_s); | ||
71 | 73 | ||
72 | /* We want to create a grandchild which will watch | 74 | /* We want to create a grandchild which will watch |
73 | * and kill the grandparent. Other methods: | 75 | * 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; | |||
1018 | /* Useful for reading port numbers */ | 1018 | /* Useful for reading port numbers */ |
1019 | uint16_t xatou16(const char *numstr) FAST_FUNC; | 1019 | uint16_t xatou16(const char *numstr) FAST_FUNC; |
1020 | 1020 | ||
1021 | #if ENABLE_FLOAT_DURATION | ||
1022 | typedef double duration_t; | ||
1023 | void sleep_for_duration(duration_t duration) FAST_FUNC; | ||
1024 | #else | ||
1025 | typedef unsigned duration_t; | ||
1026 | #define sleep_for_duration(duration) sleep(duration) | ||
1027 | #endif | ||
1028 | duration_t parse_duration_str(char *str) FAST_FUNC; | ||
1021 | 1029 | ||
1022 | /* These parse entries in /etc/passwd and /etc/group. This is desirable | 1030 | /* These parse entries in /etc/passwd and /etc/group. This is desirable |
1023 | * for BusyBox since we want to avoid using the glibc NSS stuff, which | 1031 | * 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 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 2018 Denys Vlasenko | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
8 | */ | ||
9 | //config:config FLOAT_DURATION | ||
10 | //config: bool "Enable fractional duration arguments" | ||
11 | //config: default y | ||
12 | //config: help | ||
13 | //config: Allow sleep N.NNN, top -d N.NNN etc. | ||
14 | |||
15 | //kbuild:lib-$(CONFIG_SLEEP) += duration.o | ||
16 | //kbuild:lib-$(CONFIG_TOP) += duration.o | ||
17 | //kbuild:lib-$(CONFIG_TIMEOUT) += duration.o | ||
18 | |||
19 | #include "libbb.h" | ||
20 | |||
21 | static const struct suffix_mult duration_suffixes[] = { | ||
22 | { "s", 1 }, | ||
23 | { "m", 60 }, | ||
24 | { "h", 60*60 }, | ||
25 | { "d", 24*60*60 }, | ||
26 | { "", 0 } | ||
27 | }; | ||
28 | |||
29 | #if ENABLE_FLOAT_DURATION | ||
30 | duration_t FAST_FUNC parse_duration_str(char *str) | ||
31 | { | ||
32 | duration_t duration; | ||
33 | |||
34 | if (strchr(str, '.')) { | ||
35 | double d; | ||
36 | char *pp; | ||
37 | int len = strspn(str, "0123456789."); | ||
38 | char sv = str[len]; | ||
39 | str[len] = '\0'; | ||
40 | errno = 0; | ||
41 | d = strtod(str, &pp); | ||
42 | if (errno || *pp) | ||
43 | bb_show_usage(); | ||
44 | str += len; | ||
45 | *str-- = sv; | ||
46 | sv = *str; | ||
47 | *str = '1'; | ||
48 | duration = d * xatoul_sfx(str, duration_suffixes); | ||
49 | *str = sv; | ||
50 | } else { | ||
51 | duration = xatoul_sfx(str, duration_suffixes); | ||
52 | } | ||
53 | |||
54 | return duration; | ||
55 | } | ||
56 | void FAST_FUNC sleep_for_duration(duration_t duration) | ||
57 | { | ||
58 | struct timespec ts; | ||
59 | |||
60 | ts.tv_sec = MAXINT(typeof(ts.tv_sec)); | ||
61 | ts.tv_nsec = 0; | ||
62 | if (duration >= 0 && duration < ts.tv_sec) { | ||
63 | ts.tv_sec = duration; | ||
64 | ts.tv_nsec = (duration - ts.tv_sec) * 1000000000; | ||
65 | } | ||
66 | do { | ||
67 | errno = 0; | ||
68 | nanosleep(&ts, &ts); | ||
69 | } while (errno == EINTR); | ||
70 | } | ||
71 | #else | ||
72 | duration_t FAST_FUNC parse_duration_str(char *str) | ||
73 | { | ||
74 | return xatou_range_sfx(*argv, 0, UINT_MAX, duration_suffixes); | ||
75 | } | ||
76 | #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 { | |||
901 | }; | 901 | }; |
902 | 902 | ||
903 | #if ENABLE_FEATURE_TOP_INTERACTIVE | 903 | #if ENABLE_FEATURE_TOP_INTERACTIVE |
904 | static unsigned handle_input(unsigned scan_mask, unsigned interval) | 904 | static unsigned handle_input(unsigned scan_mask, duration_t interval) |
905 | { | 905 | { |
906 | if (option_mask32 & OPT_EOF) { | 906 | if (option_mask32 & OPT_EOF) { |
907 | /* EOF on stdin ("top </dev/null") */ | 907 | /* EOF on stdin ("top </dev/null") */ |
908 | sleep(interval); | 908 | sleep_for_duration(interval); |
909 | return scan_mask; | 909 | return scan_mask; |
910 | } | 910 | } |
911 | 911 | ||
@@ -1092,9 +1092,9 @@ static unsigned handle_input(unsigned scan_mask, unsigned interval) | |||
1092 | int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1092 | int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1093 | int top_main(int argc UNUSED_PARAM, char **argv) | 1093 | int top_main(int argc UNUSED_PARAM, char **argv) |
1094 | { | 1094 | { |
1095 | duration_t interval; | ||
1095 | int iterations; | 1096 | int iterations; |
1096 | unsigned col; | 1097 | unsigned col; |
1097 | unsigned interval; | ||
1098 | char *str_interval, *str_iterations; | 1098 | char *str_interval, *str_iterations; |
1099 | unsigned scan_mask = TOP_MASK; | 1099 | unsigned scan_mask = TOP_MASK; |
1100 | 1100 | ||
@@ -1120,8 +1120,10 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1120 | /* work around for "-d 1" -> "-d -1" done by make_all_argv_opts() */ | 1120 | /* work around for "-d 1" -> "-d -1" done by make_all_argv_opts() */ |
1121 | if (str_interval[0] == '-') | 1121 | if (str_interval[0] == '-') |
1122 | str_interval++; | 1122 | str_interval++; |
1123 | interval = parse_duration_str(str_interval); | ||
1123 | /* Need to limit it to not overflow poll timeout */ | 1124 | /* Need to limit it to not overflow poll timeout */ |
1124 | interval = xatou16(str_interval); | 1125 | if (interval > INT_MAX / 1000) |
1126 | interval = INT_MAX / 1000; | ||
1125 | } | 1127 | } |
1126 | if (col & OPT_n) { | 1128 | if (col & OPT_n) { |
1127 | if (str_iterations[0] == '-') | 1129 | if (str_iterations[0] == '-') |
@@ -1169,7 +1171,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1169 | /* We output to stdout, we need size of stdout (not stdin)! */ | 1171 | /* We output to stdout, we need size of stdout (not stdin)! */ |
1170 | get_terminal_width_height(STDOUT_FILENO, &col, &G.lines); | 1172 | get_terminal_width_height(STDOUT_FILENO, &col, &G.lines); |
1171 | if (G.lines < 5 || col < 10) { | 1173 | if (G.lines < 5 || col < 10) { |
1172 | sleep(interval); | 1174 | sleep_for_duration(interval); |
1173 | continue; | 1175 | continue; |
1174 | } | 1176 | } |
1175 | if (col > LINE_BUF_SIZE - 2) | 1177 | if (col > LINE_BUF_SIZE - 2) |
@@ -1254,7 +1256,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1254 | break; | 1256 | break; |
1255 | #if !ENABLE_FEATURE_TOP_INTERACTIVE | 1257 | #if !ENABLE_FEATURE_TOP_INTERACTIVE |
1256 | clearmems(); | 1258 | clearmems(); |
1257 | sleep(interval); | 1259 | sleep_for_duration(interval); |
1258 | #else | 1260 | #else |
1259 | new_mask = handle_input(scan_mask, interval); | 1261 | new_mask = handle_input(scan_mask, interval); |
1260 | if (new_mask == NO_RESCAN_MASK) | 1262 | if (new_mask == NO_RESCAN_MASK) |