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