sleep.c (2594B)
- // Collection of Unix tools, comparable to coreutils
- // SPDX-FileCopyrightText: 2017-2023 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _POSIX_C_SOURCE 200809L
- #include <errno.h> // errno
- #include <stdio.h> // fprintf, perror, sscanf
- #include <stdlib.h> // exit
- #include <time.h> // nanosleep, timespec
- // Maybe should be moved in ./lib with iso_parse
- static struct timespec
- strtodur(char *s)
- {
- struct timespec dur = {.tv_sec = 0, .tv_nsec = 0};
- if(s[0] == 0)
- {
- fprintf(stderr, "sleep: Got an empty string as duration\n");
- return dur;
- }
- int parsed = 0;
- if(s[0] != '.' && s[0] != ',')
- {
- errno = 0;
- int ret = sscanf(s, "%10ld%n", &dur.tv_sec, &parsed);
- if(ret < 1)
- {
- if(errno == 0)
- {
- fprintf(stderr, "sleep: Not a number: %s\n", s);
- }
- else
- {
- perror("sleep: sscanf");
- }
- exit(EXIT_FAILURE);
- }
- s += parsed;
- if(s[0] == 0) return dur;
- }
- if(s[0] == '.' || s[0] == ',')
- {
- float fraction = 0.0;
- if(s[1] == 0) return dur;
- if(s[0] == ',') s[0] = '.';
- parsed = 0;
- errno = 0;
- if(sscanf(s, "%10f%n", &fraction, &parsed) < 1)
- {
- if(errno == 0)
- {
- fprintf(stderr, "sleep: Decimal part is not a number: %s\n", s);
- }
- else
- {
- perror("sleep: sscanf");
- }
- exit(EXIT_FAILURE);
- }
- dur.tv_nsec = fraction * 1000000000;
- s += parsed;
- }
- if(s[0] == 0) return dur;
- if(s[1] != 0)
- {
- fprintf(stderr, "sleep: suffix '%s' is too long, should be only one character\n", s);
- exit(1);
- }
- switch(s[0])
- {
- case 's': // seconds
- break;
- case 'm': // minutes
- dur.tv_sec *= 60;
- break;
- case 'h': // hours
- dur.tv_sec *= 60 * 60;
- break;
- default:
- fprintf(stderr, "sleep: Unknown suffix %c\n", s[0]);
- exit(1);
- }
- return dur;
- }
- int
- main(int argc, char *argv[])
- {
- struct timespec dur = {.tv_sec = 0, .tv_nsec = 0};
- for(int i = 1; i < argc; i++)
- {
- struct timespec arg_dur = strtodur(argv[i]);
- dur.tv_sec += arg_dur.tv_sec;
- dur.tv_nsec += arg_dur.tv_nsec;
- if(dur.tv_nsec > 999999999)
- {
- dur.tv_nsec = 0;
- dur.tv_sec += 1;
- }
- }
- if(dur.tv_sec == 0 && dur.tv_nsec == 0)
- {
- fprintf(stderr, "sleep: Got a duration of 0\n");
- return 1;
- }
- //fprintf(stderr, "sleep: going to sleep for %ld.%09ld seconds\n", dur.tv_sec, dur.tv_nsec);
- errno = 0;
- if(nanosleep(&dur, &dur) < 0)
- {
- if(errno == EINTR)
- {
- fprintf(stderr,
- "sleep: Interrupted during sleep, still had %ld.%09ld seconds remaining\n",
- dur.tv_sec,
- dur.tv_nsec);
- }
- else
- {
- perror("sleep: nanosleep");
- }
- }
- return 0;
- }