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