logo

utils

~/.local/bin tools and git-hooks git clone https://hacktivis.me/git/utils.git

sleep.c (2594B)


  1. // Collection of Unix tools, comparable to coreutils
  2. // SPDX-FileCopyrightText: 2017-2023 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include <errno.h> // errno
  6. #include <stdio.h> // fprintf, perror, sscanf
  7. #include <stdlib.h> // exit
  8. #include <time.h> // nanosleep, timespec
  9. // Maybe should be moved in ./lib with iso_parse
  10. static struct timespec
  11. strtodur(char *s)
  12. {
  13. struct timespec dur = {.tv_sec = 0, .tv_nsec = 0};
  14. if(s[0] == 0)
  15. {
  16. fprintf(stderr, "sleep: Got an empty string as duration\n");
  17. return dur;
  18. }
  19. int parsed = 0;
  20. if(s[0] != '.' && s[0] != ',')
  21. {
  22. errno = 0;
  23. int ret = sscanf(s, "%10ld%n", &dur.tv_sec, &parsed);
  24. if(ret < 1)
  25. {
  26. if(errno == 0)
  27. {
  28. fprintf(stderr, "sleep: Not a number: %s\n", s);
  29. }
  30. else
  31. {
  32. perror("sleep: sscanf");
  33. }
  34. exit(EXIT_FAILURE);
  35. }
  36. s += parsed;
  37. if(s[0] == 0) return dur;
  38. }
  39. if(s[0] == '.' || s[0] == ',')
  40. {
  41. float fraction = 0.0;
  42. if(s[1] == 0) return dur;
  43. if(s[0] == ',') s[0] = '.';
  44. parsed = 0;
  45. errno = 0;
  46. if(sscanf(s, "%10f%n", &fraction, &parsed) < 1)
  47. {
  48. if(errno == 0)
  49. {
  50. fprintf(stderr, "sleep: Decimal part is not a number: %s\n", s);
  51. }
  52. else
  53. {
  54. perror("sleep: sscanf");
  55. }
  56. exit(EXIT_FAILURE);
  57. }
  58. dur.tv_nsec = fraction * 1000000000;
  59. s += parsed;
  60. }
  61. if(s[0] == 0) return dur;
  62. if(s[1] != 0)
  63. {
  64. fprintf(stderr, "sleep: suffix '%s' is too long, should be only one character\n", s);
  65. exit(1);
  66. }
  67. switch(s[0])
  68. {
  69. case 's': // seconds
  70. break;
  71. case 'm': // minutes
  72. dur.tv_sec *= 60;
  73. break;
  74. case 'h': // hours
  75. dur.tv_sec *= 60 * 60;
  76. break;
  77. default:
  78. fprintf(stderr, "sleep: Unknown suffix %c\n", s[0]);
  79. exit(1);
  80. }
  81. return dur;
  82. }
  83. int
  84. main(int argc, char *argv[])
  85. {
  86. struct timespec dur = {.tv_sec = 0, .tv_nsec = 0};
  87. for(int i = 1; i < argc; i++)
  88. {
  89. struct timespec arg_dur = strtodur(argv[i]);
  90. dur.tv_sec += arg_dur.tv_sec;
  91. dur.tv_nsec += arg_dur.tv_nsec;
  92. if(dur.tv_nsec > 999999999)
  93. {
  94. dur.tv_nsec = 0;
  95. dur.tv_sec += 1;
  96. }
  97. }
  98. if(dur.tv_sec == 0 && dur.tv_nsec == 0)
  99. {
  100. fprintf(stderr, "sleep: Got a duration of 0\n");
  101. return 1;
  102. }
  103. //fprintf(stderr, "sleep: going to sleep for %ld.%09ld seconds\n", dur.tv_sec, dur.tv_nsec);
  104. errno = 0;
  105. if(nanosleep(&dur, &dur) < 0)
  106. {
  107. if(errno == EINTR)
  108. {
  109. fprintf(stderr,
  110. "sleep: Interrupted during sleep, still had %ld.%09ld seconds remaining\n",
  111. dur.tv_sec,
  112. dur.tv_nsec);
  113. }
  114. else
  115. {
  116. perror("sleep: nanosleep");
  117. }
  118. }
  119. return 0;
  120. }