OpenDNSSEC-signer 1.3.0
|
00001 /* 00002 * $Id: duration.c 5320 2011-07-12 10:42:26Z jakob $ 00003 * 00004 * Copyright (c) 2009 NLNet Labs. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00034 #include "shared/allocator.h" 00035 #include "shared/duration.h" 00036 #include "shared/log.h" 00037 00038 #include <stdio.h> 00039 #include <stdlib.h> 00040 #include <string.h> 00041 #include <time.h> 00042 00043 static const char* duration_str = "duration"; 00044 00045 00050 duration_type* 00051 duration_create(void) 00052 { 00053 duration_type* duration; 00054 allocator_type* allocator = allocator_create(malloc, free); 00055 if (!allocator) { 00056 ods_log_error("[%s] cannot create: no allocator available", 00057 duration_str); 00058 return NULL; 00059 } 00060 00061 duration = (duration_type*) allocator_alloc(allocator, 00062 sizeof(duration_type)); 00063 if (!duration) { 00064 ods_log_error("[%s] cannot create: allocator failed", duration_str); 00065 allocator_cleanup(allocator); 00066 return NULL; 00067 } 00068 duration->allocator = allocator; 00069 duration->years = 0; 00070 duration->months = 0; 00071 duration->weeks = 0; 00072 duration->days = 0; 00073 duration->hours = 0; 00074 duration->minutes = 0; 00075 duration->seconds = 0; 00076 return duration; 00077 } 00078 00079 00084 int 00085 duration_compare(duration_type* d1, duration_type* d2) 00086 { 00087 if (!d1 && !d2) { 00088 return 0; 00089 } 00090 if (!d1 || !d2) { 00091 return d1?-1:1; 00092 } 00093 00094 if (d1->years != d2->years) { 00095 return d1->years - d2->years; 00096 } 00097 if (d1->months != d2->months) { 00098 return d1->months - d2->months; 00099 } 00100 if (d1->weeks != d2->weeks) { 00101 return d1->weeks - d2->weeks; 00102 } 00103 if (d1->days != d2->days) { 00104 return d1->days - d2->days; 00105 } 00106 if (d1->hours != d2->hours) { 00107 return d1->hours - d2->hours; 00108 } 00109 if (d1->minutes != d2->minutes) { 00110 return d1->minutes - d2->minutes; 00111 } 00112 if (d1->seconds != d2->seconds) { 00113 return d1->seconds - d2->seconds; 00114 } 00115 00116 return 0; 00117 } 00118 00119 00124 duration_type* 00125 duration_create_from_string(const char* str) 00126 { 00127 duration_type* duration = duration_create(); 00128 char* P, *X, *T, *W; 00129 int not_weeks = 0; 00130 00131 if (!duration) { 00132 ods_log_error("[%s] cannot create from string %s: create failed", 00133 duration_str, str); 00134 return NULL; 00135 } 00136 if (!str) { 00137 return duration; 00138 } 00139 00140 P = strchr(str, 'P'); 00141 if (!P) { 00142 ods_log_error("[%s] cannot create from string %s: P not found", 00143 duration_str, str); 00144 duration_cleanup(duration); 00145 return NULL; 00146 } 00147 00148 T = strchr(str, 'T'); 00149 X = strchr(str, 'Y'); 00150 if (X) { 00151 duration->years = atoi(str+1); 00152 str = X; 00153 not_weeks = 1; 00154 } 00155 X = strchr(str, 'M'); 00156 if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) { 00157 duration->months = atoi(str+1); 00158 str = X; 00159 not_weeks = 1; 00160 } 00161 X = strchr(str, 'D'); 00162 if (X) { 00163 duration->days = atoi(str+1); 00164 str = X; 00165 not_weeks = 1; 00166 } 00167 if (T) { 00168 str = T; 00169 not_weeks = 1; 00170 } 00171 X = strchr(str, 'H'); 00172 if (X && T) { 00173 duration->hours = atoi(str+1); 00174 str = X; 00175 not_weeks = 1; 00176 } 00177 X = strrchr(str, 'M'); 00178 if (X && T && (size_t) (X-P) > (size_t) (T-P)) { 00179 duration->minutes = atoi(str+1); 00180 str = X; 00181 not_weeks = 1; 00182 } 00183 X = strchr(str, 'S'); 00184 if (X && T) { 00185 duration->seconds = atoi(str+1); 00186 str = X; 00187 not_weeks = 1; 00188 } 00189 00190 W = strchr(str, 'W'); 00191 if (W) { 00192 if (not_weeks) { 00193 ods_log_error("[%s] cannot create from string: parse error", 00194 duration_str, P); 00195 duration_cleanup(duration); 00196 return NULL; 00197 } else { 00198 duration->weeks = atoi(str+1); 00199 str = W; 00200 } 00201 } 00202 return duration; 00203 } 00204 00205 00210 static size_t 00211 digits_in_number(time_t duration) 00212 { 00213 uint32_t period = (uint32_t) duration; 00214 size_t count = 0; 00215 00216 while (period > 0) { 00217 count++; 00218 period /= 10; 00219 } 00220 return count; 00221 } 00222 00223 00228 char* 00229 duration2string(duration_type* duration) 00230 { 00231 char* str = NULL, *num = NULL; 00232 size_t count = 2; 00233 int T = 0; 00234 00235 if (!duration) { 00236 return NULL; 00237 } 00238 00239 if (duration->years > 0) { 00240 count = count + 1 + digits_in_number(duration->years); 00241 } 00242 if (duration->months > 0) { 00243 count = count + 1 + digits_in_number(duration->months); 00244 } 00245 if (duration->weeks > 0) { 00246 count = count + 1 + digits_in_number(duration->weeks); 00247 } 00248 if (duration->days > 0) { 00249 count = count + 1 + digits_in_number(duration->days); 00250 } 00251 if (duration->hours > 0) { 00252 count = count + 1 + digits_in_number(duration->hours); 00253 T = 1; 00254 } 00255 if (duration->minutes > 0) { 00256 count = count + 1 + digits_in_number(duration->minutes); 00257 T = 1; 00258 } 00259 if (duration->seconds > 0) { 00260 count = count + 1 + digits_in_number(duration->seconds); 00261 T = 1; 00262 } 00263 if (T) { 00264 count++; 00265 } 00266 00267 str = (char*) calloc(count, sizeof(char)); 00268 str[0] = 'P'; 00269 str[1] = '\0'; 00270 00271 if (duration->years > 0) { 00272 count = digits_in_number(duration->years); 00273 num = (char*) calloc(count+2, sizeof(char)); 00274 snprintf(num, count+2, "%uY", (uint32_t) duration->years); 00275 str = strncat(str, num, count+2); 00276 free((void*) num); 00277 } 00278 if (duration->months > 0) { 00279 count = digits_in_number(duration->months); 00280 num = (char*) calloc(count+2, sizeof(char)); 00281 snprintf(num, count+2, "%uM", (uint32_t) duration->months); 00282 str = strncat(str, num, count+2); 00283 free((void*) num); 00284 } 00285 if (duration->weeks > 0) { 00286 count = digits_in_number(duration->weeks); 00287 num = (char*) calloc(count+2, sizeof(char)); 00288 snprintf(num, count+2, "%uW", (uint32_t) duration->weeks); 00289 str = strncat(str, num, count+2); 00290 free((void*) num); 00291 } 00292 if (duration->days > 0) { 00293 count = digits_in_number(duration->days); 00294 num = (char*) calloc(count+2, sizeof(char)); 00295 snprintf(num, count+2, "%uD", (uint32_t) duration->days); 00296 str = strncat(str, num, count+2); 00297 free((void*) num); 00298 } 00299 if (T) { 00300 str = strncat(str, "T", 1); 00301 } 00302 if (duration->hours > 0) { 00303 count = digits_in_number(duration->hours); 00304 num = (char*) calloc(count+2, sizeof(char)); 00305 snprintf(num, count+2, "%uH", (uint32_t) duration->hours); 00306 str = strncat(str, num, count+2); 00307 free((void*) num); 00308 } 00309 if (duration->minutes > 0) { 00310 count = digits_in_number(duration->minutes); 00311 num = (char*) calloc(count+2, sizeof(char)); 00312 snprintf(num, count+2, "%uM", (uint32_t) duration->minutes); 00313 str = strncat(str, num, count+2); 00314 free((void*) num); 00315 } 00316 if (duration->seconds > 0) { 00317 count = digits_in_number(duration->seconds); 00318 num = (char*) calloc(count+2, sizeof(char)); 00319 snprintf(num, count+2, "%uS", (uint32_t) duration->seconds); 00320 str = strncat(str, num, count+2); 00321 free((void*) num); 00322 } 00323 return str; 00324 } 00325 00326 00331 time_t 00332 duration2time(duration_type* duration) 00333 { 00334 time_t period = 0; 00335 char* dstr = NULL; 00336 00337 if (duration) { 00338 period += (duration->seconds); 00339 period += (duration->minutes)*60; 00340 period += (duration->hours)*3600; 00341 period += (duration->days)*86400; 00342 period += (duration->weeks)*86400*7; 00343 period += (duration->months)*86400*31; 00344 period += (duration->years)*86400*365; 00345 00346 if (duration->months || duration->years) { 00347 /* [TODO] calculate correct number of days in this month/year */ 00348 dstr = duration2string(duration); 00349 ods_log_warning("[%s] converting duration %s to approximate value", 00350 duration_str, dstr?dstr:"(null)"); 00351 free((void*) dstr); 00352 } 00353 } 00354 return period; 00355 } 00356 00361 time_t 00362 time_minimum(time_t a, time_t b) 00363 { 00364 return (a < b ? a : b); 00365 } 00366 00371 time_t 00372 time_maximum(time_t a, time_t b) 00373 { 00374 return (a > b ? a : b); 00375 } 00376 00377 00382 time_t 00383 ods_rand(time_t mod) 00384 { 00385 #ifdef HAVE_ARC4RANDOM_UNIFORM 00386 return (time_t) (arc4random_uniform((uint32_t) mod+1)); 00387 #elif HAVE_ARC4RANDOM 00388 return (time_t) (arc4random() % (unsigned) mod+1); 00389 #else 00390 return (time_t) (random() % (unsigned) mod+1); 00391 #endif 00392 } 00393 00394 00395 /* Number of days per month (except for February in leap years). */ 00396 static const int mdays[] = { 00397 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 00398 }; 00399 00400 00401 static int 00402 is_leap_year(int year) 00403 { 00404 return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); 00405 } 00406 00407 00408 static int 00409 leap_days(int y1, int y2) 00410 { 00411 --y1; 00412 --y2; 00413 return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400); 00414 } 00415 00416 00417 /* 00418 * Code taken from NSD 3.2.5, which is 00419 * code adapted from Python 2.4.1 sources (Lib/calendar.py). 00420 */ 00421 static time_t 00422 mktime_from_utc(const struct tm *tm) 00423 { 00424 int year = 1900 + tm->tm_year; 00425 time_t days = 365 * (year - 1970) + leap_days(1970, year); 00426 time_t hours; 00427 time_t minutes; 00428 time_t seconds; 00429 int i; 00430 00431 for (i = 0; i < tm->tm_mon; ++i) { 00432 days += mdays[i]; 00433 } 00434 if (tm->tm_mon > 1 && is_leap_year(year)) { 00435 ++days; 00436 } 00437 days += tm->tm_mday - 1; 00438 00439 hours = days * 24 + tm->tm_hour; 00440 minutes = hours * 60 + tm->tm_min; 00441 seconds = minutes * 60 + tm->tm_sec; 00442 00443 return seconds; 00444 } 00445 00446 00451 static time_t 00452 timeshift2time(const char *time) 00453 { 00454 /* convert a string in format YYMMDDHHMMSS to time_t */ 00455 struct tm tm; 00456 time_t timeshift = 0; 00457 00458 /* Try to scan the time... */ 00459 if (strptime(time, "%Y%m%d%H%M%S", &tm)) { 00460 timeshift = mktime_from_utc(&tm); 00461 } 00462 return timeshift; 00463 } 00464 00465 00470 time_t 00471 time_now(void) 00472 { 00473 #ifdef ENFORCER_TIMESHIFT 00474 const char* env = getenv("ENFORCER_TIMESHIFT"); 00475 if (env) { 00476 return timeshift2time(env); 00477 } else 00478 #endif /* ENFORCER_TIMESHIFT */ 00479 00480 return time(NULL); 00481 } 00482 00483 00488 uint32_t 00489 time_datestamp(time_t tt, const char* format, char** str) 00490 { 00491 time_t t; 00492 struct tm *tmp; 00493 uint32_t ut = 0; 00494 char outstr[32]; 00495 00496 if (tt) { 00497 t = tt; 00498 } else { 00499 t = time_now(); 00500 } 00501 00502 tmp = localtime(&t); 00503 if (tmp == NULL) { 00504 ods_log_error("[%s] time_datestamp: localtime() failed", duration_str); 00505 return 0; 00506 } 00507 00508 if (strftime(outstr, sizeof(outstr), format, tmp) == 0) { 00509 ods_log_error("[%s] time_datestamp: strftime() failed", duration_str); 00510 return 0; 00511 } 00512 00513 ut = (uint32_t) strtoul(outstr, NULL, 10); 00514 if (str) { 00515 *str = strdup(outstr); 00516 } 00517 return ut; 00518 } 00519 00520 static void 00521 time_itoa_reverse(char* s) 00522 { 00523 int i, j; 00524 char c; 00525 00526 for (i = 0, j = strlen(s)-1; i<j; i++, j--) { 00527 c = s[i]; 00528 s[i] = s[j]; 00529 s[j] = c; 00530 } 00531 return; 00532 } 00533 00534 00539 void 00540 time_itoa(time_t n, char* s) 00541 { 00542 int i = 0; 00543 00544 do { /* generate digits in reverse order */ 00545 s[i++] = n % 10 + '0'; /* get next digit */ 00546 } while ((n /= 10) > 0); /* delete it */ 00547 s[i] = '\0'; 00548 time_itoa_reverse(s); 00549 return; 00550 } 00551 00552 00557 void 00558 duration_cleanup(duration_type* duration) 00559 { 00560 allocator_type* allocator; 00561 00562 if (!duration) { 00563 return; 00564 } 00565 allocator = duration->allocator; 00566 allocator_deallocate(allocator, (void*) duration); 00567 allocator_cleanup(allocator); 00568 return; 00569 }