1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 /*
31 * pnpsplit splits interval into prime & nonprime portions
32 * ONLY ROUTINE THAT KNOWS ABOUT HOLIDAYS AND DEFN OF PRIME/NONPRIME
33 */
34
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include "acctdef.h"
39 #include <time.h>
40 #include <ctype.h>
41
42 /*
43 * validate that hours and minutes of prime/non-prime read in
44 * from holidays file fall within proper boundaries.
45 * Time is expected in the form and range of 0000-2400.
46 */
47
48 static int thisyear = 1970; /* this is changed by holidays file */
49 static int holidays[NHOLIDAYS]; /* holidays file day-of-year table */
50
51
52 static int day_tab[2][13] = {
53 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
54 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
55 };
56
57 /*
58 * prime(0) and nonprime(1) times during a day
59 * for BTL, prime time is 9AM to 5PM
60 */
61 static struct hours {
62 int h_sec; /* normally always zero */
63 int h_min; /* initialized from holidays file (time%100) */
64 int h_hour; /* initialized from holidays file (time/100) */
65 long h_type; /* prime/nonprime of previous period */
66 } h[4];
67
68 /* the sec, min, hr of the day's end */
69 struct tm daysend = {
70 .tm_sec = 0,
71 .tm_min = 60,
72 .tm_hour = 23
73 };
74
75 long tmsecs(struct tm *, struct tm *);
76
77 /*
78 * split interval of length etime, starting at start into prime/nonprime
79 * values, return as result
80 * input values in seconds
81 */
82 int
pnpsplit(long start,ulong_t etime,long result[2])83 pnpsplit(long start, ulong_t etime, long result[2])
84 {
85 struct tm cur, end, hours;
86 time_t tcur, tend;
87 long tmp;
88 int sameday;
89 struct hours *hp;
90
91 /* once holidays file is read, this is zero */
92 if(thisyear && (checkhol() == 0)) {
93 return(0);
94 }
95 tcur = start;
96 tend = start + etime;
97 memcpy(&end, localtime(&tend), sizeof(end));
98 result[PRIME] = 0;
99 result[NONPRIME] = 0;
100
101 while ( tcur < tend ) { /* one iteration per day or part thereof */
102 memcpy(&cur, localtime(&tcur), sizeof(cur));
103 sameday = cur.tm_yday == end.tm_yday;
104 if (ssh(&cur)) { /* ssh:only NONPRIME */
105 if (sameday) {
106 result[NONPRIME] += tend-tcur;
107
108 break;
109 } else {
110 tmp = tmsecs(&cur, &daysend);
111 result[NONPRIME] += tmp;
112 tcur += tmp;
113 }
114 } else { /* working day, PRIME or NONPRIME */
115 for (hp = h; tmless(hp, &cur); hp++);
116 for (; hp->h_sec >= 0; hp++) {
117 if (sameday && tmless(&end, hp)) {
118 /* WHCC mod, change from = to += 3/6/86 Paul */
119 result[hp->h_type] += tend-tcur;
120 tcur = tend;
121 break; /* all done */
122 } else { /* time to next PRIME /NONPRIME change */
123 hours.tm_sec = hp->h_sec;
124 hours.tm_min = hp->h_min;
125 hours.tm_hour = hp->h_hour;
126 tmp = tmsecs(&cur, &hours);
127 result[hp->h_type] += tmp;
128 tcur += tmp;
129 cur.tm_sec = hp->h_sec;
130 cur.tm_min = hp->h_min;
131 cur.tm_hour = hp->h_hour;
132 }
133 }
134 }
135 }
136 return(1);
137 }
138
139 /*
140 * Starting day after Christmas, complain if holidays not yet updated.
141 * This code is only executed once per program invocation.
142 */
143 int
checkhol(void)144 checkhol(void)
145 {
146 struct tm *tp;
147 time_t t;
148
149 if(inithol() == 0) {
150 fprintf(stderr, "pnpsplit: holidays table setup failed\n");
151 thisyear = 0;
152 holidays[0] = -1;
153 return(0);
154 }
155 time(&t);
156 tp = localtime(&t);
157 tp->tm_year += 1900;
158 if ((tp->tm_year == thisyear && tp->tm_yday > 359)
159 || tp->tm_year > thisyear)
160 fprintf(stderr,
161 "***UPDATE %s WITH NEW HOLIDAYS***\n", HOLFILE);
162 thisyear = 0; /* checkhol() will not be called again */
163 return(1);
164 }
165
166 /*
167 * ssh returns 1 if Sat, Sun, or Holiday
168 */
169 int
ssh(struct tm * ltp)170 ssh(struct tm *ltp)
171 {
172 int i;
173
174 if (ltp->tm_wday == 0 || ltp->tm_wday == 6)
175 return(1);
176 for (i = 0; holidays[i] >= 0; i++)
177 if (ltp->tm_yday == holidays[i])
178 return(1);
179 return(0);
180 }
181
182 /*
183 * inithol - read from an ascii file and initialize the "thisyear"
184 * variable, the times that prime and non-prime start, and the
185 * holidays array.
186 */
187 int
inithol(void)188 inithol(void)
189 {
190 FILE *holptr;
191 char holbuf[128];
192 int line = 0,
193 holindx = 0,
194 errflag = 0;
195 int pstart, npstart;
196 int doy; /* day of the year */
197 int month, day;
198 char *c;
199
200 if((holptr=fopen(HOLFILE, "r")) == NULL) {
201 perror(HOLFILE);
202 fclose(holptr);
203 return(0);
204 }
205 while(fgets(holbuf, sizeof(holbuf), holptr) != NULL) {
206 /* skip over blank lines and comments */
207 if (holbuf[0] == '*')
208 continue;
209
210 for (c = holbuf; isspace(*c); c++)
211 /* is a space */;
212
213 if (*c == '\0')
214 continue;
215
216 else if(++line == 1) { /* format: year p-start np-start */
217 if(sscanf(holbuf, "%4d %4d %4d",
218 &thisyear, &pstart, &npstart) != 3) {
219 fprintf(stderr,
220 "%s: bad {yr ptime nptime} conversion\n",
221 HOLFILE);
222 errflag++;
223 break;
224 }
225
226 /* validate year */
227 if(thisyear < 1970 || thisyear > 2037) {
228 fprintf(stderr, "pnpsplit: invalid year: %d\n",
229 thisyear);
230 errflag++;
231 break;
232 }
233
234 /* validate prime/nonprime hours */
235 if((! okay(pstart)) || (! okay(npstart))) {
236 fprintf(stderr,
237 "pnpsplit: invalid p/np hours\n");
238 errflag++;
239 break;
240 }
241
242 /* Set up start of prime time; 2400 == 0000 */
243 h[0].h_sec = 0;
244 h[0].h_min = pstart%100;
245 h[0].h_hour = (pstart/100==24) ? 0 : pstart/100;
246 h[0].h_type = NONPRIME;
247
248 /* Set up start of non-prime time; 2400 == 2360 */
249 if ((npstart/100) == 24) {
250 h[1].h_sec = 0;
251 h[1].h_min = 60;
252 h[1].h_hour = 23;
253 } else {
254 h[1].h_sec = 0;
255 h[1].h_min = npstart % 100;
256 h[1].h_hour = npstart / 100;
257 }
258
259 h[1].h_type = PRIME;
260
261 /* This is the end of the day */
262 h[2].h_sec = 0;
263 h[2].h_min = 60;
264 h[2].h_hour = 23;
265 h[2].h_type = NONPRIME;
266
267 /* The end of the array */
268 h[3].h_sec = -1;
269
270 continue;
271 }
272 else if(holindx >= NHOLIDAYS) {
273 fprintf(stderr, "pnpsplit: too many holidays, ");
274 fprintf(stderr, "recompile with larger NHOLIDAYS\n");
275 errflag++;
276 break;
277 }
278
279 /* Fill up holidays array from holidays file */
280 sscanf(holbuf, "%d/%d %*s %*s %*[^\n]\n", &month, &day);
281 if (month < 0 || month > 12) {
282 fprintf(stderr, "pnpsplit: invalid month %d\n", month);
283 errflag++;
284 break;
285 }
286 if (day < 0 || day > 31) {
287 fprintf(stderr, "pnpsplit: invalid day %d\n", day);
288 errflag++;
289 break;
290 }
291 doy = day_of_year(thisyear, month, day);
292 holidays[holindx++] = (doy - 1);
293 }
294 fclose(holptr);
295 if(!errflag && holindx < NHOLIDAYS) {
296 holidays[holindx] = -1;
297 return(1);
298 }
299 else
300 return(0);
301 }
302
303 /*
304 * tmsecs returns number of seconds from t1 to t2,
305 * times expressed in localtime format.
306 * assumed that t1 <= t2, and are in same day.
307 */
308
309 long
tmsecs(struct tm * t1,struct tm * t2)310 tmsecs(struct tm *t1, struct tm *t2)
311 {
312 return((t2->tm_sec - t1->tm_sec) +
313 60*(t2->tm_min - t1->tm_min) +
314 3600L*(t2->tm_hour - t1->tm_hour));
315 }
316
317 /*
318 * return 1 if t1 earlier than t2 (times in localtime format)
319 * assumed that t1 and t2 are in same day
320 */
321
322 int
tmless(struct tm * t1,struct tm * t2)323 tmless(struct tm *t1, struct tm *t2)
324 {
325 if (t1->tm_hour != t2->tm_hour)
326 return(t1->tm_hour < t2->tm_hour);
327 if (t1->tm_min != t2->tm_min)
328 return(t1->tm_min < t2->tm_min);
329 return(t1->tm_sec < t2->tm_sec);
330 }
331
332 /* set day of year from month and day */
333
334 int
day_of_year(int year,int month,int day)335 day_of_year(int year, int month, int day)
336 {
337 int i, leap;
338
339 leap = year%4 == 0 && year%100 || year%400 == 0;
340 for (i = 1; i < month; i++)
341 day += day_tab[leap][i];
342 return(day);
343 }
344