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_type = PRIME; 256 257 /* This is the end of the day */ 258 h[2].h_sec = 0; 259 h[2].h_min = 60; 260 h[2].h_hour = 23; 261 h[2].h_type = NONPRIME; 262 263 /* The end of the array */ 264 h[3].h_sec = -1; 265 266 continue; 267 } 268 else if(holindx >= NHOLIDAYS) { 269 fprintf(stderr, "pnpsplit: too many holidays, "); 270 fprintf(stderr, "recompile with larger NHOLIDAYS\n"); 271 errflag++; 272 break; 273 } 274 275 /* Fill up holidays array from holidays file */ 276 sscanf(holbuf, "%d/%d %*s %*s %*[^\n]\n", &month, &day); 277 if (month < 0 || month > 12) { 278 fprintf(stderr, "pnpsplit: invalid month %d\n", month); 279 errflag++; 280 break; 281 } 282 if (day < 0 || day > 31) { 283 fprintf(stderr, "pnpsplit: invalid day %d\n", day); 284 errflag++; 285 break; 286 } 287 doy = day_of_year(thisyear, month, day); 288 holidays[holindx++] = (doy - 1); 289 } 290 fclose(holptr); 291 if(!errflag && holindx < NHOLIDAYS) { 292 holidays[holindx] = -1; 293 return(1); 294 } 295 else 296 return(0); 297 } 298 299 /* 300 * tmsecs returns number of seconds from t1 to t2, 301 * times expressed in localtime format. 302 * assumed that t1 <= t2, and are in same day. 303 */ 304 305 long 306 tmsecs(t1, t2) 307 register struct tm *t1, *t2; 308 { 309 return((t2->tm_sec - t1->tm_sec) + 310 60*(t2->tm_min - t1->tm_min) + 311 3600L*(t2->tm_hour - t1->tm_hour)); 312 } 313 314 /* 315 * return 1 if t1 earlier than t2 (times in localtime format) 316 * assumed that t1 and t2 are in same day 317 */ 318 319 int 320 tmless(t1, t2) 321 register struct tm *t1, *t2; 322 { 323 if (t1->tm_hour != t2->tm_hour) 324 return(t1->tm_hour < t2->tm_hour); 325 if (t1->tm_min != t2->tm_min) 326 return(t1->tm_min < t2->tm_min); 327 return(t1->tm_sec < t2->tm_sec); 328 } 329 330 /* set day of year from month and day */ 331 332 int 333 day_of_year(year, month, day) 334 { 335 int i, leap; 336 337 leap = year%4 == 0 && year%100 || year%400 == 0; 338 for (i = 1; i < month; i++) 339 day += day_tab[leap][i]; 340 return(day); 341 } 342