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 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 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 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 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 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 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 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