diff --git a/bin/sleep/sleep.c b/bin/sleep/sleep.c --- a/bin/sleep/sleep.c +++ b/bin/sleep/sleep.c @@ -59,31 +59,42 @@ 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); - } + char *endptr; + + errno = 0; + num = strtod(arg, &endptr); + + /* No number found or overflow */ + if (endptr == arg || errno != 0 || isnan(num)) { + warnx("invalid time interval: %s", arg); + return (INFINITY); + } + + switch (*endptr) { + case '\0': + case 's': + break; + case 'm': + num *= 60; break; - case 1: - if (!isnan(num)) - return (num); + case 'h': + num *= 60 * 60; + break; + case 'd': + num *= 24 * 60 * 60; + break; + default: + warnx("invalid time interval: %s", arg); + return (INFINITY); } - warnx("invalid time interval: %s", arg); - return (INFINITY); + + /* Reject trailing garbage like 10ms or 10sx */ + if (*endptr != '\0' && endptr[1] != '\0') { + warnx("invalid time interval: %s", arg); + return (INFINITY); + } + + return (num); } int @@ -106,7 +117,7 @@ seconds = 0; while (argc--) seconds += parse_interval(*argv++); - if (seconds > INT_MAX) + if (seconds < 0 || seconds > (double)INT_MAX) usage(); if (seconds < 1e-9) exit(0); @@ -120,8 +131,9 @@ err(1, "nanosleep"); if (report_requested) { /* Reporting does not bother with nanoseconds. */ - warnx("about %ld second(s) left out of the original %ld", + printf("about %ld second(s) left out of the original %ld\n", (long)time_to_sleep.tv_sec, (long)original); + fflush(stdout); report_requested = 0; } }