1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 1987-2000 by Sun Microsystems, Inc. 24*7c478bd9Sstevel@tonic-gate * All rights reserved. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Time management functions for auditreduce. 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include "auditr.h" 34*7c478bd9Sstevel@tonic-gate #include <locale.h> 35*7c478bd9Sstevel@tonic-gate #include <libintl.h> 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate int derive_date(char *, struct tm *); 38*7c478bd9Sstevel@tonic-gate void derive_str(time_t, char *); 39*7c478bd9Sstevel@tonic-gate int parse_time(char *, int); 40*7c478bd9Sstevel@tonic-gate time_t tm_to_secs(struct tm *); 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate static int check_time(struct tm *); 43*7c478bd9Sstevel@tonic-gate static int days_in_year(int); 44*7c478bd9Sstevel@tonic-gate static char *do_invalid(void); 45*7c478bd9Sstevel@tonic-gate static time_t local_to_gm(struct tm *); 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate static char *invalid_inter = NULL; 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* 50*7c478bd9Sstevel@tonic-gate * Array of days per month. 51*7c478bd9Sstevel@tonic-gate */ 52*7c478bd9Sstevel@tonic-gate static int days_month[] = { 53*7c478bd9Sstevel@tonic-gate 31, 28, 31, 30, 31, 30, 54*7c478bd9Sstevel@tonic-gate 31, 31, 30, 31, 30, 31 }; 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate char * 57*7c478bd9Sstevel@tonic-gate do_invalid(void) 58*7c478bd9Sstevel@tonic-gate { 59*7c478bd9Sstevel@tonic-gate if (invalid_inter == NULL) 60*7c478bd9Sstevel@tonic-gate invalid_inter = gettext("invalid date/time format -"); 61*7c478bd9Sstevel@tonic-gate return (invalid_inter); 62*7c478bd9Sstevel@tonic-gate } 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * .func local_to_gm - local time to gm time. 66*7c478bd9Sstevel@tonic-gate * .desc Convert a local time to Greenwhich Mean Time. 67*7c478bd9Sstevel@tonic-gate * The local time is in the struct tm (time.h) format, which 68*7c478bd9Sstevel@tonic-gate * is easily got from an ASCII input format (10:30:33 Jan 3, 1983). 69*7c478bd9Sstevel@tonic-gate * It works by assuming that the given local time is a GMT time and 70*7c478bd9Sstevel@tonic-gate * then asking the system for the corresponding local time. It then 71*7c478bd9Sstevel@tonic-gate * takes the difference between those two as the correction for 72*7c478bd9Sstevel@tonic-gate * time zones and daylight savings time. This is accurate unless 73*7c478bd9Sstevel@tonic-gate * the time the user asked for is near a DST switch. Then a 74*7c478bd9Sstevel@tonic-gate * correction is applied - it is assumed that if we can produce 75*7c478bd9Sstevel@tonic-gate * a GMT that, when run through localtime(), is equivalent to the 76*7c478bd9Sstevel@tonic-gate * user's original input, we have an accurate GMT. The applied 77*7c478bd9Sstevel@tonic-gate * correction simply adjusts the GMT by the amount that the derived 78*7c478bd9Sstevel@tonic-gate * localtime was off. See? 79*7c478bd9Sstevel@tonic-gate * It should be noted that when there is DST there is one local hour 80*7c478bd9Sstevel@tonic-gate * a year when time occurs twice (in the fall) and one local hour a 81*7c478bd9Sstevel@tonic-gate * year when time never occurs (in the spring). 82*7c478bd9Sstevel@tonic-gate * memcpy() is used because the calls to gmtime() and localtime() 83*7c478bd9Sstevel@tonic-gate * return pointers to static structures that are overwritten at each 84*7c478bd9Sstevel@tonic-gate * call. 85*7c478bd9Sstevel@tonic-gate * .call ret = local_to_gm(tme). 86*7c478bd9Sstevel@tonic-gate * .arg tme - ptr to struct tm (see time.h) containing local time. 87*7c478bd9Sstevel@tonic-gate * .ret time_t - seconds since epoch of equivalent GMT. 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate time_t 90*7c478bd9Sstevel@tonic-gate local_to_gm(struct tm *tme) 91*7c478bd9Sstevel@tonic-gate { 92*7c478bd9Sstevel@tonic-gate time_t secs, gsecs, lsecs, save_gsecs; 93*7c478bd9Sstevel@tonic-gate time_t r1secs, r2secs; 94*7c478bd9Sstevel@tonic-gate struct tm ltime, gtime; 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate * Get the input time in local and gmtime assuming the input 98*7c478bd9Sstevel@tonic-gate * was GMT (which it probably wasn't). 99*7c478bd9Sstevel@tonic-gate */ 100*7c478bd9Sstevel@tonic-gate r1secs = secs = tm_to_secs(tme); 101*7c478bd9Sstevel@tonic-gate (void) memcpy((void *)>ime, (void *)gmtime(&secs), sizeof (gtime)); 102*7c478bd9Sstevel@tonic-gate (void) memcpy((void *)<ime, (void *)localtime(&secs), sizeof (ltime)); 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /* 105*7c478bd9Sstevel@tonic-gate * Get the local and gmtime in seconds, from the above tm structures. 106*7c478bd9Sstevel@tonic-gate * Calculate difference between local and GMT. 107*7c478bd9Sstevel@tonic-gate */ 108*7c478bd9Sstevel@tonic-gate gsecs = tm_to_secs(>ime); 109*7c478bd9Sstevel@tonic-gate lsecs = tm_to_secs(<ime); 110*7c478bd9Sstevel@tonic-gate secs = lsecs - gsecs; 111*7c478bd9Sstevel@tonic-gate gsecs -= secs; 112*7c478bd9Sstevel@tonic-gate (void) memcpy((void *)<ime, (void *)localtime(&gsecs), 113*7c478bd9Sstevel@tonic-gate sizeof (ltime)); 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate /* 116*7c478bd9Sstevel@tonic-gate * Now get a computed local time from the computed gmtime. 117*7c478bd9Sstevel@tonic-gate */ 118*7c478bd9Sstevel@tonic-gate save_gsecs = gsecs; 119*7c478bd9Sstevel@tonic-gate r2secs = tm_to_secs(<ime); 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate /* 122*7c478bd9Sstevel@tonic-gate * If the user given local time is != computed local time then 123*7c478bd9Sstevel@tonic-gate * we need to try a correction. 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate if (r1secs != r2secs) { 126*7c478bd9Sstevel@tonic-gate /* 127*7c478bd9Sstevel@tonic-gate * Use the difference between give localtime and computed 128*7c478bd9Sstevel@tonic-gate * localtime as our correction. 129*7c478bd9Sstevel@tonic-gate */ 130*7c478bd9Sstevel@tonic-gate if (r2secs > r1secs) { 131*7c478bd9Sstevel@tonic-gate gsecs -= r2secs - r1secs; 132*7c478bd9Sstevel@tonic-gate } else { 133*7c478bd9Sstevel@tonic-gate gsecs += r1secs - r2secs; 134*7c478bd9Sstevel@tonic-gate } 135*7c478bd9Sstevel@tonic-gate /* 136*7c478bd9Sstevel@tonic-gate * And try the comparison again... 137*7c478bd9Sstevel@tonic-gate */ 138*7c478bd9Sstevel@tonic-gate (void) memcpy((void *)<ime, (void *)localtime(&gsecs), 139*7c478bd9Sstevel@tonic-gate sizeof (ltime)); 140*7c478bd9Sstevel@tonic-gate r2secs = tm_to_secs(<ime); 141*7c478bd9Sstevel@tonic-gate /* 142*7c478bd9Sstevel@tonic-gate * If the correction fails then we are on a DST line 143*7c478bd9Sstevel@tonic-gate * and the user-given local time never happened. 144*7c478bd9Sstevel@tonic-gate * Do the best we can. 145*7c478bd9Sstevel@tonic-gate */ 146*7c478bd9Sstevel@tonic-gate if (r1secs != r2secs) { 147*7c478bd9Sstevel@tonic-gate gsecs = save_gsecs; 148*7c478bd9Sstevel@tonic-gate } 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate return (gsecs); 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* 155*7c478bd9Sstevel@tonic-gate * .func tm_to_secs - convert to seconds. 156*7c478bd9Sstevel@tonic-gate * .desc Convert a tm time structure (time.h) into seconds since 157*7c478bd9Sstevel@tonic-gate * Jan 1, 1970 00:00:00. The time is assumed to be GMT and 158*7c478bd9Sstevel@tonic-gate * so no daylight savings time correction is applied. That 159*7c478bd9Sstevel@tonic-gate * is left up to the system calls (localtime(), gmtime()). 160*7c478bd9Sstevel@tonic-gate * .call ret = tm_to_secs(tme). 161*7c478bd9Sstevel@tonic-gate * .arg tme - ptr to tm structure. 162*7c478bd9Sstevel@tonic-gate * .ret time_t - number of seconds. 163*7c478bd9Sstevel@tonic-gate */ 164*7c478bd9Sstevel@tonic-gate time_t 165*7c478bd9Sstevel@tonic-gate tm_to_secs(struct tm *tme) 166*7c478bd9Sstevel@tonic-gate { 167*7c478bd9Sstevel@tonic-gate int leap_year = FALSE; 168*7c478bd9Sstevel@tonic-gate int days = 0; 169*7c478bd9Sstevel@tonic-gate time_t num_sec = 0; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate int sec = tme->tm_sec; 172*7c478bd9Sstevel@tonic-gate int min = tme->tm_min; 173*7c478bd9Sstevel@tonic-gate int hour = tme->tm_hour; 174*7c478bd9Sstevel@tonic-gate int day = tme->tm_mday; 175*7c478bd9Sstevel@tonic-gate int month = tme->tm_mon; 176*7c478bd9Sstevel@tonic-gate int year = tme->tm_year + 1900; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate if (days_in_year(year) == 366) 179*7c478bd9Sstevel@tonic-gate leap_year = TRUE; 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate while (year > 1970) { 182*7c478bd9Sstevel@tonic-gate num_sec += days_in_year(--year) * 24 * 60 * 60; 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate while (month > 0) { 185*7c478bd9Sstevel@tonic-gate days = days_month[--month]; 186*7c478bd9Sstevel@tonic-gate if (leap_year && month == 1) { /* 1 is February */ 187*7c478bd9Sstevel@tonic-gate days++; 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate num_sec += days * 24 * 60 * 60; 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate num_sec += --day * 24 * 60 * 60; 192*7c478bd9Sstevel@tonic-gate num_sec += hour * 60 * 60; 193*7c478bd9Sstevel@tonic-gate num_sec += min * 60; 194*7c478bd9Sstevel@tonic-gate num_sec += sec; 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate return (num_sec); 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate /* 201*7c478bd9Sstevel@tonic-gate * .func check_time - check tm structure. 202*7c478bd9Sstevel@tonic-gate * .desc Check the time in a tm structure to see if all of the fields 203*7c478bd9Sstevel@tonic-gate * are within range. 204*7c478bd9Sstevel@tonic-gate * .call err = check_time(tme). 205*7c478bd9Sstevel@tonic-gate * .arg tme - ptr to struct tm (see time.h). 206*7c478bd9Sstevel@tonic-gate * .ret 0 - time is ok. 207*7c478bd9Sstevel@tonic-gate * .ret -1 - time had a problem (description in error_str). 208*7c478bd9Sstevel@tonic-gate */ 209*7c478bd9Sstevel@tonic-gate int 210*7c478bd9Sstevel@tonic-gate check_time(struct tm *tme) 211*7c478bd9Sstevel@tonic-gate { 212*7c478bd9Sstevel@tonic-gate error_str = NULL; 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate if (tme->tm_sec < 0 || tme->tm_sec > 59) { 215*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 216*7c478bd9Sstevel@tonic-gate gettext("seconds out of range (%d)"), tme->tm_sec + 1); 217*7c478bd9Sstevel@tonic-gate error_str = errbuf; 218*7c478bd9Sstevel@tonic-gate } else if (tme->tm_min < 0 || tme->tm_min > 59) { 219*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 220*7c478bd9Sstevel@tonic-gate gettext("minutes out of range (%d)"), tme->tm_min + 1); 221*7c478bd9Sstevel@tonic-gate error_str = errbuf; 222*7c478bd9Sstevel@tonic-gate } else if (tme->tm_hour < 0 || tme->tm_hour > 23) { 223*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 224*7c478bd9Sstevel@tonic-gate gettext("hours out of range (%d)"), tme->tm_hour + 1); 225*7c478bd9Sstevel@tonic-gate error_str = errbuf; 226*7c478bd9Sstevel@tonic-gate } else if (tme->tm_mon < 0 || tme->tm_mon > 11) { 227*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 228*7c478bd9Sstevel@tonic-gate gettext("months out of range (%d)"), tme->tm_mon + 1); 229*7c478bd9Sstevel@tonic-gate error_str = errbuf; 230*7c478bd9Sstevel@tonic-gate } else if (tme->tm_year < 0) { 231*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 232*7c478bd9Sstevel@tonic-gate gettext("years out of range (%d)"), tme->tm_year); 233*7c478bd9Sstevel@tonic-gate error_str = errbuf; 234*7c478bd9Sstevel@tonic-gate } else if (tme->tm_mday < 1 || tme->tm_mday > days_month[tme->tm_mon]) { 235*7c478bd9Sstevel@tonic-gate if (!(days_in_year(tme->tm_year + 1900) == 366 && 236*7c478bd9Sstevel@tonic-gate tme->tm_mon == 1 && 237*7c478bd9Sstevel@tonic-gate tme->tm_mday == 29)) { /* leap year and February */ 238*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 239*7c478bd9Sstevel@tonic-gate gettext("days out of range (%d)"), tme->tm_mday); 240*7c478bd9Sstevel@tonic-gate error_str = errbuf; 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate } else if (tme->tm_wday < 0 || tme->tm_wday > 6) { 243*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 244*7c478bd9Sstevel@tonic-gate gettext("weekday out of range (%d)"), tme->tm_wday); 245*7c478bd9Sstevel@tonic-gate error_str = errbuf; 246*7c478bd9Sstevel@tonic-gate } else if (tme->tm_yday < 0 || tme->tm_yday > 365) { 247*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 248*7c478bd9Sstevel@tonic-gate gettext("day of year out of range (%d)"), tme->tm_yday); 249*7c478bd9Sstevel@tonic-gate error_str = errbuf; 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate if (error_str == NULL) 253*7c478bd9Sstevel@tonic-gate return (0); 254*7c478bd9Sstevel@tonic-gate else 255*7c478bd9Sstevel@tonic-gate return (-1); 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate /* 260*7c478bd9Sstevel@tonic-gate * .func parse_time. 261*7c478bd9Sstevel@tonic-gate * .desc Parse a user time from the command line. The user time is assumed 262*7c478bd9Sstevel@tonic-gate * to be local time. 263*7c478bd9Sstevel@tonic-gate * Supported formats currently are: 264*7c478bd9Sstevel@tonic-gate * 1. +xt - where x is a number and t is a type. 265*7c478bd9Sstevel@tonic-gate * types are - 's' second, 'm' minute, 'h' hour, and 'd' day. 266*7c478bd9Sstevel@tonic-gate * 2. yymmdd - yyyymmdd. 267*7c478bd9Sstevel@tonic-gate * yymmddhh - yyyymmddhh. 268*7c478bd9Sstevel@tonic-gate * yymmddhhmm - yyyymmddhhmm. 269*7c478bd9Sstevel@tonic-gate * yymmddhhmmss - yyyymmddhhmmss. 270*7c478bd9Sstevel@tonic-gate * .call err = parse_time(str, opt). 271*7c478bd9Sstevel@tonic-gate * .arg str - ptr to user input string. 272*7c478bd9Sstevel@tonic-gate * .arg opt - time option being processed. 273*7c478bd9Sstevel@tonic-gate * .ret 0 - succesful. 274*7c478bd9Sstevel@tonic-gate * .ret -1 - failure (error message in error_str). 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate int 277*7c478bd9Sstevel@tonic-gate parse_time(char *str, int opt) 278*7c478bd9Sstevel@tonic-gate { 279*7c478bd9Sstevel@tonic-gate int ret, len, factor; 280*7c478bd9Sstevel@tonic-gate char *strxx; 281*7c478bd9Sstevel@tonic-gate long lnum; 282*7c478bd9Sstevel@tonic-gate struct tm thentime; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate len = strlen(str); 285*7c478bd9Sstevel@tonic-gate /* 286*7c478bd9Sstevel@tonic-gate * If the strlen < 6 then in the "-b +2d" type of format. 287*7c478bd9Sstevel@tonic-gate */ 288*7c478bd9Sstevel@tonic-gate if (len < 6) { 289*7c478bd9Sstevel@tonic-gate if (*str++ != '+') { 290*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, gettext("%s needs '+' (%s)"), 291*7c478bd9Sstevel@tonic-gate do_invalid(), str); 292*7c478bd9Sstevel@tonic-gate error_str = errbuf; 293*7c478bd9Sstevel@tonic-gate return (-1); 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate if (opt != 'b') { 296*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 297*7c478bd9Sstevel@tonic-gate gettext("%s only allowed with 'b' option (%s)"), 298*7c478bd9Sstevel@tonic-gate do_invalid(), str); 299*7c478bd9Sstevel@tonic-gate error_str = errbuf; 300*7c478bd9Sstevel@tonic-gate return (-1); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate if (m_after == 0) { 303*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 304*7c478bd9Sstevel@tonic-gate gettext("must have -a to use -b +nx form (%s)"), 305*7c478bd9Sstevel@tonic-gate str); 306*7c478bd9Sstevel@tonic-gate error_str = errbuf; 307*7c478bd9Sstevel@tonic-gate return (-1); 308*7c478bd9Sstevel@tonic-gate } 309*7c478bd9Sstevel@tonic-gate /* 310*7c478bd9Sstevel@tonic-gate * Find out what type of offset it is - 's' 'm' 'h' or 'd'. 311*7c478bd9Sstevel@tonic-gate * Make sure that the offset is all numbers. 312*7c478bd9Sstevel@tonic-gate */ 313*7c478bd9Sstevel@tonic-gate if ((strxx = strpbrk(str, "dhms")) == NULL) { 314*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 315*7c478bd9Sstevel@tonic-gate gettext("%s needs 'd', 'h', 'm', or 's' (%s)"), 316*7c478bd9Sstevel@tonic-gate do_invalid(), str); 317*7c478bd9Sstevel@tonic-gate error_str = errbuf; 318*7c478bd9Sstevel@tonic-gate return (-1); 319*7c478bd9Sstevel@tonic-gate } else { 320*7c478bd9Sstevel@tonic-gate ret = *strxx; 321*7c478bd9Sstevel@tonic-gate *strxx = '\0'; 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate if (strlen(str) != strspn(str, "0123456789")) { 324*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 325*7c478bd9Sstevel@tonic-gate gettext("%s non-numeric offset (%s)"), 326*7c478bd9Sstevel@tonic-gate do_invalid(), str); 327*7c478bd9Sstevel@tonic-gate error_str = errbuf; 328*7c478bd9Sstevel@tonic-gate return (-1); 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate factor = 1; /* seconds is default */ 331*7c478bd9Sstevel@tonic-gate if (ret == 'd') /* days */ 332*7c478bd9Sstevel@tonic-gate factor = 24 * 60 * 60; 333*7c478bd9Sstevel@tonic-gate else if (ret == 'h') /* hours */ 334*7c478bd9Sstevel@tonic-gate factor = 60 * 60; 335*7c478bd9Sstevel@tonic-gate else if (ret == 'm') /* minutes */ 336*7c478bd9Sstevel@tonic-gate factor = 60; 337*7c478bd9Sstevel@tonic-gate lnum = atol(str); 338*7c478bd9Sstevel@tonic-gate m_before = m_after + (lnum * factor); 339*7c478bd9Sstevel@tonic-gate return (0); 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate /* 342*7c478bd9Sstevel@tonic-gate * Must be a specific date/time format. 343*7c478bd9Sstevel@tonic-gate */ 344*7c478bd9Sstevel@tonic-gate if (derive_date(str, &thentime)) 345*7c478bd9Sstevel@tonic-gate return (-1); 346*7c478bd9Sstevel@tonic-gate /* 347*7c478bd9Sstevel@tonic-gate * For 'd' option clear out the hh:mm:ss to get to the start of the day. 348*7c478bd9Sstevel@tonic-gate * Then add one day's worth of seconds to get the 'b' time. 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate if (opt == 'd') { 351*7c478bd9Sstevel@tonic-gate thentime.tm_sec = 0; 352*7c478bd9Sstevel@tonic-gate thentime.tm_min = 0; 353*7c478bd9Sstevel@tonic-gate thentime.tm_hour = 0; 354*7c478bd9Sstevel@tonic-gate m_after = local_to_gm(&thentime); 355*7c478bd9Sstevel@tonic-gate m_before = m_after + (24 * 60 * 60); 356*7c478bd9Sstevel@tonic-gate } else if (opt == 'a') { 357*7c478bd9Sstevel@tonic-gate m_after = local_to_gm(&thentime); 358*7c478bd9Sstevel@tonic-gate } else if (opt == 'b') { 359*7c478bd9Sstevel@tonic-gate m_before = local_to_gm(&thentime); 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate return (0); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* 366*7c478bd9Sstevel@tonic-gate * .func derive_date. 367*7c478bd9Sstevel@tonic-gate * .desc Derive a date/time structure (tm) from a string. 368*7c478bd9Sstevel@tonic-gate * String is in one of these formats: 369*7c478bd9Sstevel@tonic-gate * [yy]yymmddhhmmss 370*7c478bd9Sstevel@tonic-gate * [yy]yymmddhhmm 371*7c478bd9Sstevel@tonic-gate * [yy]yymmddhh 372*7c478bd9Sstevel@tonic-gate * [yy]yymmdd 373*7c478bd9Sstevel@tonic-gate * .call ret = derive_date(str, tme). 374*7c478bd9Sstevel@tonic-gate * .arg str - ptr to input string. 375*7c478bd9Sstevel@tonic-gate * .arg tme - ptr to tm structure (time.h). 376*7c478bd9Sstevel@tonic-gate * .ret 0 - no errors in string. 377*7c478bd9Sstevel@tonic-gate * .ret -1 - errors in string (description in error_str). 378*7c478bd9Sstevel@tonic-gate */ 379*7c478bd9Sstevel@tonic-gate int 380*7c478bd9Sstevel@tonic-gate derive_date(char *str, struct tm *tme) 381*7c478bd9Sstevel@tonic-gate { 382*7c478bd9Sstevel@tonic-gate char *strs; 383*7c478bd9Sstevel@tonic-gate char *digits = "0123456789"; 384*7c478bd9Sstevel@tonic-gate size_t len; 385*7c478bd9Sstevel@tonic-gate struct tm nowtime; 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate len = strlen(str); 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate if (len != strspn(str, digits)) { 390*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, gettext("%s not all digits (%s)"), 391*7c478bd9Sstevel@tonic-gate do_invalid(), str); 392*7c478bd9Sstevel@tonic-gate error_str = errbuf; 393*7c478bd9Sstevel@tonic-gate return (-1); 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate if (len % 2) { 396*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, gettext("%s odd number of digits (%s)"), 397*7c478bd9Sstevel@tonic-gate do_invalid(), str); 398*7c478bd9Sstevel@tonic-gate error_str = errbuf; 399*7c478bd9Sstevel@tonic-gate return (-1); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate /* 402*7c478bd9Sstevel@tonic-gate * May need larger string storage to add '19' or '20'. 403*7c478bd9Sstevel@tonic-gate */ 404*7c478bd9Sstevel@tonic-gate strs = (char *)a_calloc(1, len + 4); 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate /* 407*7c478bd9Sstevel@tonic-gate * Get current time to see what century it is. 408*7c478bd9Sstevel@tonic-gate */ 409*7c478bd9Sstevel@tonic-gate (void) memcpy((char *)&nowtime, (char *)gmtime(&time_now), 410*7c478bd9Sstevel@tonic-gate sizeof (nowtime)); 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * If the year does not begin with '19' or '20', then report 413*7c478bd9Sstevel@tonic-gate * an error and abort. 414*7c478bd9Sstevel@tonic-gate */ 415*7c478bd9Sstevel@tonic-gate if ((str[0] != '1' || str[1] != '9') && /* 19XX */ 416*7c478bd9Sstevel@tonic-gate (str[0] != '2' || str[1] != '0')) { /* 20XX */ 417*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, gettext("invalid year (%c%c%c%c)"), 418*7c478bd9Sstevel@tonic-gate str[0], str[1], str[2], str[3]); 419*7c478bd9Sstevel@tonic-gate error_str = errbuf; 420*7c478bd9Sstevel@tonic-gate free(strs); 421*7c478bd9Sstevel@tonic-gate return (-1); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate len = strlen(str); /* may have changed */ 425*7c478bd9Sstevel@tonic-gate if (len < 8 || len > 14) { 426*7c478bd9Sstevel@tonic-gate (void) sprintf(errbuf, 427*7c478bd9Sstevel@tonic-gate gettext("invalid date/time length (%s)"), str); 428*7c478bd9Sstevel@tonic-gate error_str = errbuf; 429*7c478bd9Sstevel@tonic-gate free(strs); 430*7c478bd9Sstevel@tonic-gate return (-1); 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate /* unspecified values go to 0 */ 433*7c478bd9Sstevel@tonic-gate (void) memset((void *) tme, 0, (size_t)sizeof (*tme)); 434*7c478bd9Sstevel@tonic-gate (void) strncpy(strs, str, 4); 435*7c478bd9Sstevel@tonic-gate strs[4] = '\0'; 436*7c478bd9Sstevel@tonic-gate tme->tm_year = atoi(strs) - 1900; /* get the year */ 437*7c478bd9Sstevel@tonic-gate (void) strncpy(strs, str + 4, 2); 438*7c478bd9Sstevel@tonic-gate strs[2] = '\0'; 439*7c478bd9Sstevel@tonic-gate tme->tm_mon = atoi(strs) - 1; /* get months */ 440*7c478bd9Sstevel@tonic-gate (void) strncpy(strs, str + 6, 2); 441*7c478bd9Sstevel@tonic-gate strs[2] = '\0'; 442*7c478bd9Sstevel@tonic-gate tme->tm_mday = atoi(strs); /* get days */ 443*7c478bd9Sstevel@tonic-gate if (len >= 10) { /* yyyymmddhh */ 444*7c478bd9Sstevel@tonic-gate (void) strncpy(strs, str + 8, 2); 445*7c478bd9Sstevel@tonic-gate strs[2] = '\0'; 446*7c478bd9Sstevel@tonic-gate tme->tm_hour = atoi(strs); /* get hours */ 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate if (len >= 12) { /* yyyymmddhhmm */ 449*7c478bd9Sstevel@tonic-gate (void) strncpy(strs, str + 10, 2); 450*7c478bd9Sstevel@tonic-gate strs[2] = '\0'; 451*7c478bd9Sstevel@tonic-gate tme->tm_min = atoi(strs); /* get minutes */ 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate if (len >= 14) { /* yyyymmddhhmmss */ 454*7c478bd9Sstevel@tonic-gate (void) strncpy(strs, str + 12, 2); 455*7c478bd9Sstevel@tonic-gate strs[2] = '\0'; 456*7c478bd9Sstevel@tonic-gate tme->tm_sec = atoi(strs); /* get seconds */ 457*7c478bd9Sstevel@tonic-gate } 458*7c478bd9Sstevel@tonic-gate free(strs); 459*7c478bd9Sstevel@tonic-gate return (check_time(tme)); /* lastly check the ranges */ 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate /* 464*7c478bd9Sstevel@tonic-gate * .func derive_str - derive string. 465*7c478bd9Sstevel@tonic-gate * .desc Derive a string representation of a time for a filename. 466*7c478bd9Sstevel@tonic-gate * The output is in the 14 character format yyyymmddhhmmss. 467*7c478bd9Sstevel@tonic-gate * .call derive_str(clock, buf). 468*7c478bd9Sstevel@tonic-gate * .arg clock - seconds since epoch. 469*7c478bd9Sstevel@tonic-gate * .arg buf - place to put resultant string. 470*7c478bd9Sstevel@tonic-gate * .ret void. 471*7c478bd9Sstevel@tonic-gate */ 472*7c478bd9Sstevel@tonic-gate void 473*7c478bd9Sstevel@tonic-gate derive_str(time_t clock, char *buf) 474*7c478bd9Sstevel@tonic-gate { 475*7c478bd9Sstevel@tonic-gate struct tm gtime; 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate (void) memcpy((void *) & gtime, (void *)gmtime(&clock), sizeof (gtime)); 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%4d", gtime.tm_year + 1900); 480*7c478bd9Sstevel@tonic-gate (void) sprintf(buf + 4, "%.2d", gtime.tm_mon + 1); 481*7c478bd9Sstevel@tonic-gate (void) sprintf(buf + 6, "%.2d", gtime.tm_mday); 482*7c478bd9Sstevel@tonic-gate (void) sprintf(buf + 8, "%.2d", gtime.tm_hour); 483*7c478bd9Sstevel@tonic-gate (void) sprintf(buf + 10, "%.2d", gtime.tm_min); 484*7c478bd9Sstevel@tonic-gate (void) sprintf(buf + 12, "%.2d", gtime.tm_sec); 485*7c478bd9Sstevel@tonic-gate buf[14] = '\0'; 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate int 490*7c478bd9Sstevel@tonic-gate days_in_year(int year) 491*7c478bd9Sstevel@tonic-gate { 492*7c478bd9Sstevel@tonic-gate if (isleap(year)) 493*7c478bd9Sstevel@tonic-gate return (366); 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate return (365); 496*7c478bd9Sstevel@tonic-gate } 497