1 /* Display or set the current time and date. */
2
3 /* Copyright 1985, 1987, 1988 The Regents of the University of California.
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 3. Neither the name of the University nor the names of its contributors
15 may be used to endorse or promote products derived from this software
16 without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 SUCH DAMAGE. */
29
30 #include "private.h"
31 #include <locale.h>
32 #include <stdio.h>
33
34 /*
35 ** The two things date knows about time are. . .
36 */
37
38 #ifndef TM_YEAR_BASE
39 #define TM_YEAR_BASE 1900
40 #endif /* !defined TM_YEAR_BASE */
41
42 #ifndef SECSPERMIN
43 #define SECSPERMIN 60
44 #endif /* !defined SECSPERMIN */
45
46 #if !HAVE_POSIX_DECLS
47 extern char * optarg;
48 extern int optind;
49 #endif
50
51 static int retval = EXIT_SUCCESS;
52
53 static void display(const char *, time_t);
54 static void dogmt(void);
55 static void errensure(void);
56 static void timeout(FILE *, const char *, const struct tm *);
57 static _Noreturn void usage(void);
58
59 int
main(const int argc,char * argv[])60 main(const int argc, char *argv[])
61 {
62 register const char * format = "+%+";
63 register int ch;
64 register bool rflag = false;
65 time_t t;
66 intmax_t secs;
67 char * endarg;
68
69 #ifdef LC_ALL
70 setlocale(LC_ALL, "");
71 #endif /* defined(LC_ALL) */
72 #if HAVE_GETTEXT
73 #ifdef TZ_DOMAINDIR
74 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
75 #endif /* defined(TEXTDOMAINDIR) */
76 textdomain(TZ_DOMAIN);
77 #endif /* HAVE_GETTEXT */
78 t = time(NULL);
79 while ((ch = getopt(argc, argv, "ucr:")) != EOF && ch != -1) {
80 switch (ch) {
81 default:
82 usage();
83 case 'u': /* do it in UT */
84 case 'c':
85 dogmt();
86 break;
87 case 'r': /* seconds since 1970 */
88 if (rflag) {
89 fprintf(stderr,
90 _("date: error: multiple -r's used"));
91 usage();
92 }
93 rflag = true;
94 errno = 0;
95 secs = strtoimax(optarg, &endarg, 0);
96 if (*endarg || optarg == endarg)
97 errno = EINVAL;
98 else if (! (TIME_T_MIN <= secs && secs <= TIME_T_MAX))
99 errno = ERANGE;
100 if (errno) {
101 perror(optarg);
102 errensure();
103 exit(retval);
104 }
105 t = secs;
106 break;
107 }
108 }
109 if (optind < argc) {
110 if (argc - optind != 1) {
111 fprintf(stderr,
112 _("date: error: multiple operands in command line\n"));
113 usage();
114 }
115 format = argv[optind];
116 if (*format != '+') {
117 fprintf(stderr, _("date: unknown operand: %s\n"), format);
118 usage();
119 }
120 }
121
122 display(format, t);
123 return retval;
124 }
125
126 static void
dogmt(void)127 dogmt(void)
128 {
129 static char ** fakeenv;
130
131 if (fakeenv == NULL) {
132 register int from;
133 register int to;
134 register int n;
135 static char tzegmt0[] = "TZ=GMT0";
136
137 for (n = 0; environ[n] != NULL; ++n)
138 continue;
139 fakeenv = malloc((n + 2) * sizeof *fakeenv);
140 if (fakeenv == NULL) {
141 fprintf(stderr, _("date: Memory exhausted\n"));
142 errensure();
143 exit(retval);
144 }
145 to = 0;
146 fakeenv[to++] = tzegmt0;
147 for (from = 1; environ[from] != NULL; ++from)
148 if (strncmp(environ[from], "TZ=", 3) != 0)
149 fakeenv[to++] = environ[from];
150 fakeenv[to] = NULL;
151 environ = fakeenv;
152 }
153 }
154
155 static void
errensure(void)156 errensure(void)
157 {
158 if (retval == EXIT_SUCCESS)
159 retval = EXIT_FAILURE;
160 }
161
162 static void
usage(void)163 usage(void)
164 {
165 fprintf(stderr,
166 _("date: usage: date [-u] [-c] [-r seconds]"
167 " [+format]\n"));
168 errensure();
169 exit(retval);
170 }
171
172 static void
display(char const * format,time_t now)173 display(char const *format, time_t now)
174 {
175 struct tm *tmp;
176
177 tmp = localtime(&now);
178 if (!tmp) {
179 fprintf(stderr,
180 _("date: error: time out of range\n"));
181 errensure();
182 return;
183 }
184 timeout(stdout, format, tmp);
185 putchar('\n');
186 fflush(stdout);
187 fflush(stderr);
188 if (ferror(stdout) || ferror(stderr)) {
189 fprintf(stderr,
190 _("date: error: couldn't write results\n"));
191 errensure();
192 }
193 }
194
195 #define INCR 1024
196
197 static void
timeout(FILE * fp,char const * format,struct tm const * tmp)198 timeout(FILE *fp, char const *format, struct tm const *tmp)
199 {
200 char * cp;
201 size_t result;
202 size_t size;
203 struct tm tm;
204
205 if (!tmp) {
206 fprintf(stderr, _("date: error: time out of range\n"));
207 errensure();
208 return;
209 }
210 tm = *tmp;
211 tmp = &tm;
212 size = INCR;
213 cp = malloc(size);
214 for ( ; ; ) {
215 if (cp == NULL) {
216 fprintf(stderr,
217 _("date: error: can't get memory\n"));
218 errensure();
219 exit(retval);
220 }
221 result = strftime(cp, size, format, tmp);
222 if (result != 0)
223 break;
224 size += INCR;
225 cp = realloc(cp, size);
226 }
227 fwrite(cp + 1, 1, result - 1, fp);
228 free(cp);
229 }
230