OpenDNSSEC-signer 1.2.1
|
00001 /* 00002 * $Id: duration.c 4294 2011-01-13 19:58:29Z 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 "util/duration.h" 00035 #include "util/log.h" 00036 #include "util/se_malloc.h" 00037 00038 #include <stdio.h> /* snprintf() */ 00039 #include <stdlib.h> /* atoi(), strtoul(), [arc4]random[_uniform](), getenv() */ 00040 #include <string.h> /* strncat(), strchr() */ 00041 #include <time.h> /* time(), localtime(), strftime() */ 00042 00043 00048 duration_type* 00049 duration_create(void) 00050 { 00051 duration_type* duration = (duration_type*) 00052 se_malloc(sizeof(duration_type)); 00053 duration->years = 0; 00054 duration->months = 0; 00055 duration->weeks = 0; 00056 duration->days = 0; 00057 duration->hours = 0; 00058 duration->minutes = 0; 00059 duration->seconds = 0; 00060 return duration; 00061 } 00062 00063 00068 int 00069 duration_compare(duration_type* d1, duration_type* d2) 00070 { 00071 if (!d1 && !d2) { 00072 return 0; 00073 } 00074 if (!d1 || !d2) { 00075 return d1?-1:1; 00076 } 00077 00078 if (d1->years != d2->years) { 00079 return d1->years - d2->years; 00080 } 00081 if (d1->months != d2->months) { 00082 return d1->months - d2->months; 00083 } 00084 if (d1->weeks != d2->weeks) { 00085 return d1->weeks - d2->weeks; 00086 } 00087 if (d1->days != d2->days) { 00088 return d1->days - d2->days; 00089 } 00090 if (d1->hours != d2->hours) { 00091 return d1->hours - d2->hours; 00092 } 00093 if (d1->minutes != d2->minutes) { 00094 return d1->minutes - d2->minutes; 00095 } 00096 if (d1->seconds != d2->seconds) { 00097 return d1->seconds - d2->seconds; 00098 } 00099 00100 return 0; 00101 } 00102 00107 duration_type* 00108 duration_create_from_string(const char* str) 00109 { 00110 duration_type* duration = duration_create(); 00111 char* P, *X, *T, *W; 00112 int not_weeks = 0; 00113 00114 if (!str) { 00115 return duration; 00116 } 00117 00118 P = strchr(str, 'P'); 00119 if (!P) { 00120 se_log_error("unable to create duration from string %s", str); 00121 duration_cleanup(duration); 00122 return NULL; 00123 } 00124 00125 T = strchr(str, 'T'); 00126 X = strchr(str, 'Y'); 00127 if (X) { 00128 duration->years = atoi(str+1); 00129 str = X; 00130 not_weeks = 1; 00131 } 00132 X = strchr(str, 'M'); 00133 if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) { 00134 duration->months = atoi(str+1); 00135 str = X; 00136 not_weeks = 1; 00137 } 00138 X = strchr(str, 'D'); 00139 if (X) { 00140 duration->days = atoi(str+1); 00141 str = X; 00142 not_weeks = 1; 00143 } 00144 if (T) { 00145 str = T; 00146 not_weeks = 1; 00147 } 00148 X = strchr(str, 'H'); 00149 if (X && T) { 00150 duration->hours = atoi(str+1); 00151 str = X; 00152 not_weeks = 1; 00153 } 00154 X = strrchr(str, 'M'); 00155 if (X && T && (size_t) (X-P) > (size_t) (T-P)) { 00156 duration->minutes = atoi(str+1); 00157 str = X; 00158 not_weeks = 1; 00159 } 00160 X = strchr(str, 'S'); 00161 if (X && T) { 00162 duration->seconds = atoi(str+1); 00163 str = X; 00164 not_weeks = 1; 00165 } 00166 00167 W = strchr(str, 'W'); 00168 if (W) { 00169 if (not_weeks) { 00170 se_log_error("unable to create duration from string %s", P); 00171 duration_cleanup(duration); 00172 return NULL; 00173 } else { 00174 duration->weeks = atoi(str+1); 00175 str = W; 00176 } 00177 } 00178 return duration; 00179 } 00180 00181 00186 static size_t 00187 digits_in_number(time_t duration) 00188 { 00189 uint32_t period = (uint32_t) duration; 00190 size_t count = 0; 00191 00192 while (period > 0) { 00193 count++; 00194 period /= 10; 00195 } 00196 return count; 00197 } 00198 00199 00204 char* 00205 duration2string(duration_type* duration) 00206 { 00207 char* str = NULL, *num = NULL; 00208 size_t count = 2; 00209 int T = 0; 00210 00211 if (!duration) { 00212 str = (char*) se_calloc(5, sizeof(char)); 00213 str[0] = '\0'; 00214 str = strncat(str, "None", 4); 00215 return str; 00216 } 00217 00218 if (duration->years > 0) { 00219 count = count + 1 + digits_in_number(duration->years); 00220 } 00221 if (duration->months > 0) { 00222 count = count + 1 + digits_in_number(duration->months); 00223 } 00224 if (duration->weeks > 0) { 00225 count = count + 1 + digits_in_number(duration->weeks); 00226 } 00227 if (duration->days > 0) { 00228 count = count + 1 + digits_in_number(duration->days); 00229 } 00230 if (duration->hours > 0) { 00231 count = count + 1 + digits_in_number(duration->hours); 00232 T = 1; 00233 } 00234 if (duration->minutes > 0) { 00235 count = count + 1 + digits_in_number(duration->minutes); 00236 T = 1; 00237 } 00238 if (duration->seconds > 0) { 00239 count = count + 1 + digits_in_number(duration->seconds); 00240 T = 1; 00241 } 00242 if (T) { 00243 count++; 00244 } 00245 00246 str = (char*) se_calloc(count, sizeof(char)); 00247 str[0] = 'P'; 00248 str[1] = '\0'; 00249 00250 if (duration->years > 0) { 00251 count = digits_in_number(duration->years); 00252 num = (char*) se_calloc(count+2, sizeof(char)); 00253 snprintf(num, count+2, "%uY", (uint32_t) duration->years); 00254 str = strncat(str, num, count+2); 00255 se_free((void*) num); 00256 } 00257 if (duration->months > 0) { 00258 count = digits_in_number(duration->months); 00259 num = (char*) se_calloc(count+2, sizeof(char)); 00260 snprintf(num, count+2, "%uM", (uint32_t) duration->months); 00261 str = strncat(str, num, count+2); 00262 se_free((void*) num); 00263 } 00264 if (duration->weeks > 0) { 00265 count = digits_in_number(duration->weeks); 00266 num = (char*) se_calloc(count+2, sizeof(char)); 00267 snprintf(num, count+2, "%uW", (uint32_t) duration->weeks); 00268 str = strncat(str, num, count+2); 00269 se_free((void*) num); 00270 } 00271 if (duration->days > 0) { 00272 count = digits_in_number(duration->days); 00273 num = (char*) se_calloc(count+2, sizeof(char)); 00274 snprintf(num, count+2, "%uD", (uint32_t) duration->days); 00275 str = strncat(str, num, count+2); 00276 se_free((void*) num); 00277 } 00278 if (T) { 00279 str = strncat(str, "T", 1); 00280 } 00281 if (duration->hours > 0) { 00282 count = digits_in_number(duration->hours); 00283 num = (char*) se_calloc(count+2, sizeof(char)); 00284 snprintf(num, count+2, "%uH", (uint32_t) duration->hours); 00285 str = strncat(str, num, count+2); 00286 se_free((void*) num); 00287 } 00288 if (duration->minutes > 0) { 00289 count = digits_in_number(duration->minutes); 00290 num = (char*) se_calloc(count+2, sizeof(char)); 00291 snprintf(num, count+2, "%uM", (uint32_t) duration->minutes); 00292 str = strncat(str, num, count+2); 00293 se_free((void*) num); 00294 } 00295 if (duration->seconds > 0) { 00296 count = digits_in_number(duration->seconds); 00297 num = (char*) se_calloc(count+2, sizeof(char)); 00298 snprintf(num, count+2, "%uS", (uint32_t) duration->seconds); 00299 str = strncat(str, num, count+2); 00300 se_free((void*) num); 00301 } 00302 return str; 00303 } 00304 00305 00310 time_t 00311 duration2time(duration_type* duration) 00312 { 00313 time_t period = 0; 00314 char* dstr = NULL; 00315 00316 if (duration) { 00317 period += (duration->seconds); 00318 period += (duration->minutes)*60; 00319 period += (duration->hours)*3600; 00320 period += (duration->days)*86400; 00321 period += (duration->weeks)*86400*7; 00322 period += (duration->months)*86400*31; 00323 period += (duration->years)*86400*365; 00324 00325 if (duration->months || duration->years) { 00326 /* TODO calculate correct number of days in this month/year */ 00327 dstr = duration2string(duration); 00328 se_log_warning("converting duration %s to approximate value", 00329 dstr?dstr:"(null)"); 00330 se_free((void*) dstr); 00331 } 00332 } 00333 return period; 00334 } 00335 00340 time_t 00341 time_minimum(time_t a, time_t b) 00342 { 00343 return (a < b ? a : b); 00344 } 00345 00350 time_t 00351 time_maximum(time_t a, time_t b) 00352 { 00353 return (a > b ? a : b); 00354 } 00355 00356 00361 time_t 00362 se_rand(time_t mod) 00363 { 00364 #ifdef HAVE_ARC4RANDOM_UNIFORM 00365 return (time_t) (arc4random_uniform((uint32_t) mod+1)); 00366 #elif HAVE_ARC4RANDOM 00367 return (time_t) (arc4random() % (unsigned) mod+1); 00368 #else 00369 return (time_t) (random() % (unsigned) mod+1); 00370 #endif 00371 } 00372 00373 00374 /* Number of days per month (except for February in leap years). */ 00375 static const int mdays[] = { 00376 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 00377 }; 00378 00379 00380 static int 00381 is_leap_year(int year) 00382 { 00383 return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); 00384 } 00385 00386 00387 static int 00388 leap_days(int y1, int y2) 00389 { 00390 --y1; 00391 --y2; 00392 return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400); 00393 } 00394 00395 00396 /* 00397 * Code taken from NSD 3.2.5, which is 00398 * code adapted from Python 2.4.1 sources (Lib/calendar.py). 00399 */ 00400 static time_t 00401 mktime_from_utc(const struct tm *tm) 00402 { 00403 int year = 1900 + tm->tm_year; 00404 time_t days = 365 * (year - 1970) + leap_days(1970, year); 00405 time_t hours; 00406 time_t minutes; 00407 time_t seconds; 00408 int i; 00409 00410 for (i = 0; i < tm->tm_mon; ++i) { 00411 days += mdays[i]; 00412 } 00413 if (tm->tm_mon > 1 && is_leap_year(year)) { 00414 ++days; 00415 } 00416 days += tm->tm_mday - 1; 00417 00418 hours = days * 24 + tm->tm_hour; 00419 minutes = hours * 60 + tm->tm_min; 00420 seconds = minutes * 60 + tm->tm_sec; 00421 00422 return seconds; 00423 } 00424 00425 00430 time_t 00431 timeshift2time(const char *time) 00432 { 00433 /* convert a string in format YYMMDDHHMMSS to time_t */ 00434 struct tm tm; 00435 time_t timeshift = 0; 00436 00437 /* Try to scan the time... */ 00438 if (strptime(time, "%Y%m%d%H%M%S", &tm)) { 00439 timeshift = mktime_from_utc(&tm); 00440 } 00441 return timeshift; 00442 } 00443 00444 00449 time_t 00450 time_now(void) 00451 { 00452 #ifdef ENFORCER_TIMESHIFT 00453 const char* env = getenv("ENFORCER_TIMESHIFT"); 00454 if (env) { 00455 return timeshift2time(env); 00456 } else 00457 #endif /* ENFORCER_TIMESHIFT */ 00458 00459 return time(NULL); 00460 } 00461 00462 00467 uint32_t 00468 time_datestamp(time_t tt, const char* format, char** str) 00469 { 00470 time_t t; 00471 struct tm *tmp; 00472 uint32_t ut = 0; 00473 char outstr[32]; 00474 00475 if (tt) { 00476 t = tt; 00477 } else { 00478 t = time_now(); 00479 } 00480 00481 tmp = localtime(&t); 00482 if (tmp == NULL) { 00483 se_log_error("time_datestamp: localtime() failed"); 00484 return 0; 00485 } 00486 00487 if (strftime(outstr, sizeof(outstr), format, tmp) == 0) { 00488 se_log_error("time_datestamp: strftime() failed"); 00489 return 0; 00490 } 00491 00492 ut = (uint32_t) strtoul(outstr, NULL, 10); 00493 if (str) { 00494 *str = se_strdup(outstr); 00495 } 00496 return ut; 00497 } 00498 00499 static void 00500 time_itoa_reverse(char* s) 00501 { 00502 int i, j; 00503 char c; 00504 00505 for (i = 0, j = strlen(s)-1; i<j; i++, j--) { 00506 c = s[i]; 00507 s[i] = s[j]; 00508 s[j] = c; 00509 } 00510 return; 00511 } 00512 00513 00518 void 00519 time_itoa(time_t n, char* s) 00520 { 00521 int i = 0; 00522 00523 do { /* generate digits in reverse order */ 00524 s[i++] = n % 10 + '0'; /* get next digit */ 00525 } while ((n /= 10) > 0); /* delete it */ 00526 s[i] = '\0'; 00527 time_itoa_reverse(s); 00528 return; 00529 } 00530 00531 00536 void 00537 duration_cleanup(duration_type* duration) 00538 { 00539 if (duration) { 00540 se_free((void*) duration); 00541 } else { 00542 se_log_warning("cleanup empty duration"); 00543 } 00544 }