diff options
Diffstat (limited to 'bin/sleep/sleep.c')
-rw-r--r-- | bin/sleep/sleep.c | 125 |
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); } |