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