hush: rename hush-redir/redir3.tests (ash has redir3.tests which id different)
[oweals/busybox.git] / coreutils / sleep.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * sleep implementation for busybox
4  *
5  * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8  */
9 /* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
10  *
11  * Rewritten to do proper arg and error checking.
12  * Also, added a 'fancy' configuration to accept multiple args with
13  * time suffixes for seconds, minutes, hours, and days.
14  */
15 //config:config SLEEP
16 //config:       bool "sleep"
17 //config:       default y
18 //config:       help
19 //config:         sleep is used to pause for a specified number of seconds.
20 //config:         It comes in 3 versions:
21 //config:         - small: takes one integer parameter
22 //config:         - fancy: takes multiple integer arguments with suffixes:
23 //config:           sleep 1d 2h 3m 15s
24 //config:         - fancy with fractional numbers:
25 //config:           sleep 2.3s 4.5h sleeps for 16202.3 seconds
26 //config:         Last one is "the most compatible" with coreutils sleep,
27 //config:         but it adds around 1k of code.
28 //config:
29 //config:config FEATURE_FANCY_SLEEP
30 //config:       bool "Enable multiple arguments and s/m/h/d suffixes"
31 //config:       default y
32 //config:       depends on SLEEP
33 //config:       help
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
43 /* 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))
45
46 //kbuild:lib-$(CONFIG_SLEEP) += sleep.o
47
48 /* BB_AUDIT SUSv3 compliant */
49 /* BB_AUDIT GNU issues -- fancy version matches except args must be ints. */
50 /* http://www.opengroup.org/onlinepubs/007904975/utilities/sleep.html */
51
52 //usage:#define sleep_trivial_usage
53 //usage:        IF_FEATURE_FANCY_SLEEP("[") "N" IF_FEATURE_FANCY_SLEEP("]...")
54 //usage:#define sleep_full_usage "\n\n"
55 //usage:        IF_NOT_FEATURE_FANCY_SLEEP("Pause for N seconds")
56 //usage:        IF_FEATURE_FANCY_SLEEP(
57 //usage:       "Pause for a time equal to the total of the args given, where each arg can\n"
58 //usage:       "have an optional suffix of (s)econds, (m)inutes, (h)ours, or (d)ays")
59 //usage:
60 //usage:#define sleep_example_usage
61 //usage:       "$ sleep 2\n"
62 //usage:       "[2 second delay results]\n"
63 //usage:        IF_FEATURE_FANCY_SLEEP(
64 //usage:       "$ sleep 1d 3h 22m 8s\n"
65 //usage:       "[98528 second delay results]\n")
66
67 #include "libbb.h"
68
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;
80 int sleep_main(int argc UNUSED_PARAM, char **argv)
81 {
82 #if ENABLE_FEATURE_FLOAT_SLEEP
83         double duration;
84         struct timespec ts;
85 #else
86         unsigned duration;
87 #endif
88
89         ++argv;
90         if (!*argv)
91                 bb_show_usage();
92
93 #if ENABLE_FEATURE_FLOAT_SLEEP
94
95 # if ENABLE_LOCALE_SUPPORT
96         /* undo busybox.c setlocale */
97         setlocale(LC_NUMERIC, "C");
98 # endif
99         duration = 0;
100         do {
101                 char *arg = *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);
122
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 */
143
144         duration = xatou(*argv);
145         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
152
153         return EXIT_SUCCESS;
154 }