| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: sleep.c,v 1.29 2019/01/27 02:00:45 christos Exp $ */ | | 1 | /* $NetBSD: sleep.c,v 1.30 2019/03/10 15:18:45 kre Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1993, 1994 | | 4 | * Copyright (c) 1988, 1993, 1994 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -29,63 +29,66 @@ | | | @@ -29,63 +29,66 @@ |
29 | * SUCH DAMAGE. | | 29 | * SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | #ifndef lint | | 33 | #ifndef lint |
34 | __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\ | | 34 | __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\ |
35 | The Regents of the University of California. All rights reserved."); | | 35 | The Regents of the University of California. All rights reserved."); |
36 | #endif /* not lint */ | | 36 | #endif /* not lint */ |
37 | | | 37 | |
38 | #ifndef lint | | 38 | #ifndef lint |
39 | #if 0 | | 39 | #if 0 |
40 | static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94"; | | 40 | static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94"; |
41 | #else | | 41 | #else |
42 | __RCSID("$NetBSD: sleep.c,v 1.29 2019/01/27 02:00:45 christos Exp $"); | | 42 | __RCSID("$NetBSD: sleep.c,v 1.30 2019/03/10 15:18:45 kre Exp $"); |
43 | #endif | | 43 | #endif |
44 | #endif /* not lint */ | | 44 | #endif /* not lint */ |
45 | | | 45 | |
46 | #include <ctype.h> | | 46 | #include <ctype.h> |
47 | #include <err.h> | | 47 | #include <err.h> |
| | | 48 | #include <errno.h> |
48 | #include <locale.h> | | 49 | #include <locale.h> |
49 | #include <math.h> | | 50 | #include <math.h> |
50 | #include <signal.h> | | 51 | #include <signal.h> |
51 | #include <stdio.h> | | 52 | #include <stdio.h> |
52 | #include <stdlib.h> | | 53 | #include <stdlib.h> |
| | | 54 | #include <string.h> |
53 | #include <time.h> | | 55 | #include <time.h> |
54 | #include <unistd.h> | | 56 | #include <unistd.h> |
55 | | | 57 | |
56 | __dead static void alarmhandle(int); | | 58 | __dead static void alarmhandle(int); |
57 | __dead static void usage(void); | | 59 | __dead static void usage(void); |
58 | | | 60 | |
59 | static void report(const time_t, const time_t, const char *const); | | 61 | static void report(const time_t, const time_t, const char *const); |
60 | | | 62 | |
61 | static volatile sig_atomic_t report_requested; | | 63 | static volatile sig_atomic_t report_requested; |
62 | static void | | 64 | static void |
63 | report_request(int signo __unused) | | 65 | report_request(int signo __unused) |
64 | { | | 66 | { |
65 | | | 67 | |
66 | report_requested = 1; | | 68 | report_requested = 1; |
67 | } | | 69 | } |
68 | | | 70 | |
69 | int | | 71 | int |
70 | main(int argc, char *argv[]) | | 72 | main(int argc, char *argv[]) |
71 | { | | 73 | { |
72 | char *arg, *temp; | | 74 | char *arg, *temp; |
73 | const char *msg; | | 75 | const char *msg; |
74 | double fval, ival, val; | | 76 | double fval, ival, val; |
75 | struct timespec ntime; | | 77 | struct timespec ntime; |
| | | 78 | struct timespec endtime; |
| | | 79 | struct timespec now; |
76 | time_t original; | | 80 | time_t original; |
77 | int ch, fracflag; | | 81 | int ch, fracflag; |
78 | unsigned delay; | | | |
79 | | | 82 | |
80 | setprogname(argv[0]); | | 83 | setprogname(argv[0]); |
81 | (void)setlocale(LC_ALL, ""); | | 84 | (void)setlocale(LC_ALL, ""); |
82 | | | 85 | |
83 | (void)signal(SIGALRM, alarmhandle); | | 86 | (void)signal(SIGALRM, alarmhandle); |
84 | | | 87 | |
85 | while ((ch = getopt(argc, argv, "")) != -1) | | 88 | while ((ch = getopt(argc, argv, "")) != -1) |
86 | switch(ch) { | | 89 | switch(ch) { |
87 | default: | | 90 | default: |
88 | usage(); | | 91 | usage(); |
89 | } | | 92 | } |
90 | argc -= optind; | | 93 | argc -= optind; |
91 | argv += optind; | | 94 | argv += optind; |
| @@ -135,91 +138,104 @@ main(int argc, char *argv[]) | | | @@ -135,91 +138,104 @@ main(int argc, char *argv[]) |
135 | if (val < 0 || temp == arg || *temp != '\0') | | 138 | if (val < 0 || temp == arg || *temp != '\0') |
136 | usage(); | | 139 | usage(); |
137 | | | 140 | |
138 | ival = floor(val); | | 141 | ival = floor(val); |
139 | fval = (1000000000 * (val-ival)); | | 142 | fval = (1000000000 * (val-ival)); |
140 | ntime.tv_sec = ival; | | 143 | ntime.tv_sec = ival; |
141 | if ((double)ntime.tv_sec != ival) | | 144 | if ((double)ntime.tv_sec != ival) |
142 | errx(1, "requested delay (%s) out of range", arg); | | 145 | errx(1, "requested delay (%s) out of range", arg); |
143 | ntime.tv_nsec = fval; | | 146 | ntime.tv_nsec = fval; |
144 | | | 147 | |
145 | if (ntime.tv_sec == 0 && ntime.tv_nsec == 0) | | 148 | if (ntime.tv_sec == 0 && ntime.tv_nsec == 0) |
146 | return EXIT_SUCCESS; /* was 0.0 or underflowed */ | | 149 | return EXIT_SUCCESS; /* was 0.0 or underflowed */ |
147 | } else { | | 150 | } else { |
| | | 151 | errno = 0; |
148 | ntime.tv_sec = strtol(arg, &temp, 10); | | 152 | ntime.tv_sec = strtol(arg, &temp, 10); |
149 | if (ntime.tv_sec < 0 || temp == arg || *temp != '\0') | | 153 | if (ntime.tv_sec < 0 || temp == arg || *temp != '\0') |
150 | usage(); | | 154 | usage(); |
| | | 155 | if (errno == ERANGE) |
| | | 156 | errx(EXIT_FAILURE, "Requested delay (%s) out of range", |
| | | 157 | arg); |
| | | 158 | else if (errno != 0) |
| | | 159 | err(EXIT_FAILURE, "Requested delay (%s)", arg); |
151 | | | 160 | |
152 | if (ntime.tv_sec == 0) | | 161 | if (ntime.tv_sec == 0) |
153 | return EXIT_SUCCESS; | | 162 | return EXIT_SUCCESS; |
154 | ntime.tv_nsec = 0; | | 163 | ntime.tv_nsec = 0; |
155 | } | | 164 | } |
156 | | | 165 | |
157 | original = ntime.tv_sec; | | 166 | original = ntime.tv_sec; |
158 | if (ntime.tv_nsec != 0) | | 167 | if (original < 86400) { |
159 | msg = " and a bit"; | | 168 | if (ntime.tv_nsec > 1000000000 * 2 / 3) { |
160 | else | | 169 | original++; |
| | | 170 | msg = " less a bit"; |
| | | 171 | } else if (ntime.tv_nsec != 0) |
| | | 172 | msg = " and a bit"; |
| | | 173 | else |
| | | 174 | msg = ""; |
| | | 175 | } else |
161 | msg = ""; | | 176 | msg = ""; |
162 | | | 177 | |
| | | 178 | if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) |
| | | 179 | err(EXIT_FAILURE, "clock_gettime"); |
| | | 180 | timespecadd(&now, &ntime, &endtime); |
| | | 181 | |
| | | 182 | if (endtime.tv_sec < now.tv_sec || (endtime.tv_sec == now.tv_sec && |
| | | 183 | endtime.tv_nsec <= now.tv_nsec)) |
| | | 184 | errx(EXIT_FAILURE, "cannot sleep beyond the end of time"); |
| | | 185 | |
163 | signal(SIGINFO, report_request); | | 186 | signal(SIGINFO, report_request); |
| | | 187 | for (;;) { |
| | | 188 | int e; |
| | | 189 | |
| | | 190 | if ((e = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, |
| | | 191 | &endtime, NULL)) == 0) |
| | | 192 | return EXIT_SUCCESS; |
164 | | | 193 | |
165 | if (ntime.tv_sec <= 10000) { /* arbitrary */ | | 194 | if (!report_requested || e != EINTR) { |
166 | while (nanosleep(&ntime, &ntime) != 0) { | | 195 | errno = e; |
167 | if (report_requested) { | | 196 | err(EXIT_FAILURE, "clock_nanotime"); |
168 | report(ntime.tv_sec, original, msg); | | | |
169 | report_requested = 0; | | | |
170 | } else | | | |
171 | err(EXIT_FAILURE, "nanosleep failed"); | | | |
172 | } | | 197 | } |
173 | } else while (ntime.tv_sec > 0) { | | | |
174 | delay = (unsigned int)ntime.tv_sec; | | | |
175 | | | 198 | |
176 | if ((time_t)delay != ntime.tv_sec || delay > 30 * 86400) | | 199 | report_requested = 0; |
177 | delay = 30 * 86400; | | 200 | if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) /* Huh? */ |
| | | 201 | continue; |
178 | | | 202 | |
179 | ntime.tv_sec -= delay; | | 203 | timespecsub(&endtime, &now, &ntime); |
180 | delay = sleep(delay); | | 204 | report(ntime.tv_sec, original, msg); |
181 | ntime.tv_sec += delay; | | | |
182 | | | | |
183 | if (delay != 0 && report_requested) { | | | |
184 | report(ntime.tv_sec, original, ""); | | | |
185 | report_requested = 0; | | | |
186 | } else | | | |
187 | break; | | | |
188 | } | | 205 | } |
189 | | | | |
190 | return EXIT_SUCCESS; | | | |
191 | /* NOTREACHED */ | | | |
192 | } | | 206 | } |
193 | | | 207 | |
194 | /* Reporting does not bother with nanoseconds. */ | | 208 | /* Reporting does not bother with nanoseconds. */ |
195 | static void | | 209 | static void |
196 | report(const time_t remain, const time_t original, const char * const msg) | | 210 | report(const time_t remain, const time_t original, const char * const msg) |
197 | { | | 211 | { |
198 | if (remain == 0) | | 212 | if (remain == 0) |
199 | warnx("In the final moments of the original" | | 213 | warnx("In the final moments of the original" |
200 | " %jd%s second%s", (intmax_t)original, msg, | | 214 | " %g%s second%s", (double)original, msg, |
201 | original == 1 && *msg == '\0' ? "" : "s"); | | 215 | original == 1 && *msg == '\0' ? "" : "s"); |
202 | else if (remain < 2000) | | 216 | else if (remain < 2000) |
203 | warnx("Between %jd and %jd seconds left" | | 217 | warnx("Between %jd and %jd seconds left" |
204 | " out of the original %g%s", | | 218 | " out of the original %g%s", |
205 | (intmax_t)remain, (intmax_t)remain + 1, (double)original, | | 219 | (intmax_t)remain, (intmax_t)remain + 1, (double)original, |
206 | msg); | | 220 | msg); |
207 | else if ((original - remain) < 100000 && (original-remain) < original/8) | | 221 | else if ((original - remain) < 100000 && (original-remain) < original/8) |
208 | warnx("Have waited only %jd seconds of the original %g", | | 222 | warnx("Have waited only %jd second%s of the original %g%s", |
209 | (intmax_t)(original - remain), (double)original); | | 223 | (intmax_t)(original - remain), |
| | | 224 | (original - remain) == 1 ? "" : "s", |
| | | 225 | (double)original, msg); |
210 | else | | 226 | else |
211 | warnx("Approximately %g seconds left out of the original %g", | | 227 | warnx("Approximately %g seconds left out of the original %g%s", |
212 | (double)remain, (double)original); | | 228 | (double)remain, (double)original, msg); |
213 | } | | 229 | } |
214 | | | 230 | |
215 | static void | | 231 | static void |
216 | usage(void) | | 232 | usage(void) |
217 | { | | 233 | { |
218 | (void)fprintf(stderr, "usage: %s seconds\n", getprogname()); | | 234 | (void)fprintf(stderr, "usage: %s seconds\n", getprogname()); |
219 | exit(EXIT_FAILURE); | | 235 | exit(EXIT_FAILURE); |
220 | /* NOTREACHED */ | | 236 | /* NOTREACHED */ |
221 | } | | 237 | } |
222 | | | 238 | |
223 | /* ARGSUSED */ | | 239 | /* ARGSUSED */ |
224 | static void | | 240 | static void |
225 | alarmhandle(int i) | | 241 | alarmhandle(int i) |