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 int daysend[] = {0, 60, 23}; /* the sec, min, hr of the day's end */ 68 69 struct tm *localtime(); 70 long tmsecs(); 71 72 /* 73 * split interval of length etime, starting at start into prime/nonprime 74 * values, return as result 75 * input values in seconds 76 */ 77 int 78 pnpsplit(start, etime, result) 79 long start, result[2]; 80 ulong_t etime; 81 { 82 struct tm cur, end; 83 time_t tcur, tend; 84 long tmp; 85 int sameday; 86 register struct hours *hp; 87 char *memcpy(); 88 89 /* once holidays file is read, this is zero */ 90 if(thisyear && (checkhol() == 0)) { 91 return(0); 92 } 93 tcur = start; 94 tend = start + etime; 95 memcpy(&end, localtime(&tend), sizeof(end)); 96 result[PRIME] = 0; 97 result[NONPRIME] = 0; 98 99 while ( tcur < tend ) { /* one iteration per day or part thereof */ 100 memcpy(&cur, localtime(&tcur), sizeof(cur)); 101 sameday = cur.tm_yday == end.tm_yday; 102 if (ssh(&cur)) { /* ssh:only NONPRIME */ 103 if (sameday) { 104 result[NONPRIME] += tend-tcur; 105 106 break; 107 } else { 108 tmp = tmsecs(&cur, daysend); 109 result[NONPRIME] += tmp; 110 tcur += tmp; 111 } 112 } else { /* working day, PRIME or NONPRIME */ 113 for (hp = h; tmless(hp, &cur); hp++); 114 for (; hp->h_sec >= 0; hp++) { 115 if (sameday && tmless(&end, hp)) { 116 /* WHCC mod, change from = to += 3/6/86 Paul */ 117 result[hp->h_type] += tend-tcur; 118 tcur = tend; 119 break; /* all done */ 120 } else { /* time to next PRIME /NONPRIME change */ 121 tmp = tmsecs(&cur, hp); 122 result[hp->h_type] += tmp; 123 tcur += tmp; 124 cur.tm_sec = hp->h_sec; 125 cur.tm_min = hp->h_min; 126 cur.tm_hour = hp->h_hour; 127 } 128 } 129 } 130 } 131 return(1); 132 } 133 134 /* 135 * Starting day after Christmas, complain if holidays not yet updated. 136 * This code is only executed once per program invocation. 137 */ 138 int 139 checkhol() 140 { 141 register struct tm *tp; 142 time_t t; 143 144 if(inithol() == 0) { 145 fprintf(stderr, "pnpsplit: holidays table setup failed\n"); 146 thisyear = 0; 147 holidays[0] = -1; 148 return(0); 149 } 150 time(&t); 151 tp = localtime(&t); 152 tp->tm_year += 1900; 153 if ((tp->tm_year == thisyear && tp->tm_yday > 359) 154 || tp->tm_year > thisyear) 155 fprintf(stderr, 156 "***UPDATE %s WITH NEW HOLIDAYS***\n", HOLFILE); 157 thisyear = 0; /* checkhol() will not be called again */ 158 return(1); 159 } 160 161 /* 162 * ssh returns 1 if Sat, Sun, or Holiday 163 */ 164 int 165 ssh(ltp) 166 register struct tm *ltp; 167 { 168 int i; 169 170 if (ltp->tm_wday == 0 || ltp->tm_wday == 6) 171 return(1); 172 for (i = 0; holidays[i] >= 0; i++) 173 if (ltp->tm_yday == holidays[i]) 174 return(1); 175 return(0); 176 } 177 178 /* 179 * inithol - read from an ascii file and initialize the "thisyear" 180 * variable, the times that prime and non-prime start, and the 181 * holidays array. 182 */ 183 int 184 inithol() 185 { 186 FILE *fopen(), *holptr; 187 char *fgets(), holbuf[128]; 188 register int line = 0, 189 holindx = 0, 190 errflag = 0; 191 int pstart, npstart; 192 int doy; /* day of the year */ 193 int month, day; 194 char *c; 195 196 if((holptr=fopen(HOLFILE, "r")) == NULL) { 197 perror(HOLFILE); 198 fclose(holptr); 199 return(0); 200 } 201 while(fgets(holbuf, sizeof(holbuf), holptr) != NULL) { 202 /* skip over blank lines and comments */ 203 if (holbuf[0] == '*') 204 continue; 205 206 for (c = holbuf; isspace(*c); c++) 207 /* is a space */; 208 209 if (*c == '\0') 210 continue; 211 212 else if(++line == 1) { /* format: year p-start np-start */ 213 if(sscanf(holbuf, "%4d %4d %4d", 214 &thisyear, &pstart, &npstart) != 3) { 215 fprintf(stderr, 216 "%s: bad {yr ptime nptime} conversion\n", 217 HOLFILE); 218 errflag++; 219 break; 220 } 221 222 /* validate year */ 223 if(thisyear < 1970 || thisyear > 2037) { 224 fprintf(stderr, "pnpsplit: invalid year: %d\n", 225 thisyear); 226 errflag++; 227 break; 228 } 229 230 /* validate prime/nonprime hours */ 231 if((! okay(pstart)) || (! okay(npstart))) { 232 fprintf(stderr, 233 "pnpsplit: invalid p/np hours\n"); 234 errflag++; 235 break; 236 } 237 238 /* Set up start of prime time; 2400 == 0000 */ 239 h[0].h_sec = 0; 240 h[0].h_min = pstart%100; 241 h[0].h_hour = (pstart/100==24) ? 0 : pstart/100; 242 h[0].h_type = NONPRIME; 243 244 /* Set up start of non-prime time; 2400 == 2360 */ 245 if ((npstart/100) == 24) { 246 h[1].h_sec = 0; 247 h[1].h_min = 60; 248 h[1].h_hour = 23; 249 } else { 250 h[1].h_sec = 0; 251 h[1].h_min = npstart % 100; 252 h[1].h_hour = npstart / 100; 253 } 254 255 h[1].h_sec = 0; 256 h[1].h_min = npstart%100; 257 h[1].h_hour = (npstart/100==24) ? 0 : npstart/100; 258 h[1].h_type = PRIME ; 259 260 /* This is the end of the day */ 261 h[2].h_sec = 0; 262 h[2].h_min = 60; 263 h[2].h_hour = 23; 264 h[2].h_type = NONPRIME; 265 266 /* The end of the array */ 267 h[3].h_sec = -1; 268 269 continue; 270 } 271 else if(holindx >= NHOLIDAYS) { 272 fprintf(stderr, "pnpsplit: too many holidays, "); 273 fprintf(stderr, "recompile with larger NHOLIDAYS\n"); 274 errflag++; 275 break; 276 } 277 278 /* Fill up holidays array from holidays file */ 279 sscanf(holbuf, "%d/%d %*s %*s %*[^\n]\n", &month, &day); 280 if (month < 0 || month > 12) { 281 fprintf(stderr, "pnpsplit: invalid month %d\n", month); 282 errflag++; 283 break; 284 } 285 if (day < 0 || day > 31) { 286 fprintf(stderr, "pnpsplit: invalid day %d\n", day); 287 errflag++; 288 break; 289 } 290 doy = day_of_year(thisyear, month, day); 291 holidays[holindx++] = (doy - 1); 292 } 293 fclose(holptr); 294 if(!errflag && holindx < NHOLIDAYS) { 295 holidays[holindx] = -1; 296 return(1); 297 } 298 else 299 return(0); 300 } 301 302 /* 303 * tmsecs returns number of seconds from t1 to t2, 304 * times expressed in localtime format. 305 * assumed that t1 <= t2, and are in same day. 306 */ 307 308 long 309 tmsecs(t1, t2) 310 register struct tm *t1, *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(t1, t2) 324 register struct tm *t1, *t2; 325 { 326 if (t1->tm_hour != t2->tm_hour) 327 return(t1->tm_hour < t2->tm_hour); 328 if (t1->tm_min != t2->tm_min) 329 return(t1->tm_min < t2->tm_min); 330 return(t1->tm_sec < t2->tm_sec); 331 } 332 333 /* set day of year from month and day */ 334 335 int 336 day_of_year(year, month, day) 337 { 338 int i, leap; 339 340 leap = year%4 == 0 && year%100 || year%400 == 0; 341 for (i = 1; i < month; i++) 342 day += day_tab[leap][i]; 343 return(day); 344 } 345