time.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* time.c - various time routines */
  42. #include <stdio.h>
  43. #include <sys/types.h>
  44. #ifndef _WIN32
  45. #ifdef AIX
  46. #include <time.h>
  47. #else
  48. #include <sys/time.h>
  49. #endif
  50. #endif /* _WIN32 */
  51. #include "slap.h"
  52. #include "fe.h"
  53. LDAP_API(unsigned long) strntoul( char *from, size_t len, int base );
  54. #define mktime_r(from) mktime (from) /* possible bug: is this thread-safe? */
  55. static time_t currenttime;
  56. static int currenttime_set = 0;
  57. /* XXX currenttime and currenttime_set are used by multiple threads,
  58. * concurrently (one thread sets them, many threads read them),
  59. * WITHOUT SYNCHRONIZATION. If assignment to currenttime especially
  60. * is not atomic, current_time() will return bogus values, and
  61. * bogus behavior may ensue. We think this isn't a problem, because
  62. * currenttime is a static variable, and defined first in this module;
  63. * consequently it's aligned, and doesn't cross cache lines or
  64. * otherwise run afoul of multiprocessor weirdness that might make
  65. * assignment to it non-atomic.
  66. */
  67. #ifndef HAVE_TIME_R
  68. PRLock *time_func_mutex;
  69. int gmtime_r(
  70. const time_t *timer,
  71. struct tm *result
  72. )
  73. {
  74. if ( result == NULL ) {
  75. return -1;
  76. }
  77. PR_Lock( time_func_mutex );
  78. memcpy( (void *) result, (const void *) gmtime( timer ),
  79. sizeof( struct tm ));
  80. PR_Unlock( time_func_mutex );
  81. return 0;
  82. }
  83. int localtime_r(
  84. const time_t *timer,
  85. struct tm *result
  86. )
  87. {
  88. if ( result == NULL ) {
  89. return -1;
  90. }
  91. PR_Lock( time_func_mutex );
  92. memcpy( (void *) result, (const void *) localtime( timer ),
  93. sizeof( struct tm ));
  94. PR_Unlock( time_func_mutex );
  95. return 0;
  96. }
  97. int ctime_r(
  98. const time_t *timer,
  99. char *buffer,
  100. int buflen
  101. )
  102. {
  103. if (( buffer == NULL ) || ( buflen < 26)) {
  104. return -1;
  105. }
  106. PR_Lock( time_func_mutex );
  107. memset( buffer, 0, buflen );
  108. memcpy( buffer, ctime( timer ), 26 );
  109. PR_Unlock( time_func_mutex );
  110. return 0;
  111. }
  112. #endif /* HAVE_TIME_R */
  113. char *
  114. get_timestring(time_t *t)
  115. {
  116. char *timebuf;
  117. #if defined( _WIN32 )
  118. timebuf = ctime( t );
  119. #else
  120. if ( (timebuf = slapi_ch_malloc(32)) == NULL )
  121. return("No memory for get_timestring");
  122. CTIME(t, timebuf, 32);
  123. #endif
  124. timebuf[strlen(timebuf) - 1] = '\0'; /* strip out return */
  125. return(timebuf);
  126. }
  127. void
  128. free_timestring(char *timestr)
  129. {
  130. #if defined( _WIN32 )
  131. return;
  132. #else
  133. if ( timestr != NULL )
  134. slapi_ch_free((void**)&timestr);
  135. #endif
  136. }
  137. /*
  138. * poll_current_time() is called at least once every second by the time
  139. * thread (see daemon.c:time_thread()). current_time() returns the time
  140. * that poll_current_time() last stored. This approach is used to avoid
  141. * calling the time() system call many times per second.
  142. *
  143. * Note: during server startup, poll_current_time() is not called at all so
  144. * current_time() just calls through to time() until poll_current_time() starts
  145. * to be called.
  146. */
  147. time_t
  148. poll_current_time()
  149. {
  150. if ( !currenttime_set ) {
  151. currenttime_set = 1;
  152. }
  153. time( &currenttime );
  154. return( currenttime );
  155. }
  156. time_t
  157. current_time( void )
  158. {
  159. if ( currenttime_set ) {
  160. return( currenttime );
  161. } else {
  162. return( time( (time_t *)0 ));
  163. }
  164. }
  165. time_t
  166. time_plus_sec (time_t l, long r)
  167. /* return the point in time 'r' seconds after 'l'. */
  168. {
  169. /* On many (but not all) platforms this is simply l + r;
  170. perhaps it would be better to implement it that way. */
  171. struct tm t;
  172. if (r == 0) return l; /* performance optimization */
  173. #ifdef _WIN32
  174. {
  175. struct tm *pt = localtime( &l );
  176. memcpy(&t, pt, sizeof(struct tm) );
  177. }
  178. #else
  179. localtime_r (&l, &t);
  180. #endif
  181. /* Conceptually, we want to do: t.tm_sec += r;
  182. but to avoid overflowing fields: */
  183. r += t.tm_sec; t.tm_sec = r % 60; r /= 60;
  184. r += t.tm_min; t.tm_min = r % 60; r /= 60;
  185. r += t.tm_hour; t.tm_hour = r % 24; r /= 24;
  186. t.tm_mday += r; /* may be > 31; mktime_r() must handle this */
  187. /* These constants are chosen to work when the maximum
  188. field values are 127 (the worst case) or more.
  189. Perhaps this is excessively conservative. */
  190. return mktime_r (&t);
  191. }
  192. char*
  193. format_localTime (time_t from)
  194. /* return a newly-allocated string containing the given time, expressed
  195. in the syntax of a generalizedTime, except without the time zone. */
  196. {
  197. char* into;
  198. struct tm t;
  199. #ifdef _WIN32
  200. {
  201. struct tm *pt = localtime( &from );
  202. memcpy(&t, pt, sizeof(struct tm) );
  203. }
  204. #else
  205. localtime_r (&from, &t);
  206. #endif
  207. into = slapi_ch_smprintf("%.4li%.2i%.2i%.2i%.2i%.2i",
  208. 1900L + t.tm_year, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.
  209. tm_sec);
  210. return into;
  211. }
  212. time_t
  213. read_localTime (struct berval* from)
  214. /* the inverse of write_localTime */
  215. {
  216. return (read_genTime(from));
  217. }
  218. time_t
  219. parse_localTime (char* from)
  220. /* the inverse of format_localTime */
  221. {
  222. return (parse_genTime(from));
  223. }
  224. void
  225. write_localTime (time_t from, struct berval* into)
  226. /* like format_localTime, except it returns a berval */
  227. {
  228. into->bv_val = format_localTime (from);
  229. into->bv_len = 14; /* strlen (into->bv_val) */
  230. }
  231. /*
  232. * Function: strntoul
  233. *
  234. * Returns: the value of "from", converted to an unsigned long integer.
  235. *
  236. * Arguments: from - a pointer to the string to be converted.
  237. * len - the maximum number of characters to process.
  238. * base - the base to use for conversion. See strtoul(3).
  239. *
  240. * Returns: See strtoul(3).
  241. */
  242. LDAP_API(unsigned long) strntoul( char *from, size_t len, int base )
  243. {
  244. unsigned long result;
  245. char c = from[ len ];
  246. from[ len ] = '\0';
  247. result = strtoul( from, NULL, base );
  248. from[ len ] = c;
  249. return result;
  250. }
  251. /*
  252. * New time functions.
  253. * The format and write functions, express time as
  254. * generalizedTime (in the Z form).
  255. * The parse and read functions, can read either
  256. * localTime or generalizedTime.
  257. */
  258. char *
  259. format_genTime (time_t from)
  260. /* return a newly-allocated string containing the given time, expressed
  261. in the syntax of a generalizedTime. */
  262. {
  263. char* into;
  264. struct tm t;
  265. #ifdef _WIN32
  266. {
  267. struct tm *pt = gmtime( &from );
  268. memcpy(&t, pt, sizeof(struct tm) );
  269. }
  270. #else
  271. gmtime_r (&from, &t);
  272. #endif
  273. into = slapi_ch_malloc (20);
  274. strftime(into, 20, "%Y%m%d%H%M%SZ", &t);
  275. return into;
  276. }
  277. void
  278. write_genTime (time_t from, struct berval* into)
  279. /* like format_localTime, except it returns a berval */
  280. {
  281. into->bv_val = format_genTime (from);
  282. into->bv_len = strlen (into->bv_val);
  283. }
  284. time_t
  285. read_genTime(struct berval*from)
  286. {
  287. struct tm t;
  288. time_t retTime;
  289. time_t diffsec = 0;
  290. int i, gflag = 0, havesec = 0;
  291. memset (&t, 0, sizeof(t));
  292. t.tm_isdst = -1;
  293. t.tm_year = strntoul (from->bv_val , 4, 10) - 1900L;
  294. t.tm_mon = strntoul (from->bv_val + 4, 2, 10) - 1;
  295. t.tm_mday = strntoul (from->bv_val + 6, 2, 10);
  296. t.tm_hour = strntoul (from->bv_val + 8, 2, 10);
  297. t.tm_min = strntoul (from->bv_val + 10, 2, 10);
  298. i =12;
  299. /*
  300. * the string can end with Z or -xxxx or +xxxx
  301. * or before to have the Z/+/- we may have two digits for the seconds.
  302. * If there's no Z/+/-, it means it's been expressed as local time
  303. * (not standard).
  304. */
  305. while (from->bv_val[i]) {
  306. switch (from->bv_val[i]) {
  307. case 'Z':
  308. case 'z':
  309. gflag = 1;
  310. ++i;
  311. break;
  312. case '+': /* Offset from GMT is on 4 digits */
  313. i++;
  314. diffsec -= strntoul (from->bv_val + i, 4, 10);
  315. gflag = 1;
  316. i += 4;
  317. break;
  318. case '-': /* Offset from GMT is on 4 digits */
  319. i++;
  320. diffsec += strntoul (from->bv_val + i, 4, 10);
  321. gflag = 1;
  322. i += 4;
  323. break;
  324. default:
  325. if (havesec){
  326. /* Ignore milliseconds */
  327. i++;
  328. } else {
  329. t.tm_sec = strntoul (from->bv_val + i, 2, 10);
  330. havesec = 1;
  331. i += 2;
  332. }
  333. } /* end switch */
  334. }
  335. if (gflag){
  336. PRTime pt;
  337. PRExplodedTime expt = {0};
  338. unsigned long year = strntoul (from->bv_val , 4, 10);
  339. expt.tm_year = (PRInt16)year;
  340. expt.tm_month = t.tm_mon;
  341. expt.tm_mday = t.tm_mday;
  342. expt.tm_hour = t.tm_hour;
  343. expt.tm_min = t.tm_min;
  344. expt.tm_sec = t.tm_sec;
  345. /* This is a GMT time */
  346. expt.tm_params.tp_gmt_offset = 0;
  347. expt.tm_params.tp_dst_offset = 0;
  348. /* PRTime is expressed in microseconds */
  349. pt = PR_ImplodeTime(&expt) / 1000000L;
  350. retTime = (time_t)pt;
  351. return (retTime + diffsec);
  352. } else {
  353. return mktime_r (&t);
  354. }
  355. }
  356. time_t
  357. parse_genTime (char* from)
  358. /* the inverse of format_genTime
  359. * Because read_localTime has been rewriten to take into
  360. * account generalizedTime, parse_time is similar to parse_localTime.
  361. * The new call is
  362. */
  363. {
  364. struct berval tbv;
  365. tbv.bv_val = from;
  366. tbv.bv_len = strlen (from);
  367. return read_genTime(&tbv);
  368. }