1 /* $NetBSD: time.c,v 1.6 2014/12/10 04:37:58 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2005, 2007, 2009-2012, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1998-2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <stdio.h> 27 #include <isc/string.h> /* Required for HP/UX (and others?) */ 28 #include <time.h> 29 #include <ctype.h> 30 31 #include <isc/print.h> 32 #include <isc/region.h> 33 #include <isc/serial.h> 34 #include <isc/stdtime.h> 35 #include <isc/util.h> 36 37 #include <dns/result.h> 38 #include <dns/time.h> 39 40 static const int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 41 42 isc_result_t 43 dns_time64_totext(isc_int64_t t, isc_buffer_t *target) { 44 struct tm tm; 45 char buf[sizeof("YYYYMMDDHHMMSS")]; 46 int secs; 47 unsigned int l; 48 isc_region_t region; 49 50 /* 51 * Warning. Do NOT use arguments with side effects with these macros. 52 */ 53 #define is_leap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) 54 #define year_secs(y) ((is_leap(y) ? 366 : 365 ) * 86400) 55 #define month_secs(m,y) ((days[m] + ((m == 1 && is_leap(y)) ? 1 : 0 )) * 86400) 56 57 tm.tm_year = 70; 58 while (t < 0) { 59 if (tm.tm_year == 0) 60 return (ISC_R_RANGE); 61 tm.tm_year--; 62 secs = year_secs(tm.tm_year + 1900); 63 t += secs; 64 } 65 while ((secs = year_secs(tm.tm_year + 1900)) <= t) { 66 t -= secs; 67 tm.tm_year++; 68 if (tm.tm_year + 1900 > 9999) 69 return (ISC_R_RANGE); 70 } 71 tm.tm_mon = 0; 72 while ((secs = month_secs(tm.tm_mon, tm.tm_year + 1900)) <= t) { 73 t -= secs; 74 tm.tm_mon++; 75 } 76 tm.tm_mday = 1; 77 while (86400 <= t) { 78 t -= 86400; 79 tm.tm_mday++; 80 } 81 tm.tm_hour = 0; 82 while (3600 <= t) { 83 t -= 3600; 84 tm.tm_hour++; 85 } 86 tm.tm_min = 0; 87 while (60 <= t) { 88 t -= 60; 89 tm.tm_min++; 90 } 91 tm.tm_sec = (int)t; 92 /* yyyy mm dd HH MM SS */ 93 snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02d", 94 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 95 tm.tm_hour, tm.tm_min, tm.tm_sec); 96 97 isc_buffer_availableregion(target, ®ion); 98 l = strlen(buf); 99 100 if (l > region.length) 101 return (ISC_R_NOSPACE); 102 103 memmove(region.base, buf, l); 104 isc_buffer_add(target, l); 105 return (ISC_R_SUCCESS); 106 } 107 108 isc_int64_t 109 dns_time64_from32(isc_uint32_t value) { 110 isc_stdtime_t now; 111 isc_int64_t start; 112 isc_int64_t t; 113 114 /* 115 * Adjust the time to the closest epoch. This should be changed 116 * to use a 64-bit counterpart to isc_stdtime_get() if one ever 117 * is defined, but even the current code is good until the year 118 * 2106. 119 */ 120 isc_stdtime_get(&now); 121 start = (isc_int64_t) now; 122 if (isc_serial_gt(value, now)) 123 t = start + (value - now); 124 else 125 t = start - (now - value); 126 127 return (t); 128 } 129 130 isc_result_t 131 dns_time32_totext(isc_uint32_t value, isc_buffer_t *target) { 132 return (dns_time64_totext(dns_time64_from32(value), target)); 133 } 134 135 isc_result_t 136 dns_time64_fromtext(const char *source, isc_int64_t *target) { 137 int year, month, day, hour, minute, second; 138 isc_int64_t value; 139 int secs; 140 int i; 141 142 #define RANGE(min, max, value) \ 143 do { \ 144 if (value < (min) || value > (max)) \ 145 return (ISC_R_RANGE); \ 146 } while (/*CONSTCOND*/0) 147 148 if (strlen(source) != 14U) 149 return (DNS_R_SYNTAX); 150 /* 151 * Confirm the source only consists digits. sscanf() allows some 152 * minor exceptions. 153 */ 154 for (i = 0; i < 14; i++) { 155 if (!isdigit((unsigned char)source[i])) 156 return (DNS_R_SYNTAX); 157 } 158 if (sscanf(source, "%4d%2d%2d%2d%2d%2d", 159 &year, &month, &day, &hour, &minute, &second) != 6) 160 return (DNS_R_SYNTAX); 161 162 RANGE(0, 9999, year); 163 RANGE(1, 12, month); 164 RANGE(1, days[month - 1] + 165 ((month == 2 && is_leap(year)) ? 1 : 0), day); 166 #ifdef __COVERITY__ 167 /* 168 * Use a simplified range to silence Coverity warning (in 169 * arithmetic with day below). 170 */ 171 RANGE(1, 31, day); 172 #endif /* __COVERITY__ */ 173 174 RANGE(0, 23, hour); 175 RANGE(0, 59, minute); 176 RANGE(0, 60, second); /* 60 == leap second. */ 177 178 /* 179 * Calculate seconds from epoch. 180 * Note: this uses a idealized calendar. 181 */ 182 value = second + (60 * minute) + (3600 * hour) + ((day - 1) * 86400); 183 for (i = 0; i < (month - 1); i++) 184 value += days[i] * 86400; 185 if (is_leap(year) && month > 2) 186 value += 86400; 187 if (year < 1970) { 188 for (i = 1969; i >= year; i--) { 189 secs = (is_leap(i) ? 366 : 365) * 86400; 190 value -= secs; 191 } 192 } else { 193 for (i = 1970; i < year; i++) { 194 secs = (is_leap(i) ? 366 : 365) * 86400; 195 value += secs; 196 } 197 } 198 199 *target = value; 200 return (ISC_R_SUCCESS); 201 } 202 203 isc_result_t 204 dns_time32_fromtext(const char *source, isc_uint32_t *target) { 205 isc_int64_t value64; 206 isc_result_t result; 207 result = dns_time64_fromtext(source, &value64); 208 if (result != ISC_R_SUCCESS) 209 return (result); 210 *target = (isc_uint32_t)value64; 211 212 return (ISC_R_SUCCESS); 213 } 214