aboutsummaryrefslogtreecommitdiff
path: root/bin/sleep/sleep.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/sleep/sleep.c')
-rw-r--r--bin/sleep/sleep.c125
1 files changed, 59 insertions, 66 deletions
diff --git a/bin/sleep/sleep.c b/bin/sleep/sleep.c
index 55e0aba9871a..34d335cf4736 100644
--- a/bin/sleep/sleep.c
+++ b/bin/sleep/sleep.c
@@ -27,111 +27,104 @@
* SUCH DAMAGE.
*/
-#if 0
-#ifndef lint
-static char const copyright[] =
-"@(#) Copyright (c) 1988, 1993, 1994\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94";
-#endif /* not lint */
-#endif
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <capsicum_helpers.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
+#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
-
-static void usage(void);
+#include <unistd.h>
static volatile sig_atomic_t report_requested;
+
static void
report_request(int signo __unused)
{
-
report_requested = 1;
}
+static void __dead2
+usage(void)
+{
+ fprintf(stderr, "usage: sleep number[unit] [...]\n"
+ "Unit can be 's' (seconds, the default), "
+ "m (minutes), h (hours), or d (days).\n");
+ exit(1);
+}
+
+static double
+parse_interval(const char *arg)
+{
+ double num;
+ char unit, extra;
+
+ switch (sscanf(arg, "%lf%c%c", &num, &unit, &extra)) {
+ case 2:
+ switch (unit) {
+ case 'd':
+ num *= 24;
+ /* FALLTHROUGH */
+ case 'h':
+ num *= 60;
+ /* FALLTHROUGH */
+ case 'm':
+ num *= 60;
+ /* FALLTHROUGH */
+ case 's':
+ if (!isnan(num))
+ return (num);
+ }
+ break;
+ case 1:
+ if (!isnan(num))
+ return (num);
+ }
+ warnx("invalid time interval: %s", arg);
+ return (INFINITY);
+}
+
int
main(int argc, char *argv[])
{
struct timespec time_to_sleep;
- double d, seconds;
+ double seconds;
time_t original;
- char unit;
- char buf[2];
- int i, matches;
if (caph_limit_stdio() < 0 || caph_enter() < 0)
err(1, "capsicum");
- if (argc < 2)
+ while (getopt(argc, argv, "") != -1)
+ usage();
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
usage();
seconds = 0;
- for (i = 1; i < argc; i++) {
- matches = sscanf(argv[i], "%lf%c%1s", &d, &unit, buf);
- if (matches == 2)
- switch(unit) {
- case 'd':
- d *= 24;
- /* FALLTHROUGH */
- case 'h':
- d *= 60;
- /* FALLTHROUGH */
- case 'm':
- d *= 60;
- /* FALLTHROUGH */
- case 's':
- break;
- default:
- usage();
- }
- else
- if (matches != 1)
- usage();
- seconds += d;
- }
+ while (argc--)
+ seconds += parse_interval(*argv++);
if (seconds > INT_MAX)
usage();
- if (seconds <= 0)
- return (0);
+ if (seconds < 1e-9)
+ exit(0);
original = time_to_sleep.tv_sec = (time_t)seconds;
time_to_sleep.tv_nsec = 1e9 * (seconds - time_to_sleep.tv_sec);
signal(SIGINFO, report_request);
- /*
- * Note: [EINTR] is supposed to happen only when a signal was handled
- * but the kernel also returns it when a ptrace-based debugger
- * attaches. This is a bug but it is hard to fix.
- */
while (nanosleep(&time_to_sleep, &time_to_sleep) != 0) {
+ if (errno != EINTR)
+ err(1, "nanosleep");
if (report_requested) {
/* Reporting does not bother with nanoseconds. */
- warnx("about %d second(s) left out of the original %d",
- (int)time_to_sleep.tv_sec, (int)original);
+ warnx("about %ld second(s) left out of the original %ld",
+ (long)time_to_sleep.tv_sec, (long)original);
report_requested = 0;
- } else if (errno != EINTR)
- err(1, "nanosleep");
+ }
}
- return (0);
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "usage: sleep number[unit] ...\n");
- fprintf(stderr, "Unit can be 's' (seconds, the default), "
- "m (minutes), h (hours), or d (days).\n");
- exit(1);
+ exit(0);
}