xref: /illumos-gate/usr/src/cmd/sleep/sleep.c (revision b871f899)
1*b871f899SRobert Mustacchi /*
2*b871f899SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*b871f899SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*b871f899SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*b871f899SRobert Mustacchi  * 1.0 of the CDDL.
6*b871f899SRobert Mustacchi  *
7*b871f899SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*b871f899SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*b871f899SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*b871f899SRobert Mustacchi  */
11*b871f899SRobert Mustacchi 
12*b871f899SRobert Mustacchi /*
13*b871f899SRobert Mustacchi  * Copyright 2019 Robert Mustacchi
14*b871f899SRobert Mustacchi  */
15*b871f899SRobert Mustacchi 
16*b871f899SRobert Mustacchi #include <locale.h>
17*b871f899SRobert Mustacchi #include <stdlib.h>
18*b871f899SRobert Mustacchi #include <signal.h>
19*b871f899SRobert Mustacchi #include <unistd.h>
20*b871f899SRobert Mustacchi #include <stdio.h>
21*b871f899SRobert Mustacchi #include <err.h>
22*b871f899SRobert Mustacchi #include <errno.h>
23*b871f899SRobert Mustacchi #include <math.h>
24*b871f899SRobert Mustacchi #include <limits.h>
25*b871f899SRobert Mustacchi #include <time.h>
26*b871f899SRobert Mustacchi #include <libintl.h>
27*b871f899SRobert Mustacchi 
28*b871f899SRobert Mustacchi /*
29*b871f899SRobert Mustacchi  * This implements the sleep(1) command. It allows for a number of extensions
30*b871f899SRobert Mustacchi  * that match both the GNU implementation and parts of what ksh93 used to
31*b871f899SRobert Mustacchi  * provide. Mainly:
32*b871f899SRobert Mustacchi  *
33*b871f899SRobert Mustacchi  *  o Fractional seconds
34*b871f899SRobert Mustacchi  *  o Suffixes that change the amount of time
35*b871f899SRobert Mustacchi  */
36*b871f899SRobert Mustacchi 
37*b871f899SRobert Mustacchi typedef struct {
38*b871f899SRobert Mustacchi 	char		sm_char;
39*b871f899SRobert Mustacchi 	uint64_t	sm_adj;
40*b871f899SRobert Mustacchi } sleep_map_t;
41*b871f899SRobert Mustacchi 
42*b871f899SRobert Mustacchi static const sleep_map_t sleep_map[] = {
43*b871f899SRobert Mustacchi 	{ 's', 1 },
44*b871f899SRobert Mustacchi 	{ 'm', 60 },
45*b871f899SRobert Mustacchi 	{ 'h', 60 * 60 },
46*b871f899SRobert Mustacchi 	{ 'd', 60 * 60 * 24 },
47*b871f899SRobert Mustacchi 	{ 'w', 60 * 60 * 24 * 7 },
48*b871f899SRobert Mustacchi 	{ 'y', 60 * 60 * 24 * 365 },
49*b871f899SRobert Mustacchi 	{ '\0', 0 }
50*b871f899SRobert Mustacchi };
51*b871f899SRobert Mustacchi 
52*b871f899SRobert Mustacchi static void
sleep_sigalrm(int sig)53*b871f899SRobert Mustacchi sleep_sigalrm(int sig)
54*b871f899SRobert Mustacchi {
55*b871f899SRobert Mustacchi 	/*
56*b871f899SRobert Mustacchi 	 * Note, the normal exit(2) function is not Async-Signal-Safe.
57*b871f899SRobert Mustacchi 	 */
58*b871f899SRobert Mustacchi 	_exit(0);
59*b871f899SRobert Mustacchi }
60*b871f899SRobert Mustacchi 
61*b871f899SRobert Mustacchi int
main(int argc,char * argv[])62*b871f899SRobert Mustacchi main(int argc, char *argv[])
63*b871f899SRobert Mustacchi {
64*b871f899SRobert Mustacchi 	int c;
65*b871f899SRobert Mustacchi 	long double d, sec, frac;
66*b871f899SRobert Mustacchi 	char *eptr;
67*b871f899SRobert Mustacchi 
68*b871f899SRobert Mustacchi 	(void) setlocale(LC_ALL, "");
69*b871f899SRobert Mustacchi #if !defined(TEXT_DOMAIN)
70*b871f899SRobert Mustacchi #define	TEXT_DOMAIN "SYS_TEST"
71*b871f899SRobert Mustacchi #endif
72*b871f899SRobert Mustacchi 	(void) textdomain(TEXT_DOMAIN);
73*b871f899SRobert Mustacchi 
74*b871f899SRobert Mustacchi 	(void) signal(SIGALRM, sleep_sigalrm);
75*b871f899SRobert Mustacchi 
76*b871f899SRobert Mustacchi 	while ((c = getopt(argc, argv, ":")) != -1) {
77*b871f899SRobert Mustacchi 		switch (c) {
78*b871f899SRobert Mustacchi 		case '?':
79*b871f899SRobert Mustacchi 			warnx(gettext("illegal option -- %c"), optopt);
80*b871f899SRobert Mustacchi 			(void) fprintf(stderr,
81*b871f899SRobert Mustacchi 			    gettext("Usage: sleep time[suffix]\n"));
82*b871f899SRobert Mustacchi 			exit(EXIT_FAILURE);
83*b871f899SRobert Mustacchi 		}
84*b871f899SRobert Mustacchi 	}
85*b871f899SRobert Mustacchi 
86*b871f899SRobert Mustacchi 	argc -= optind;
87*b871f899SRobert Mustacchi 	argv += optind;
88*b871f899SRobert Mustacchi 
89*b871f899SRobert Mustacchi 	if (argc != 1) {
90*b871f899SRobert Mustacchi 		warnx(gettext("only one operand is supported"));
91*b871f899SRobert Mustacchi 		(void) fprintf(stderr, gettext("Usage: sleep time[suffix]\n"));
92*b871f899SRobert Mustacchi 		exit(EXIT_FAILURE);
93*b871f899SRobert Mustacchi 	}
94*b871f899SRobert Mustacchi 
95*b871f899SRobert Mustacchi 	errno = 0;
96*b871f899SRobert Mustacchi 	d = strtold(argv[0], &eptr);
97*b871f899SRobert Mustacchi 	if (errno != 0 || (eptr[0] != '\0' && eptr[1] != '\0') ||
98*b871f899SRobert Mustacchi 	    eptr == argv[0] || d == NAN) {
99*b871f899SRobert Mustacchi 		errx(EXIT_FAILURE, gettext("failed to parse time '%s'"),
100*b871f899SRobert Mustacchi 		    argv[0]);
101*b871f899SRobert Mustacchi 	}
102*b871f899SRobert Mustacchi 
103*b871f899SRobert Mustacchi 	if (d < 0.0) {
104*b871f899SRobert Mustacchi 		errx(EXIT_FAILURE,
105*b871f899SRobert Mustacchi 		    gettext("time interval '%s', cannot be negative"), argv[0]);
106*b871f899SRobert Mustacchi 	}
107*b871f899SRobert Mustacchi 
108*b871f899SRobert Mustacchi 	if (eptr[0] != '\0') {
109*b871f899SRobert Mustacchi 		int i;
110*b871f899SRobert Mustacchi 		for (i = 0; sleep_map[i].sm_char != '\0'; i++) {
111*b871f899SRobert Mustacchi 			if (sleep_map[i].sm_char == eptr[0]) {
112*b871f899SRobert Mustacchi 				d *= sleep_map[i].sm_adj;
113*b871f899SRobert Mustacchi 				break;
114*b871f899SRobert Mustacchi 			}
115*b871f899SRobert Mustacchi 		}
116*b871f899SRobert Mustacchi 
117*b871f899SRobert Mustacchi 		if (sleep_map[i].sm_char == '\0') {
118*b871f899SRobert Mustacchi 			errx(EXIT_FAILURE, gettext("failed to parse time %s"),
119*b871f899SRobert Mustacchi 			    argv[0]);
120*b871f899SRobert Mustacchi 		}
121*b871f899SRobert Mustacchi 	}
122*b871f899SRobert Mustacchi 
123*b871f899SRobert Mustacchi 	/*
124*b871f899SRobert Mustacchi 	 * If we have no time, then we're done. Short circuit.
125*b871f899SRobert Mustacchi 	 */
126*b871f899SRobert Mustacchi 	if (d == 0) {
127*b871f899SRobert Mustacchi 		exit(EXIT_SUCCESS);
128*b871f899SRobert Mustacchi 	}
129*b871f899SRobert Mustacchi 
130*b871f899SRobert Mustacchi 	/*
131*b871f899SRobert Mustacchi 	 * Split this apart into the fractional and seconds parts to make it
132*b871f899SRobert Mustacchi 	 * easier to work with.
133*b871f899SRobert Mustacchi 	 */
134*b871f899SRobert Mustacchi 	frac = modfl(d, &sec);
135*b871f899SRobert Mustacchi 
136*b871f899SRobert Mustacchi 	/*
137*b871f899SRobert Mustacchi 	 * We may have a rather large double value. Chop it up in units of
138*b871f899SRobert Mustacchi 	 * INT_MAX.
139*b871f899SRobert Mustacchi 	 */
140*b871f899SRobert Mustacchi 	while (sec > 0 || frac != 0) {
141*b871f899SRobert Mustacchi 		struct timespec ts;
142*b871f899SRobert Mustacchi 
143*b871f899SRobert Mustacchi 		if (frac != 0) {
144*b871f899SRobert Mustacchi 			frac *= NANOSEC;
145*b871f899SRobert Mustacchi 			ts.tv_nsec = (long)frac;
146*b871f899SRobert Mustacchi 			frac = 0;
147*b871f899SRobert Mustacchi 		} else {
148*b871f899SRobert Mustacchi 			ts.tv_nsec = 0;
149*b871f899SRobert Mustacchi 		}
150*b871f899SRobert Mustacchi 
151*b871f899SRobert Mustacchi 		/*
152*b871f899SRobert Mustacchi 		 * We have a floating point number of fractional seconds. We
153*b871f899SRobert Mustacchi 		 * need to convert that to nanoseconds.
154*b871f899SRobert Mustacchi 		 */
155*b871f899SRobert Mustacchi 		if (sec > (float)INT_MAX) {
156*b871f899SRobert Mustacchi 			ts.tv_sec = INT_MAX;
157*b871f899SRobert Mustacchi 		} else {
158*b871f899SRobert Mustacchi 			ts.tv_sec = (time_t)sec;
159*b871f899SRobert Mustacchi 		}
160*b871f899SRobert Mustacchi 		sec -= ts.tv_sec;
161*b871f899SRobert Mustacchi 
162*b871f899SRobert Mustacchi 		if (nanosleep(&ts, NULL) != 0) {
163*b871f899SRobert Mustacchi 			err(EXIT_FAILURE, gettext("nanosleep failed"));
164*b871f899SRobert Mustacchi 		}
165*b871f899SRobert Mustacchi 	}
166*b871f899SRobert Mustacchi 
167*b871f899SRobert Mustacchi 	return (0);
168*b871f899SRobert Mustacchi }
169