summaryrefslogtreecommitdiff
path: root/coreutils/sleep.c
blob: ad2d6b526eaedb3f994a2b0a7731c0a98119800c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* vi: set sw=4 ts=4: */
/*
 * sleep implementation for busybox
 *
 * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
 *
 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
 */
/* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
 *
 * Rewritten to do proper arg and error checking.
 * Also, added a 'fancy' configuration to accept multiple args with
 * time suffixes for seconds, minutes, hours, and days.
 */
//config:config SLEEP
//config:	bool "sleep"
//config:	default y
//config:	help
//config:	  sleep is used to pause for a specified number of seconds.
//config:	  It comes in 3 versions:
//config:	  - small: takes one integer parameter
//config:	  - fancy: takes multiple integer arguments with suffixes:
//config:	    sleep 1d 2h 3m 15s
//config:	  - fancy with fractional numbers:
//config:	    sleep 2.3s 4.5h sleeps for 16202.3 seconds
//config:	  Last one is "the most compatible" with coreutils sleep,
//config:	  but it adds around 1k of code.
//config:
//config:config FEATURE_FANCY_SLEEP
//config:	bool "Enable multiple arguments and s/m/h/d suffixes"
//config:	default y
//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))

//kbuild:lib-$(CONFIG_SLEEP) += sleep.o

/* BB_AUDIT SUSv3 compliant */
/* BB_AUDIT GNU issues -- fancy version matches except args must be ints. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/sleep.html */

//usage:#define sleep_trivial_usage
//usage:	IF_FEATURE_FANCY_SLEEP("[") "N" IF_FEATURE_FANCY_SLEEP("]...")
//usage:#define sleep_full_usage "\n\n"
//usage:	IF_NOT_FEATURE_FANCY_SLEEP("Pause for N seconds")
//usage:	IF_FEATURE_FANCY_SLEEP(
//usage:       "Pause for a time equal to the total of the args given, where each arg can\n"
//usage:       "have an optional suffix of (s)econds, (m)inutes, (h)ours, or (d)ays")
//usage:
//usage:#define sleep_example_usage
//usage:       "$ sleep 2\n"
//usage:       "[2 second delay results]\n"
//usage:	IF_FEATURE_FANCY_SLEEP(
//usage:       "$ sleep 1d 3h 22m 8s\n"
//usage:       "[98528 second delay results]\n")

#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

	++argv;
	if (!*argv)
		bb_show_usage();

#if ENABLE_FEATURE_FLOAT_SLEEP

# if ENABLE_LOCALE_SUPPORT
	/* 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);
		}
	} 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);

#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;
}