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