blob: 793d02f427ba6816e9360f5de37d514944410155 [file] [log] [blame]
Denys Vlasenko4c20d9f2018-08-03 18:17:12 +02001/* 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
Denys Vlasenko277e00e2018-08-03 18:51:46 +020018//kbuild:lib-$(CONFIG_PING) += duration.o
19//kbuild:lib-$(CONFIG_PING6) += duration.o
Denys Vlasenko5fa5c4b2020-06-23 21:28:19 +020020//kbuild:lib-$(CONFIG_WATCH) += duration.o
Denys Vlasenko4c20d9f2018-08-03 18:17:12 +020021
22#include "libbb.h"
23
Denys Vlasenko965b7952020-11-30 13:03:03 +010024static const struct suffix_mult duration_suffixes[] ALIGN_SUFFIX = {
Denys Vlasenko4c20d9f2018-08-03 18:17:12 +020025 { "s", 1 },
26 { "m", 60 },
27 { "h", 60*60 },
28 { "d", 24*60*60 },
29 { "", 0 }
30};
31
32#if ENABLE_FLOAT_DURATION
33duration_t FAST_FUNC parse_duration_str(char *str)
34{
35 duration_t duration;
36
37 if (strchr(str, '.')) {
38 double d;
39 char *pp;
Denys Vlasenkoc2bd0b62021-03-23 13:50:02 +010040 int len;
41 char sv;
42
43# if ENABLE_LOCALE_SUPPORT
44 /* Undo busybox.c: on input, we want to use dot
45 * as fractional separator in strtod(),
46 * regardless of current locale
47 */
48 setlocale(LC_NUMERIC, "C");
49# endif
50 len = strspn(str, "0123456789.");
51 sv = str[len];
Denys Vlasenko4c20d9f2018-08-03 18:17:12 +020052 str[len] = '\0';
53 errno = 0;
54 d = strtod(str, &pp);
55 if (errno || *pp)
56 bb_show_usage();
57 str += len;
58 *str-- = sv;
59 sv = *str;
60 *str = '1';
61 duration = d * xatoul_sfx(str, duration_suffixes);
62 *str = sv;
63 } else {
64 duration = xatoul_sfx(str, duration_suffixes);
65 }
66
67 return duration;
68}
69void FAST_FUNC sleep_for_duration(duration_t duration)
70{
71 struct timespec ts;
72
73 ts.tv_sec = MAXINT(typeof(ts.tv_sec));
74 ts.tv_nsec = 0;
75 if (duration >= 0 && duration < ts.tv_sec) {
76 ts.tv_sec = duration;
77 ts.tv_nsec = (duration - ts.tv_sec) * 1000000000;
78 }
Shawn Landden58598eb2022-08-27 19:56:21 +020079 /* NB: if ENABLE_ASH_SLEEP, we end up here if "sleep N"
80 * is run in ash. ^C will still work, because ash's signal handler
81 * does not return (it longjumps), the below loop
82 * will not continue looping.
83 * (This wouldn't work in hush)
84 */
Denys Vlasenko4c20d9f2018-08-03 18:17:12 +020085 do {
86 errno = 0;
87 nanosleep(&ts, &ts);
88 } while (errno == EINTR);
89}
90#else
91duration_t FAST_FUNC parse_duration_str(char *str)
92{
Denys Vlasenko67911402018-08-26 16:32:16 +020093 return xatou_range_sfx(str, 0, UINT_MAX, duration_suffixes);
Denys Vlasenko4c20d9f2018-08-03 18:17:12 +020094}
95#endif