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 *
do_invalid(void)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
local_to_gm(struct tm * tme)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
tm_to_secs(struct tm * tme)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
check_time(struct tm * tme)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
parse_time(char * str,int opt)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
derive_date(char * str,struct tm * tme)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
derive_str(time_t clock,char * buf)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
days_in_year(int year)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