time.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /* time.c - various time routines */
  13. #include <stdio.h>
  14. #include <sys/types.h>
  15. #include <sys/time.h>
  16. #include "slap.h"
  17. #include "fe.h"
  18. unsigned long strntoul( char *from, size_t len, int base );
  19. #define mktime_r(from) mktime (from) /* possible bug: is this thread-safe? */
  20. static time_t currenttime;
  21. static int currenttime_set = 0;
  22. /* XXX currenttime and currenttime_set are used by multiple threads,
  23. * concurrently (one thread sets them, many threads read them),
  24. * WITHOUT SYNCHRONIZATION. If assignment to currenttime especially
  25. * is not atomic, current_time() will return bogus values, and
  26. * bogus behavior may ensue. We think this isn't a problem, because
  27. * currenttime is a static variable, and defined first in this module;
  28. * consequently it's aligned, and doesn't cross cache lines or
  29. * otherwise run afoul of multiprocessor weirdness that might make
  30. * assignment to it non-atomic.
  31. */
  32. #ifndef HAVE_TIME_R
  33. PRLock *time_func_mutex;
  34. int gmtime_r(
  35. const time_t *timer,
  36. struct tm *result
  37. )
  38. {
  39. if ( result == NULL ) {
  40. return -1;
  41. }
  42. PR_Lock( time_func_mutex );
  43. memcpy( (void *) result, (const void *) gmtime( timer ),
  44. sizeof( struct tm ));
  45. PR_Unlock( time_func_mutex );
  46. return 0;
  47. }
  48. int localtime_r(
  49. const time_t *timer,
  50. struct tm *result
  51. )
  52. {
  53. if ( result == NULL ) {
  54. return -1;
  55. }
  56. PR_Lock( time_func_mutex );
  57. memcpy( (void *) result, (const void *) localtime( timer ),
  58. sizeof( struct tm ));
  59. PR_Unlock( time_func_mutex );
  60. return 0;
  61. }
  62. int ctime_r(
  63. const time_t *timer,
  64. char *buffer,
  65. int buflen
  66. )
  67. {
  68. if (( buffer == NULL ) || ( buflen < 26)) {
  69. return -1;
  70. }
  71. PR_Lock( time_func_mutex );
  72. memset( buffer, 0, buflen );
  73. memcpy( buffer, ctime( timer ), 26 );
  74. PR_Unlock( time_func_mutex );
  75. return 0;
  76. }
  77. #endif /* HAVE_TIME_R */
  78. char *
  79. get_timestring(time_t *t)
  80. {
  81. char *timebuf;
  82. if ( (timebuf = slapi_ch_malloc(32)) == NULL )
  83. return("No memory for get_timestring");
  84. CTIME(t, timebuf, 32);
  85. timebuf[strlen(timebuf) - 1] = '\0'; /* strip out return */
  86. return(timebuf);
  87. }
  88. void
  89. free_timestring(char *timestr)
  90. {
  91. if ( timestr != NULL )
  92. slapi_ch_free((void**)&timestr);
  93. }
  94. /*
  95. * poll_current_time() is called at least once every second by the time
  96. * thread (see daemon.c:time_thread()). current_time() returns the time
  97. * that poll_current_time() last stored. This approach is used to avoid
  98. * calling the time() system call many times per second.
  99. *
  100. * Note: during server startup, poll_current_time() is not called at all so
  101. * current_time() just calls through to time() until poll_current_time() starts
  102. * to be called.
  103. */
  104. time_t
  105. poll_current_time()
  106. {
  107. if ( !currenttime_set ) {
  108. currenttime_set = 1;
  109. }
  110. time( &currenttime );
  111. return( currenttime );
  112. }
  113. time_t
  114. current_time( void )
  115. {
  116. if ( currenttime_set ) {
  117. return( currenttime );
  118. } else {
  119. return( time( (time_t *)0 ));
  120. }
  121. }
  122. time_t
  123. slapi_current_time( void )
  124. {
  125. return current_time();
  126. }
  127. time_t
  128. time_plus_sec (time_t l, long r)
  129. /* return the point in time 'r' seconds after 'l'. */
  130. {
  131. /* On many (but not all) platforms this is simply l + r;
  132. perhaps it would be better to implement it that way. */
  133. struct tm t;
  134. if (r == 0) return l; /* performance optimization */
  135. localtime_r (&l, &t);
  136. /* Conceptually, we want to do: t.tm_sec += r;
  137. but to avoid overflowing fields: */
  138. r += t.tm_sec; t.tm_sec = r % 60; r /= 60;
  139. r += t.tm_min; t.tm_min = r % 60; r /= 60;
  140. r += t.tm_hour; t.tm_hour = r % 24; r /= 24;
  141. t.tm_mday += r; /* may be > 31; mktime_r() must handle this */
  142. /* These constants are chosen to work when the maximum
  143. field values are 127 (the worst case) or more.
  144. Perhaps this is excessively conservative. */
  145. return mktime_r (&t);
  146. }
  147. char*
  148. format_localTime (time_t from)
  149. /* return a newly-allocated string containing the given time, expressed
  150. in the syntax of a generalizedTime, except without the time zone. */
  151. {
  152. char* into;
  153. struct tm t;
  154. localtime_r (&from, &t);
  155. into = slapi_ch_smprintf("%.4li%.2i%.2i%.2i%.2i%.2i",
  156. 1900L + t.tm_year, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.
  157. tm_sec);
  158. return into;
  159. }
  160. time_t
  161. read_localTime (struct berval* from)
  162. /* the inverse of write_localTime */
  163. {
  164. return (read_genTime(from));
  165. }
  166. time_t
  167. parse_localTime (char* from)
  168. /* the inverse of format_localTime */
  169. {
  170. return (parse_genTime(from));
  171. }
  172. void
  173. write_localTime (time_t from, struct berval* into)
  174. /* like format_localTime, except it returns a berval */
  175. {
  176. into->bv_val = format_localTime (from);
  177. into->bv_len = 14; /* strlen (into->bv_val) */
  178. }
  179. /*
  180. * Function: strntoul
  181. *
  182. * Returns: the value of "from", converted to an unsigned long integer.
  183. *
  184. * Arguments: from - a pointer to the string to be converted.
  185. * len - the maximum number of characters to process.
  186. * base - the base to use for conversion. See strtoul(3).
  187. *
  188. * Returns: See strtoul(3).
  189. */
  190. unsigned long strntoul( char *from, size_t len, int base )
  191. {
  192. unsigned long result;
  193. char c = from[ len ];
  194. from[ len ] = '\0';
  195. result = strtoul( from, NULL, base );
  196. from[ len ] = c;
  197. return result;
  198. }
  199. /*
  200. * New time functions.
  201. * The format and write functions, express time as
  202. * generalizedTime (in the Z form).
  203. * The parse and read functions, can read either
  204. * localTime or generalizedTime.
  205. */
  206. char *
  207. format_genTime (time_t from)
  208. /* return a newly-allocated string containing the given time, expressed
  209. in the syntax of a generalizedTime. */
  210. {
  211. char* into;
  212. struct tm t;
  213. gmtime_r (&from, &t);
  214. into = slapi_ch_malloc (20);
  215. strftime(into, 20, "%Y%m%d%H%M%SZ", &t);
  216. return into;
  217. }
  218. void
  219. write_genTime (time_t from, struct berval* into)
  220. /* like format_localTime, except it returns a berval */
  221. {
  222. into->bv_val = format_genTime (from);
  223. into->bv_len = strlen (into->bv_val);
  224. }
  225. time_t
  226. read_genTime(struct berval*from)
  227. {
  228. struct tm t;
  229. time_t retTime;
  230. time_t diffsec = 0;
  231. int i, gflag = 0, havesec = 0;
  232. memset (&t, 0, sizeof(t));
  233. t.tm_isdst = -1;
  234. t.tm_year = strntoul (from->bv_val , 4, 10) - 1900L;
  235. t.tm_mon = strntoul (from->bv_val + 4, 2, 10) - 1;
  236. t.tm_mday = strntoul (from->bv_val + 6, 2, 10);
  237. t.tm_hour = strntoul (from->bv_val + 8, 2, 10);
  238. t.tm_min = strntoul (from->bv_val + 10, 2, 10);
  239. i =12;
  240. /*
  241. * the string can end with Z or -xxxx or +xxxx
  242. * or before to have the Z/+/- we may have two digits for the seconds.
  243. * If there's no Z/+/-, it means it's been expressed as local time
  244. * (not standard).
  245. */
  246. while (from->bv_val[i]) {
  247. switch (from->bv_val[i]) {
  248. case 'Z':
  249. case 'z':
  250. gflag = 1;
  251. ++i;
  252. break;
  253. case '+': /* Offset from GMT is on 4 digits */
  254. i++;
  255. diffsec -= strntoul (from->bv_val + i, 4, 10);
  256. gflag = 1;
  257. i += 4;
  258. break;
  259. case '-': /* Offset from GMT is on 4 digits */
  260. i++;
  261. diffsec += strntoul (from->bv_val + i, 4, 10);
  262. gflag = 1;
  263. i += 4;
  264. break;
  265. default:
  266. if (havesec){
  267. /* Ignore milliseconds */
  268. i++;
  269. } else {
  270. t.tm_sec = strntoul (from->bv_val + i, 2, 10);
  271. havesec = 1;
  272. i += 2;
  273. }
  274. } /* end switch */
  275. }
  276. if (gflag){
  277. PRTime pt;
  278. PRExplodedTime expt = {0};
  279. unsigned long year = strntoul (from->bv_val , 4, 10);
  280. expt.tm_year = (PRInt16)year;
  281. expt.tm_month = t.tm_mon;
  282. expt.tm_mday = t.tm_mday;
  283. expt.tm_hour = t.tm_hour;
  284. expt.tm_min = t.tm_min;
  285. expt.tm_sec = t.tm_sec;
  286. /* This is a GMT time */
  287. expt.tm_params.tp_gmt_offset = 0;
  288. expt.tm_params.tp_dst_offset = 0;
  289. /* PRTime is expressed in microseconds */
  290. pt = PR_ImplodeTime(&expt) / 1000000L;
  291. retTime = (time_t)pt;
  292. return (retTime + diffsec);
  293. } else {
  294. return mktime_r (&t);
  295. }
  296. }
  297. time_t
  298. parse_genTime (char* from)
  299. /* the inverse of format_genTime
  300. * Because read_localTime has been rewriten to take into
  301. * account generalizedTime, parse_time is similar to parse_localTime.
  302. * The new call is
  303. */
  304. {
  305. struct berval tbv;
  306. tbv.bv_val = from;
  307. tbv.bv_len = strlen (from);
  308. return read_genTime(&tbv);
  309. }
  310. /*
  311. * Return Value:
  312. * Success: duration in seconds
  313. * Failure: -1
  314. */
  315. long
  316. parse_duration(char *value)
  317. {
  318. char *input = NULL;
  319. char *endp;
  320. long duration = -1;
  321. int times = 1;
  322. if (NULL == value || '\0' == *value) {
  323. goto bail;
  324. }
  325. input = slapi_ch_strdup(value);
  326. endp = input + strlen(input) - 1;
  327. while ((' ' == *endp || '\t' == *endp) && endp > input) {
  328. endp--;
  329. }
  330. if ((endp == input) && !isdigit(*input)) {
  331. goto bail;
  332. }
  333. switch ( *endp ) {
  334. case 'w':
  335. case 'W':
  336. times = 60 * 60 * 24 * 7;
  337. *endp = '\0';
  338. break;
  339. case 'd':
  340. case 'D':
  341. times = 60 * 60 * 24;
  342. *endp = '\0';
  343. break;
  344. case 'h':
  345. case 'H':
  346. times = 60 * 60;
  347. *endp = '\0';
  348. break;
  349. case 'm':
  350. case 'M':
  351. times = 60;
  352. *endp = '\0';
  353. break;
  354. case 's':
  355. case 'S':
  356. times = 1;
  357. *endp = '\0';
  358. break;
  359. default:
  360. if (isdigit(*endp)) {
  361. times = 1;
  362. break;
  363. } else {
  364. goto bail;
  365. }
  366. }
  367. duration = strtol(input, &endp, 10);
  368. if ( *endp != '\0' || errno == ERANGE ) {
  369. duration = -1;
  370. goto bail;
  371. }
  372. duration *= times;
  373. bail:
  374. if (duration == -1) {
  375. LDAPDebug1Arg(LDAP_DEBUG_ANY, "slapi_parse_duration: invalid duration (%s)\n", value?value:"null");
  376. }
  377. slapi_ch_free_string(&input);
  378. return duration;
  379. }
  380. time_t
  381. slapi_parse_duration(const char *value)
  382. {
  383. return (time_t)parse_duration((char *)value);
  384. }
  385. static int
  386. is_valid_duration_unit(const char value)
  387. {
  388. int rc = 0;
  389. switch (value) {
  390. case 'w':
  391. case 'W':
  392. case 'd':
  393. case 'D':
  394. case 'h':
  395. case 'H':
  396. case 'm':
  397. case 'M':
  398. case 's':
  399. case 'S':
  400. rc = 1;
  401. break;
  402. }
  403. return rc;
  404. }
  405. int
  406. slapi_is_duration_valid(const char *value)
  407. {
  408. int rc = 1; /* valid */
  409. const char *p = value;
  410. if (p && *p && isdigit(*p)) { /* 1st character must be digit */
  411. for (++p; p && *p; p++) {
  412. if (!isdigit(*p) && !is_valid_duration_unit(*p)) {
  413. rc = 0;
  414. goto bail;
  415. }
  416. }
  417. } else {
  418. rc = 0;
  419. }
  420. bail:
  421. return rc;
  422. }
  423. /*
  424. * caller is responsible to free the returned string
  425. */
  426. char *
  427. gen_duration(long duration)
  428. {
  429. char *duration_str = NULL;
  430. long remainder = 0;
  431. long devided = duration;
  432. int devider[] = {60, 60, 24, 0};
  433. char *unit[] = {"", "M", "H", "D", NULL};
  434. int i = 0;
  435. if (0 > duration) {
  436. goto bail;
  437. } else if (0 == duration) {
  438. duration_str = strdup("0");
  439. goto bail;
  440. }
  441. do {
  442. remainder = devided % devider[i];
  443. if (remainder) {
  444. break;
  445. }
  446. devided /= devider[i++];
  447. } while (devider[i]);
  448. duration_str = slapi_ch_smprintf("%ld%s", devided, unit[i]);
  449. bail:
  450. return duration_str;
  451. }