OpenDNSSEC-signer  1.4.3
duration.c
Go to the documentation of this file.
1 /*
2  * $Id: duration.c 7352 2013-10-09 12:33:09Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "shared/allocator.h"
35 #include "shared/duration.h"
36 #include "shared/log.h"
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 
43 static const char* duration_str = "duration";
44 
45 
52 {
53  duration_type* duration;
54  allocator_type* allocator = allocator_create(malloc, free);
55  if (!allocator) {
56  ods_log_error("[%s] cannot create: no allocator available",
57  duration_str);
58  return NULL;
59  }
60 
61  duration = (duration_type*) allocator_alloc(allocator,
62  sizeof(duration_type));
63  if (!duration) {
64  ods_log_error("[%s] cannot create: allocator failed", duration_str);
65  allocator_cleanup(allocator);
66  return NULL;
67  }
68  duration->allocator = allocator;
69  duration->years = 0;
70  duration->months = 0;
71  duration->weeks = 0;
72  duration->days = 0;
73  duration->hours = 0;
74  duration->minutes = 0;
75  duration->seconds = 0;
76  return duration;
77 }
78 
79 
84 int
86 {
87  if (!d1 && !d2) {
88  return 0;
89  }
90  if (!d1 || !d2) {
91  return d1?-1:1;
92  }
93 
94  if (d1->years != d2->years) {
95  return d1->years - d2->years;
96  }
97  if (d1->months != d2->months) {
98  return d1->months - d2->months;
99  }
100  if (d1->weeks != d2->weeks) {
101  return d1->weeks - d2->weeks;
102  }
103  if (d1->days != d2->days) {
104  return d1->days - d2->days;
105  }
106  if (d1->hours != d2->hours) {
107  return d1->hours - d2->hours;
108  }
109  if (d1->minutes != d2->minutes) {
110  return d1->minutes - d2->minutes;
111  }
112  if (d1->seconds != d2->seconds) {
113  return d1->seconds - d2->seconds;
114  }
115 
116  return 0;
117 }
118 
119 
126 {
127  duration_type* duration = duration_create();
128  char* P, *X, *T, *W;
129  int not_weeks = 0;
130 
131  if (!duration) {
132  ods_log_error("[%s] cannot create from string %s: create failed",
133  duration_str, str);
134  return NULL;
135  }
136  if (!str) {
137  return duration;
138  }
139 
140  P = strchr(str, 'P');
141  if (!P) {
142  ods_log_error("[%s] cannot create from string %s: P not found",
143  duration_str, str);
144  duration_cleanup(duration);
145  return NULL;
146  }
147 
148  T = strchr(str, 'T');
149  X = strchr(str, 'Y');
150  if (X) {
151  duration->years = atoi(str+1);
152  str = X;
153  not_weeks = 1;
154  }
155  X = strchr(str, 'M');
156  if (X && (!T || (size_t) (X-P) < (size_t) (T-P))) {
157  duration->months = atoi(str+1);
158  str = X;
159  not_weeks = 1;
160  }
161  X = strchr(str, 'D');
162  if (X) {
163  duration->days = atoi(str+1);
164  str = X;
165  not_weeks = 1;
166  }
167  if (T) {
168  str = T;
169  not_weeks = 1;
170  }
171  X = strchr(str, 'H');
172  if (X && T) {
173  duration->hours = atoi(str+1);
174  str = X;
175  not_weeks = 1;
176  }
177  X = strrchr(str, 'M');
178  if (X && T && (size_t) (X-P) > (size_t) (T-P)) {
179  duration->minutes = atoi(str+1);
180  str = X;
181  not_weeks = 1;
182  }
183  X = strchr(str, 'S');
184  if (X && T) {
185  duration->seconds = atoi(str+1);
186  str = X;
187  not_weeks = 1;
188  }
189 
190  W = strchr(str, 'W');
191  if (W) {
192  if (not_weeks) {
193  ods_log_error("[%s] cannot create from string: parse error",
194  duration_str, P);
195  duration_cleanup(duration);
196  return NULL;
197  } else {
198  duration->weeks = atoi(str+1);
199  str = W;
200  }
201  }
202  return duration;
203 }
204 
205 
210 static size_t
211 digits_in_number(time_t duration)
212 {
213  uint32_t period = (uint32_t) duration;
214  size_t count = 0;
215  if (!period) {
216  return 1;
217  }
218  while (period > 0) {
219  count++;
220  period /= 10;
221  }
222  return count;
223 }
224 
225 
230 char*
232 {
233  char* str = NULL, *num = NULL;
234  size_t count = 2;
235  int T = 0, D = 0;
236 
237  if (!duration) {
238  return NULL;
239  }
240 
241  if (duration->years > 0) {
242  count = count + 1 + digits_in_number(duration->years);
243  D = 1;
244  }
245  if (duration->months > 0) {
246  count = count + 1 + digits_in_number(duration->months);
247  D = 1;
248  }
249  if (duration->weeks > 0) {
250  count = count + 1 + digits_in_number(duration->weeks);
251  D = 1;
252  }
253  if (duration->days > 0) {
254  count = count + 1 + digits_in_number(duration->days);
255  D = 1;
256  }
257  if (duration->hours > 0) {
258  count = count + 1 + digits_in_number(duration->hours);
259  T = 1;
260  }
261  if (duration->minutes > 0) {
262  count = count + 1 + digits_in_number(duration->minutes);
263  T = 1;
264  }
265  if (duration->seconds > 0 ||
266  (!D && !duration->hours && !duration->minutes)) {
267  count = count + 1 + digits_in_number(duration->seconds);
268  T = 1;
269  }
270  if (T) {
271  count++;
272  }
273 
274  str = (char*) calloc(count, sizeof(char));
275  str[0] = 'P';
276  str[1] = '\0';
277 
278  if (duration->years > 0) {
279  count = digits_in_number(duration->years);
280  num = (char*) calloc(count+2, sizeof(char));
281  if (num) {
282  snprintf(num, count+2, "%uY", (uint32_t) duration->years);
283  str = strncat(str, num, count+2);
284  free((void*) num);
285  } else {
286  goto duration2string_num_calloc_failed;
287  }
288  }
289  if (duration->months > 0) {
290  count = digits_in_number(duration->months);
291  num = (char*) calloc(count+2, sizeof(char));
292  if (num) {
293  snprintf(num, count+2, "%uM", (uint32_t) duration->months);
294  str = strncat(str, num, count+2);
295  free((void*) num);
296  } else {
297  goto duration2string_num_calloc_failed;
298  }
299  }
300  if (duration->weeks > 0) {
301  count = digits_in_number(duration->weeks);
302  num = (char*) calloc(count+2, sizeof(char));
303  if (num) {
304  snprintf(num, count+2, "%uW", (uint32_t) duration->weeks);
305  str = strncat(str, num, count+2);
306  free((void*) num);
307  } else {
308  goto duration2string_num_calloc_failed;
309  }
310  }
311  if (duration->days > 0) {
312  count = digits_in_number(duration->days);
313  num = (char*) calloc(count+2, sizeof(char));
314  if (num) {
315  snprintf(num, count+2, "%uD", (uint32_t) duration->days);
316  str = strncat(str, num, count+2);
317  free((void*) num);
318  } else {
319  goto duration2string_num_calloc_failed;
320  }
321  }
322  if (T) {
323  str = strncat(str, "T", 1);
324  }
325  if (duration->hours > 0) {
326  count = digits_in_number(duration->hours);
327  num = (char*) calloc(count+2, sizeof(char));
328  if (num) {
329  snprintf(num, count+2, "%uH", (uint32_t) duration->hours);
330  str = strncat(str, num, count+2);
331  free((void*) num);
332  } else {
333  goto duration2string_num_calloc_failed;
334  }
335  }
336  if (duration->minutes > 0) {
337  count = digits_in_number(duration->minutes);
338  num = (char*) calloc(count+2, sizeof(char));
339  if (num) {
340  snprintf(num, count+2, "%uM", (uint32_t) duration->minutes);
341  str = strncat(str, num, count+2);
342  free((void*) num);
343  } else {
344  goto duration2string_num_calloc_failed;
345  }
346  }
347  if (duration->seconds > 0 ||
348  (!D && !duration->hours && !duration->minutes)) {
349  count = digits_in_number(duration->seconds);
350  num = (char*) calloc(count+2, sizeof(char));
351  if (num) {
352  snprintf(num, count+2, "%uS", (uint32_t) duration->seconds);
353  str = strncat(str, num, count+2);
354  free((void*) num);
355  } else {
356  goto duration2string_num_calloc_failed;
357  }
358  }
359  return str;
360 
361 duration2string_num_calloc_failed:
362  ods_log_error("[%s] cannot create string: malloc error", duration_str);
363  free((void*) str);
364  return NULL;
365 }
366 
367 
372 time_t
374 {
375  time_t period = 0;
376  char* dstr = NULL;
377 
378  if (duration) {
379  period += (duration->seconds);
380  period += (duration->minutes)*60;
381  period += (duration->hours)*3600;
382  period += (duration->days)*86400;
383  period += (duration->weeks)*86400*7;
384  period += (duration->months)*86400*31;
385  period += (duration->years)*86400*365;
386 
387  if (duration->months || duration->years) {
388  /* [TODO] calculate correct number of days in this month/year */
389  dstr = duration2string(duration);
390  ods_log_warning("[%s] converting duration %s to approximate value",
391  duration_str, dstr?dstr:"(null)");
392  free((void*) dstr);
393  }
394  }
395  return period;
396 }
397 
402 time_t
403 time_minimum(time_t a, time_t b)
404 {
405  return (a < b ? a : b);
406 }
407 
412 time_t
413 time_maximum(time_t a, time_t b)
414 {
415  return (a > b ? a : b);
416 }
417 
418 
423 time_t
424 ods_rand(time_t mod)
425 {
426 #ifdef HAVE_ARC4RANDOM_UNIFORM
427  return (time_t) (arc4random_uniform((uint32_t) mod+1));
428 #elif HAVE_ARC4RANDOM
429  return (time_t) (arc4random() % (unsigned) mod+1);
430 #else
431  return (time_t) (random() % (unsigned) mod+1);
432 #endif
433 }
434 
435 
436 /* Number of days per month (except for February in leap years). */
437 static const int mdays[] = {
438  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
439 };
440 
441 
442 static int
443 is_leap_year(int year)
444 {
445  return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
446 }
447 
448 
449 static int
450 leap_days(int y1, int y2)
451 {
452  --y1;
453  --y2;
454  return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400);
455 }
456 
457 
458 #ifdef ENFORCER_TIMESHIFT
459 /*
460  * Code taken from NSD 3.2.5, which is
461  * code adapted from Python 2.4.1 sources (Lib/calendar.py).
462  */
463 static time_t
464 mktime_from_utc(const struct tm *tm)
465 {
466  int year = 1900 + tm->tm_year;
467  time_t days = 365 * ((time_t) (year - 1970)) +
468  ((time_t) leap_days(1970, year));
469  time_t hours;
470  time_t minutes;
471  time_t seconds;
472  int i;
473 
474  for (i = 0; i < tm->tm_mon; ++i) {
475  days += mdays[i];
476  }
477  if (tm->tm_mon > 1 && is_leap_year(year)) {
478  ++days;
479  }
480  days += tm->tm_mday - 1;
481 
482  hours = days * 24 + tm->tm_hour;
483  minutes = hours * 60 + tm->tm_min;
484  seconds = minutes * 60 + tm->tm_sec;
485 
486  return seconds;
487 }
488 
489 
494 static time_t
495 timeshift2time(const char *time)
496 {
497  /* convert a string in format YYMMDDHHMMSS to time_t */
498  struct tm tm;
499  time_t timeshift = 0;
500 
501  /* Try to scan the time... */
502  if (strptime(time, "%Y%m%d%H%M%S", &tm)) {
503  timeshift = mktime_from_utc(&tm);
504  }
505  return timeshift;
506 }
507 #endif
508 
509 
514 time_t
515 time_now(void)
516 {
517 #ifdef ENFORCER_TIMESHIFT
518  const char* env = getenv("ENFORCER_TIMESHIFT");
519  if (env) {
520  return timeshift2time(env);
521  } else
522 #endif /* ENFORCER_TIMESHIFT */
523 
524  return time(NULL);
525 }
526 
527 
532 uint32_t
533 time_datestamp(time_t tt, const char* format, char** str)
534 {
535  time_t t;
536  struct tm *tmp;
537  uint32_t ut = 0;
538  char outstr[32];
539 
540  if (tt) {
541  t = tt;
542  } else {
543  t = time_now();
544  }
545 
546  tmp = localtime(&t);
547  if (tmp == NULL) {
548  ods_log_error("[%s] time_datestamp: localtime() failed", duration_str);
549  return 0;
550  }
551 
552  if (strftime(outstr, sizeof(outstr), format, tmp) == 0) {
553  ods_log_error("[%s] time_datestamp: strftime() failed", duration_str);
554  return 0;
555  }
556 
557  ut = (uint32_t) strtoul(outstr, NULL, 10);
558  if (str) {
559  *str = strdup(outstr);
560  }
561  return ut;
562 }
563 
564 static void
565 time_itoa_reverse(char* s)
566 {
567  int i, j;
568  char c;
569 
570  for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
571  c = s[i];
572  s[i] = s[j];
573  s[j] = c;
574  }
575  return;
576 }
577 
578 
583 void
584 time_itoa(time_t n, char* s)
585 {
586  int i = 0;
587 
588  do { /* generate digits in reverse order */
589  s[i++] = n % 10 + '0'; /* get next digit */
590  } while ((n /= 10) > 0); /* delete it */
591  s[i] = '\0';
592  time_itoa_reverse(s);
593  return;
594 }
595 
596 
601 void
603 {
604  allocator_type* allocator;
605 
606  if (!duration) {
607  return;
608  }
609  allocator = duration->allocator;
610  allocator_deallocate(allocator, (void*) duration);
611  allocator_cleanup(allocator);
612  return;
613 }
time_t hours
Definition: duration.h:55
uint32_t time_datestamp(time_t tt, const char *format, char **str)
Definition: duration.c:533
void * allocator_alloc(allocator_type *allocator, size_t size)
Definition: allocator.c:68
duration_type * duration_create(void)
Definition: duration.c:51
time_t minutes
Definition: duration.h:56
time_t seconds
Definition: duration.h:57
void ods_log_error(const char *format,...)
Definition: log.c:336
time_t years
Definition: duration.h:51
time_t weeks
Definition: duration.h:53
time_t months
Definition: duration.h:52
void duration_cleanup(duration_type *duration)
Definition: duration.c:602
time_t time_maximum(time_t a, time_t b)
Definition: duration.c:413
allocator_type * allocator_create(void *(*allocator)(size_t size), void(*deallocator)(void *))
Definition: allocator.c:49
char * duration2string(duration_type *duration)
Definition: duration.c:231
time_t duration2time(duration_type *duration)
Definition: duration.c:373
int duration_compare(duration_type *d1, duration_type *d2)
Definition: duration.c:85
void allocator_cleanup(allocator_type *allocator)
Definition: allocator.c:153
void time_itoa(time_t n, char *s)
Definition: duration.c:584
void allocator_deallocate(allocator_type *allocator, void *data)
Definition: allocator.c:137
allocator_type * allocator
Definition: duration.h:50
duration_type * duration_create_from_string(const char *str)
Definition: duration.c:125
time_t ods_rand(time_t mod)
Definition: duration.c:424
time_t time_minimum(time_t a, time_t b)
Definition: duration.c:403
void ods_log_warning(const char *format,...)
Definition: log.c:320
time_t days
Definition: duration.h:54
time_t time_now(void)
Definition: duration.c:515