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 #if !HAVE_POSIX_DECLS 35 extern char * optarg; 36 extern int optind; 37 #endif 38 39 static int retval = EXIT_SUCCESS; 40 41 static void display(const char *, time_t); 42 static void dogmt(void); 43 static void errensure(void); 44 static void timeout(FILE *, const char *, const struct tm *); 45 static ATTRIBUTE_NORETURN void usage(void); 46 47 int 48 main(const int argc, char *argv[]) 49 { 50 register const char * format = "+%+"; 51 register int ch; 52 register bool rflag = false; 53 time_t t; 54 intmax_t secs; 55 char * endarg; 56 57 #ifdef LC_ALL 58 setlocale(LC_ALL, ""); 59 #endif /* defined(LC_ALL) */ 60 #if HAVE_GETTEXT 61 # ifdef TZ_DOMAINDIR 62 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 63 # endif /* defined(TEXTDOMAINDIR) */ 64 textdomain(TZ_DOMAIN); 65 #endif /* HAVE_GETTEXT */ 66 t = time(NULL); 67 while ((ch = getopt(argc, argv, "ucr:")) != EOF && ch != -1) { 68 switch (ch) { 69 default: 70 usage(); 71 case 'u': /* do it in UT */ 72 case 'c': 73 dogmt(); 74 break; 75 case 'r': /* seconds since 1970 */ 76 if (rflag) { 77 fprintf(stderr, 78 _("date: error: multiple -r's used")); 79 usage(); 80 } 81 rflag = true; 82 errno = 0; 83 secs = strtoimax(optarg, &endarg, 0); 84 if (*endarg || optarg == endarg) 85 errno = EINVAL; 86 else if (! (TIME_T_MIN <= secs && secs <= TIME_T_MAX)) 87 errno = ERANGE; 88 if (errno) { 89 perror(optarg); 90 errensure(); 91 exit(retval); 92 } 93 t = secs; 94 break; 95 } 96 } 97 if (optind < argc) { 98 if (argc - optind != 1) { 99 fprintf(stderr, 100 _("date: error: multiple operands in command line\n")); 101 usage(); 102 } 103 format = argv[optind]; 104 if (*format != '+') { 105 fprintf(stderr, _("date: unknown operand: %s\n"), format); 106 usage(); 107 } 108 } 109 110 display(format, t); 111 return retval; 112 } 113 114 static void 115 dogmt(void) 116 { 117 static char ** fakeenv; 118 119 if (fakeenv == NULL) { 120 static char tzeutc0[] = "TZ=UTC0"; 121 ptrdiff_t from, to, n; 122 123 for (n = 0; environ[n] != NULL; ++n) 124 continue; 125 #if defined ckd_add && defined ckd_mul 126 if (!ckd_add(&n, n, 2) && !ckd_mul(&n, n, sizeof *fakeenv) 127 && n <= SIZE_MAX) 128 fakeenv = malloc(n); 129 #else 130 if (n <= min(PTRDIFF_MAX, SIZE_MAX) / sizeof *fakeenv - 2) 131 fakeenv = malloc((n + 2) * sizeof *fakeenv); 132 #endif 133 if (fakeenv == NULL) { 134 fprintf(stderr, _("date: Memory exhausted\n")); 135 errensure(); 136 exit(retval); 137 } 138 to = 0; 139 fakeenv[to++] = tzeutc0; 140 for (from = 1; environ[from] != NULL; ++from) 141 if (strncmp(environ[from], "TZ=", 3) != 0) 142 fakeenv[to++] = environ[from]; 143 fakeenv[to] = NULL; 144 environ = fakeenv; 145 } 146 } 147 148 static void 149 errensure(void) 150 { 151 if (retval == EXIT_SUCCESS) 152 retval = EXIT_FAILURE; 153 } 154 155 static void 156 usage(void) 157 { 158 fprintf(stderr, 159 _("date: usage: date [-u] [-c] [-r seconds]" 160 " [+format]\n")); 161 errensure(); 162 exit(retval); 163 } 164 165 static void 166 display(char const *format, time_t now) 167 { 168 struct tm *tmp; 169 170 tmp = localtime(&now); 171 if (!tmp) { 172 fprintf(stderr, 173 _("date: error: time out of range\n")); 174 errensure(); 175 return; 176 } 177 timeout(stdout, format, tmp); 178 putchar('\n'); 179 fflush(stdout); 180 fflush(stderr); 181 if (ferror(stdout) || ferror(stderr)) { 182 fprintf(stderr, 183 _("date: error: couldn't write results\n")); 184 errensure(); 185 } 186 } 187 188 static void 189 timeout(FILE *fp, char const *format, struct tm const *tmp) 190 { 191 char *cp = NULL; 192 ptrdiff_t result; 193 ptrdiff_t size = 1024 / 2; 194 195 for ( ; ; ) { 196 #ifdef ckd_mul 197 bool bigger = !ckd_mul(&size, size, 2) && size <= SIZE_MAX; 198 #else 199 bool bigger = (size <= min(PTRDIFF_MAX, SIZE_MAX) / 2 200 && (size *= 2, true)); 201 #endif 202 char *newcp = bigger ? realloc(cp, size) : NULL; 203 if (!newcp) { 204 fprintf(stderr, 205 _("date: error: can't get memory\n")); 206 errensure(); 207 exit(retval); 208 } 209 cp = newcp; 210 result = strftime(cp, size, format, tmp); 211 if (result != 0) 212 break; 213 } 214 fwrite(cp + 1, 1, result - 1, fp); 215 free(cp); 216 } 217