LCOV - code coverage report
Current view: top level - basic - time-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 561 738 76.0 %
Date: 2019-08-22 15:41:25 Functions: 34 46 73.9 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <ctype.h>
       4             : #include <errno.h>
       5             : #include <limits.h>
       6             : #include <stdlib.h>
       7             : #include <string.h>
       8             : #include <sys/mman.h>
       9             : #include <sys/stat.h>
      10             : #include <sys/time.h>
      11             : #include <sys/timerfd.h>
      12             : #include <sys/timex.h>
      13             : #include <sys/types.h>
      14             : #include <unistd.h>
      15             : 
      16             : #include "alloc-util.h"
      17             : #include "fd-util.h"
      18             : #include "fileio.h"
      19             : #include "fs-util.h"
      20             : #include "io-util.h"
      21             : #include "log.h"
      22             : #include "macro.h"
      23             : #include "missing_timerfd.h"
      24             : #include "parse-util.h"
      25             : #include "path-util.h"
      26             : #include "process-util.h"
      27             : #include "stat-util.h"
      28             : #include "string-util.h"
      29             : #include "strv.h"
      30             : #include "time-util.h"
      31             : 
      32      235024 : static clockid_t map_clock_id(clockid_t c) {
      33             : 
      34             :         /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will
      35             :          * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is
      36             :          * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on
      37             :          * those archs. */
      38             : 
      39      235024 :         switch (c) {
      40             : 
      41           1 :         case CLOCK_BOOTTIME_ALARM:
      42           1 :                 return CLOCK_BOOTTIME;
      43             : 
      44           8 :         case CLOCK_REALTIME_ALARM:
      45           8 :                 return CLOCK_REALTIME;
      46             : 
      47      235015 :         default:
      48      235015 :                 return c;
      49             :         }
      50             : }
      51             : 
      52      235002 : usec_t now(clockid_t clock_id) {
      53             :         struct timespec ts;
      54             : 
      55      235002 :         assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
      56             : 
      57      235002 :         return timespec_load(&ts);
      58             : }
      59             : 
      60           0 : nsec_t now_nsec(clockid_t clock_id) {
      61             :         struct timespec ts;
      62             : 
      63           0 :         assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
      64             : 
      65           0 :         return timespec_load_nsec(&ts);
      66             : }
      67             : 
      68        8100 : dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
      69        8100 :         assert(ts);
      70             : 
      71        8100 :         ts->realtime = now(CLOCK_REALTIME);
      72        8100 :         ts->monotonic = now(CLOCK_MONOTONIC);
      73             : 
      74        8100 :         return ts;
      75             : }
      76             : 
      77       51737 : triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
      78       51737 :         assert(ts);
      79             : 
      80       51737 :         ts->realtime = now(CLOCK_REALTIME);
      81       51737 :         ts->monotonic = now(CLOCK_MONOTONIC);
      82       51737 :         ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY;
      83             : 
      84       51737 :         return ts;
      85             : }
      86             : 
      87           0 : dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
      88             :         int64_t delta;
      89           0 :         assert(ts);
      90             : 
      91           0 :         if (u == USEC_INFINITY || u <= 0) {
      92           0 :                 ts->realtime = ts->monotonic = u;
      93           0 :                 return ts;
      94             :         }
      95             : 
      96           0 :         ts->realtime = u;
      97             : 
      98           0 :         delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
      99           0 :         ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
     100             : 
     101           0 :         return ts;
     102             : }
     103             : 
     104           0 : triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) {
     105             :         int64_t delta;
     106             : 
     107           0 :         assert(ts);
     108             : 
     109           0 :         if (u == USEC_INFINITY || u <= 0) {
     110           0 :                 ts->realtime = ts->monotonic = ts->boottime = u;
     111           0 :                 return ts;
     112             :         }
     113             : 
     114           0 :         ts->realtime = u;
     115           0 :         delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
     116           0 :         ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
     117           0 :         ts->boottime = clock_boottime_supported() ? usec_sub_signed(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
     118             : 
     119           0 :         return ts;
     120             : }
     121             : 
     122           1 : dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
     123             :         int64_t delta;
     124           1 :         assert(ts);
     125             : 
     126           1 :         if (u == USEC_INFINITY) {
     127           0 :                 ts->realtime = ts->monotonic = USEC_INFINITY;
     128           0 :                 return ts;
     129             :         }
     130             : 
     131           1 :         ts->monotonic = u;
     132           1 :         delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
     133           1 :         ts->realtime = usec_sub_signed(now(CLOCK_REALTIME), delta);
     134             : 
     135           1 :         return ts;
     136             : }
     137             : 
     138           0 : dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
     139             :         int64_t delta;
     140             : 
     141           0 :         if (u == USEC_INFINITY) {
     142           0 :                 ts->realtime = ts->monotonic = USEC_INFINITY;
     143           0 :                 return ts;
     144             :         }
     145             : 
     146           0 :         dual_timestamp_get(ts);
     147           0 :         delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
     148           0 :         ts->realtime = usec_sub_signed(ts->realtime, delta);
     149           0 :         ts->monotonic = usec_sub_signed(ts->monotonic, delta);
     150             : 
     151           0 :         return ts;
     152             : }
     153             : 
     154          61 : usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) {
     155             : 
     156          61 :         switch (clock) {
     157             : 
     158           7 :         case CLOCK_REALTIME:
     159             :         case CLOCK_REALTIME_ALARM:
     160           7 :                 return ts->realtime;
     161             : 
     162           7 :         case CLOCK_MONOTONIC:
     163           7 :                 return ts->monotonic;
     164             : 
     165          47 :         case CLOCK_BOOTTIME:
     166             :         case CLOCK_BOOTTIME_ALARM:
     167          47 :                 return ts->boottime;
     168             : 
     169           0 :         default:
     170           0 :                 return USEC_INFINITY;
     171             :         }
     172             : }
     173             : 
     174      237337 : usec_t timespec_load(const struct timespec *ts) {
     175      237337 :         assert(ts);
     176             : 
     177      237337 :         if (ts->tv_sec < 0 || ts->tv_nsec < 0)
     178           0 :                 return USEC_INFINITY;
     179             : 
     180      237337 :         if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
     181           0 :                 return USEC_INFINITY;
     182             : 
     183             :         return
     184      474674 :                 (usec_t) ts->tv_sec * USEC_PER_SEC +
     185      237337 :                 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
     186             : }
     187             : 
     188           0 : nsec_t timespec_load_nsec(const struct timespec *ts) {
     189           0 :         assert(ts);
     190             : 
     191           0 :         if (ts->tv_sec < 0 || ts->tv_nsec < 0)
     192           0 :                 return NSEC_INFINITY;
     193             : 
     194           0 :         if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC)
     195           0 :                 return NSEC_INFINITY;
     196             : 
     197           0 :         return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec;
     198             : }
     199             : 
     200         139 : struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
     201         139 :         assert(ts);
     202             : 
     203         139 :         if (u == USEC_INFINITY ||
     204             :             u / USEC_PER_SEC >= TIME_T_MAX) {
     205           0 :                 ts->tv_sec = (time_t) -1;
     206           0 :                 ts->tv_nsec = (long) -1;
     207           0 :                 return ts;
     208             :         }
     209             : 
     210         139 :         ts->tv_sec = (time_t) (u / USEC_PER_SEC);
     211         139 :         ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
     212             : 
     213         139 :         return ts;
     214             : }
     215             : 
     216           0 : usec_t timeval_load(const struct timeval *tv) {
     217           0 :         assert(tv);
     218             : 
     219           0 :         if (tv->tv_sec < 0 || tv->tv_usec < 0)
     220           0 :                 return USEC_INFINITY;
     221             : 
     222           0 :         if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
     223           0 :                 return USEC_INFINITY;
     224             : 
     225             :         return
     226           0 :                 (usec_t) tv->tv_sec * USEC_PER_SEC +
     227           0 :                 (usec_t) tv->tv_usec;
     228             : }
     229             : 
     230         101 : struct timeval *timeval_store(struct timeval *tv, usec_t u) {
     231         101 :         assert(tv);
     232             : 
     233         101 :         if (u == USEC_INFINITY ||
     234             :             u / USEC_PER_SEC > TIME_T_MAX) {
     235           0 :                 tv->tv_sec = (time_t) -1;
     236           0 :                 tv->tv_usec = (suseconds_t) -1;
     237             :         } else {
     238         101 :                 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
     239         101 :                 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
     240             :         }
     241             : 
     242         101 :         return tv;
     243             : }
     244             : 
     245        6500 : static char *format_timestamp_internal(
     246             :                 char *buf,
     247             :                 size_t l,
     248             :                 usec_t t,
     249             :                 bool utc,
     250             :                 bool us) {
     251             : 
     252             :         /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
     253             :          * generated timestamps may be parsed with parse_timestamp(), and always read the same. */
     254             :         static const char * const weekdays[] = {
     255             :                 [0] = "Sun",
     256             :                 [1] = "Mon",
     257             :                 [2] = "Tue",
     258             :                 [3] = "Wed",
     259             :                 [4] = "Thu",
     260             :                 [5] = "Fri",
     261             :                 [6] = "Sat",
     262             :         };
     263             : 
     264             :         struct tm tm;
     265             :         time_t sec;
     266             :         size_t n;
     267             : 
     268        6500 :         assert(buf);
     269             : 
     270        6500 :         if (l < (size_t) (3 +                  /* week day */
     271             :                           1 + 10 +             /* space and date */
     272             :                           1 + 8 +              /* space and time */
     273             :                           (us ? 1 + 6 : 0) +   /* "." and microsecond part */
     274             :                           1 + 1 +              /* space and shortest possible zone */
     275             :                           1))
     276           0 :                 return NULL; /* Not enough space even for the shortest form. */
     277        6500 :         if (t <= 0 || t == USEC_INFINITY)
     278        3176 :                 return NULL; /* Timestamp is unset */
     279             : 
     280             :         /* Let's not format times with years > 9999 */
     281        3324 :         if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) {
     282           1 :                 assert(l >= STRLEN("--- XXXX-XX-XX XX:XX:XX") + 1);
     283           1 :                 strcpy(buf, "--- XXXX-XX-XX XX:XX:XX");
     284           1 :                 return buf;
     285             :         }
     286             : 
     287        3323 :         sec = (time_t) (t / USEC_PER_SEC); /* Round down */
     288             : 
     289        3323 :         if (!localtime_or_gmtime_r(&sec, &tm, utc))
     290           0 :                 return NULL;
     291             : 
     292             :         /* Start with the week day */
     293        3323 :         assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
     294        3323 :         memcpy(buf, weekdays[tm.tm_wday], 4);
     295             : 
     296             :         /* Add the main components */
     297        3323 :         if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0)
     298           0 :                 return NULL; /* Doesn't fit */
     299             : 
     300             :         /* Append the microseconds part, if that's requested */
     301        3323 :         if (us) {
     302         264 :                 n = strlen(buf);
     303         264 :                 if (n + 8 > l)
     304           0 :                         return NULL; /* Microseconds part doesn't fit. */
     305             : 
     306         264 :                 sprintf(buf + n, ".%06"PRI_USEC, t % USEC_PER_SEC);
     307             :         }
     308             : 
     309             :         /* Append the timezone */
     310        3323 :         n = strlen(buf);
     311        3323 :         if (utc) {
     312             :                 /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the
     313             :                  * obsolete "GMT" instead. */
     314         203 :                 if (n + 5 > l)
     315           0 :                         return NULL; /* "UTC" doesn't fit. */
     316             : 
     317         203 :                 strcpy(buf + n, " UTC");
     318             : 
     319        3120 :         } else if (!isempty(tm.tm_zone)) {
     320             :                 size_t tn;
     321             : 
     322             :                 /* An explicit timezone is specified, let's use it, if it fits */
     323        3120 :                 tn = strlen(tm.tm_zone);
     324        3120 :                 if (n + 1 + tn + 1 > l) {
     325             :                         /* The full time zone does not fit in. Yuck. */
     326             : 
     327           0 :                         if (n + 1 + _POSIX_TZNAME_MAX + 1 > l)
     328           0 :                                 return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */
     329             : 
     330             :                         /* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX
     331             :                          * minimum time zone length. In this case suppress the timezone entirely, in order not to dump
     332             :                          * an overly long, hard to read string on the user. This should be safe, because the user will
     333             :                          * assume the local timezone anyway if none is shown. And so does parse_timestamp(). */
     334             :                 } else {
     335        3120 :                         buf[n++] = ' ';
     336        3120 :                         strcpy(buf + n, tm.tm_zone);
     337             :                 }
     338             :         }
     339             : 
     340        3323 :         return buf;
     341             : }
     342             : 
     343        6130 : char *format_timestamp(char *buf, size_t l, usec_t t) {
     344        6130 :         return format_timestamp_internal(buf, l, t, false, false);
     345             : }
     346             : 
     347         106 : char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
     348         106 :         return format_timestamp_internal(buf, l, t, true, false);
     349             : }
     350             : 
     351         164 : char *format_timestamp_us(char *buf, size_t l, usec_t t) {
     352         164 :         return format_timestamp_internal(buf, l, t, false, true);
     353             : }
     354             : 
     355         100 : char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
     356         100 :         return format_timestamp_internal(buf, l, t, true, true);
     357             : }
     358             : 
     359         137 : char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
     360             :         const char *s;
     361             :         usec_t n, d;
     362             : 
     363         137 :         if (t <= 0 || t == USEC_INFINITY)
     364           0 :                 return NULL;
     365             : 
     366         137 :         n = now(CLOCK_REALTIME);
     367         137 :         if (n > t) {
     368          84 :                 d = n - t;
     369          84 :                 s = "ago";
     370             :         } else {
     371          53 :                 d = t - n;
     372          53 :                 s = "left";
     373             :         }
     374             : 
     375         137 :         if (d >= USEC_PER_YEAR)
     376         115 :                 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
     377             :                          d / USEC_PER_YEAR,
     378         115 :                          (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
     379          22 :         else if (d >= USEC_PER_MONTH)
     380           2 :                 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
     381             :                          d / USEC_PER_MONTH,
     382           2 :                          (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
     383          20 :         else if (d >= USEC_PER_WEEK)
     384           1 :                 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
     385             :                          d / USEC_PER_WEEK,
     386           1 :                          (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
     387          19 :         else if (d >= 2*USEC_PER_DAY)
     388           0 :                 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
     389          19 :         else if (d >= 25*USEC_PER_HOUR)
     390           3 :                 snprintf(buf, l, "1 day " USEC_FMT "h %s",
     391           3 :                          (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
     392          16 :         else if (d >= 6*USEC_PER_HOUR)
     393           5 :                 snprintf(buf, l, USEC_FMT "h %s",
     394             :                          d / USEC_PER_HOUR, s);
     395          11 :         else if (d >= USEC_PER_HOUR)
     396          10 :                 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
     397             :                          d / USEC_PER_HOUR,
     398          10 :                          (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
     399           1 :         else if (d >= 5*USEC_PER_MINUTE)
     400           0 :                 snprintf(buf, l, USEC_FMT "min %s",
     401             :                          d / USEC_PER_MINUTE, s);
     402           1 :         else if (d >= USEC_PER_MINUTE)
     403           0 :                 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
     404             :                          d / USEC_PER_MINUTE,
     405           0 :                          (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
     406           1 :         else if (d >= USEC_PER_SEC)
     407           0 :                 snprintf(buf, l, USEC_FMT "s %s",
     408             :                          d / USEC_PER_SEC, s);
     409           1 :         else if (d >= USEC_PER_MSEC)
     410           0 :                 snprintf(buf, l, USEC_FMT "ms %s",
     411             :                          d / USEC_PER_MSEC, s);
     412           1 :         else if (d > 0)
     413           1 :                 snprintf(buf, l, USEC_FMT"us %s",
     414             :                          d, s);
     415             :         else
     416           0 :                 snprintf(buf, l, "now");
     417             : 
     418         137 :         buf[l-1] = 0;
     419         137 :         return buf;
     420             : }
     421             : 
     422         931 : char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
     423             :         static const struct {
     424             :                 const char *suffix;
     425             :                 usec_t usec;
     426             :         } table[] = {
     427             :                 { "y",     USEC_PER_YEAR   },
     428             :                 { "month", USEC_PER_MONTH  },
     429             :                 { "w",     USEC_PER_WEEK   },
     430             :                 { "d",     USEC_PER_DAY    },
     431             :                 { "h",     USEC_PER_HOUR   },
     432             :                 { "min",   USEC_PER_MINUTE },
     433             :                 { "s",     USEC_PER_SEC    },
     434             :                 { "ms",    USEC_PER_MSEC   },
     435             :                 { "us",    1               },
     436             :         };
     437             : 
     438             :         size_t i;
     439         931 :         char *p = buf;
     440         931 :         bool something = false;
     441             : 
     442         931 :         assert(buf);
     443         931 :         assert(l > 0);
     444             : 
     445         931 :         if (t == USEC_INFINITY) {
     446         455 :                 strncpy(p, "infinity", l-1);
     447         455 :                 p[l-1] = 0;
     448         455 :                 return p;
     449             :         }
     450             : 
     451         476 :         if (t <= 0) {
     452          51 :                 strncpy(p, "0", l-1);
     453          51 :                 p[l-1] = 0;
     454          51 :                 return p;
     455             :         }
     456             : 
     457             :         /* The result of this function can be parsed with parse_sec */
     458             : 
     459        3470 :         for (i = 0; i < ELEMENTSOF(table); i++) {
     460        3461 :                 int k = 0;
     461             :                 size_t n;
     462        3461 :                 bool done = false;
     463             :                 usec_t a, b;
     464             : 
     465        3461 :                 if (t <= 0)
     466         416 :                         break;
     467             : 
     468        3045 :                 if (t < accuracy && something)
     469           0 :                         break;
     470             : 
     471        3045 :                 if (t < table[i].usec)
     472        2294 :                         continue;
     473             : 
     474         751 :                 if (l <= 1)
     475           0 :                         break;
     476             : 
     477         751 :                 a = t / table[i].usec;
     478         751 :                 b = t % table[i].usec;
     479             : 
     480             :                 /* Let's see if we should shows this in dot notation */
     481         751 :                 if (t < USEC_PER_MINUTE && b > 0) {
     482             :                         usec_t cc;
     483             :                         signed char j;
     484             : 
     485         128 :                         j = 0;
     486         827 :                         for (cc = table[i].usec; cc > 1; cc /= 10)
     487         699 :                                 j++;
     488             : 
     489         563 :                         for (cc = accuracy; cc > 1; cc /= 10) {
     490         435 :                                 b /= 10;
     491         435 :                                 j--;
     492             :                         }
     493             : 
     494         128 :                         if (j > 0) {
     495          82 :                                 k = snprintf(p, l,
     496             :                                              "%s"USEC_FMT".%0*"PRI_USEC"%s",
     497             :                                              p > buf ? " " : "",
     498             :                                              a,
     499             :                                              j,
     500             :                                              b,
     501             :                                              table[i].suffix);
     502             : 
     503          82 :                                 t = 0;
     504          82 :                                 done = true;
     505             :                         }
     506             :                 }
     507             : 
     508             :                 /* No? Then let's show it normally */
     509         751 :                 if (!done) {
     510         669 :                         k = snprintf(p, l,
     511             :                                      "%s"USEC_FMT"%s",
     512             :                                      p > buf ? " " : "",
     513             :                                      a,
     514             :                                      table[i].suffix);
     515             : 
     516         669 :                         t = b;
     517             :                 }
     518             : 
     519         751 :                 n = MIN((size_t) k, l);
     520             : 
     521         751 :                 l -= n;
     522         751 :                 p += n;
     523             : 
     524         751 :                 something = true;
     525             :         }
     526             : 
     527         425 :         *p = 0;
     528             : 
     529         425 :         return buf;
     530             : }
     531             : 
     532         513 : static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
     533             :         static const struct {
     534             :                 const char *name;
     535             :                 const int nr;
     536             :         } day_nr[] = {
     537             :                 { "Sunday",    0 },
     538             :                 { "Sun",       0 },
     539             :                 { "Monday",    1 },
     540             :                 { "Mon",       1 },
     541             :                 { "Tuesday",   2 },
     542             :                 { "Tue",       2 },
     543             :                 { "Wednesday", 3 },
     544             :                 { "Wed",       3 },
     545             :                 { "Thursday",  4 },
     546             :                 { "Thu",       4 },
     547             :                 { "Friday",    5 },
     548             :                 { "Fri",       5 },
     549             :                 { "Saturday",  6 },
     550             :                 { "Sat",       6 },
     551             :         };
     552             : 
     553         513 :         const char *k, *utc = NULL, *tzn = NULL;
     554             :         struct tm tm, copy;
     555             :         time_t x;
     556         513 :         usec_t x_usec, plus = 0, minus = 0, ret;
     557         513 :         int r, weekday = -1, dst = -1;
     558             :         size_t i;
     559             : 
     560             :         /* Allowed syntaxes:
     561             :          *
     562             :          *   2012-09-22 16:34:22
     563             :          *   2012-09-22 16:34     (seconds will be set to 0)
     564             :          *   2012-09-22           (time will be set to 00:00:00)
     565             :          *   16:34:22             (date will be set to today)
     566             :          *   16:34                (date will be set to today, seconds to 0)
     567             :          *   now
     568             :          *   yesterday            (time is set to 00:00:00)
     569             :          *   today                (time is set to 00:00:00)
     570             :          *   tomorrow             (time is set to 00:00:00)
     571             :          *   +5min
     572             :          *   -5days
     573             :          *   @2147483647          (seconds since epoch)
     574             :          */
     575             : 
     576         513 :         assert(t);
     577             : 
     578         513 :         if (t[0] == '@' && !with_tz)
     579           2 :                 return parse_sec(t + 1, usec);
     580             : 
     581         511 :         ret = now(CLOCK_REALTIME);
     582             : 
     583         511 :         if (!with_tz) {
     584         511 :                 if (streq(t, "now"))
     585           1 :                         goto finish;
     586             : 
     587         510 :                 else if (t[0] == '+') {
     588           4 :                         r = parse_sec(t+1, &plus);
     589           4 :                         if (r < 0)
     590           2 :                                 return r;
     591             : 
     592           2 :                         goto finish;
     593             : 
     594         506 :                 } else if (t[0] == '-') {
     595           1 :                         r = parse_sec(t+1, &minus);
     596           1 :                         if (r < 0)
     597           0 :                                 return r;
     598             : 
     599           1 :                         goto finish;
     600             : 
     601         505 :                 } else if ((k = endswith(t, " ago"))) {
     602          63 :                         t = strndupa(t, k - t);
     603             : 
     604          63 :                         r = parse_sec(t, &minus);
     605          63 :                         if (r < 0)
     606           0 :                                 return r;
     607             : 
     608          63 :                         goto finish;
     609             : 
     610         442 :                 } else if ((k = endswith(t, " left"))) {
     611          38 :                         t = strndupa(t, k - t);
     612             : 
     613          38 :                         r = parse_sec(t, &plus);
     614          38 :                         if (r < 0)
     615           0 :                                 return r;
     616             : 
     617          38 :                         goto finish;
     618             :                 }
     619             : 
     620             :                 /* See if the timestamp is suffixed with UTC */
     621         404 :                 utc = endswith_no_case(t, " UTC");
     622         404 :                 if (utc)
     623         228 :                         t = strndupa(t, utc - t);
     624             :                 else {
     625         176 :                         const char *e = NULL;
     626             :                         int j;
     627             : 
     628         176 :                         tzset();
     629             : 
     630             :                         /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
     631             :                          * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
     632             :                          * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
     633             :                          * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
     634             :                          * support arbitrary timezone specifications. */
     635             : 
     636         365 :                         for (j = 0; j <= 1; j++) {
     637             : 
     638         352 :                                 if (isempty(tzname[j]))
     639           0 :                                         continue;
     640             : 
     641         352 :                                 e = endswith_no_case(t, tzname[j]);
     642         352 :                                 if (!e)
     643         189 :                                         continue;
     644         163 :                                 if (e == t)
     645           0 :                                         continue;
     646         163 :                                 if (e[-1] != ' ')
     647           0 :                                         continue;
     648             : 
     649         163 :                                 break;
     650             :                         }
     651             : 
     652         176 :                         if (IN_SET(j, 0, 1)) {
     653             :                                 /* Found one of the two timezones specified. */
     654         163 :                                 t = strndupa(t, e - t - 1);
     655         163 :                                 dst = j;
     656         163 :                                 tzn = tzname[j];
     657             :                         }
     658             :                 }
     659             :         }
     660             : 
     661         404 :         x = (time_t) (ret / USEC_PER_SEC);
     662         404 :         x_usec = 0;
     663             : 
     664         404 :         if (!localtime_or_gmtime_r(&x, &tm, utc))
     665           0 :                 return -EINVAL;
     666             : 
     667         404 :         tm.tm_isdst = dst;
     668         404 :         if (!with_tz && tzn)
     669         163 :                 tm.tm_zone = tzn;
     670             : 
     671         404 :         if (streq(t, "today")) {
     672           2 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     673           2 :                 goto from_tm;
     674             : 
     675         402 :         } else if (streq(t, "yesterday")) {
     676           2 :                 tm.tm_mday--;
     677           2 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     678           2 :                 goto from_tm;
     679             : 
     680         400 :         } else if (streq(t, "tomorrow")) {
     681           2 :                 tm.tm_mday++;
     682           2 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     683           2 :                 goto from_tm;
     684             :         }
     685             : 
     686        3141 :         for (i = 0; i < ELEMENTSOF(day_nr); i++) {
     687             :                 size_t skip;
     688             : 
     689        3108 :                 if (!startswith_no_case(t, day_nr[i].name))
     690        2743 :                         continue;
     691             : 
     692         365 :                 skip = strlen(day_nr[i].name);
     693         365 :                 if (t[skip] != ' ')
     694           0 :                         continue;
     695             : 
     696         365 :                 weekday = day_nr[i].nr;
     697         365 :                 t += skip + 1;
     698         365 :                 break;
     699             :         }
     700             : 
     701         398 :         copy = tm;
     702         398 :         k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
     703         398 :         if (k) {
     704           4 :                 if (*k == '.')
     705           0 :                         goto parse_usec;
     706           4 :                 else if (*k == 0)
     707           4 :                         goto from_tm;
     708             :         }
     709             : 
     710         394 :         tm = copy;
     711         394 :         k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
     712         394 :         if (k) {
     713         367 :                 if (*k == '.')
     714         197 :                         goto parse_usec;
     715         170 :                 else if (*k == 0)
     716         170 :                         goto from_tm;
     717             :         }
     718             : 
     719          27 :         tm = copy;
     720          27 :         k = strptime(t, "%y-%m-%d %H:%M", &tm);
     721          27 :         if (k && *k == 0) {
     722           2 :                 tm.tm_sec = 0;
     723           2 :                 goto from_tm;
     724             :         }
     725             : 
     726          25 :         tm = copy;
     727          25 :         k = strptime(t, "%Y-%m-%d %H:%M", &tm);
     728          25 :         if (k && *k == 0) {
     729           2 :                 tm.tm_sec = 0;
     730           2 :                 goto from_tm;
     731             :         }
     732             : 
     733          23 :         tm = copy;
     734          23 :         k = strptime(t, "%y-%m-%d", &tm);
     735          23 :         if (k && *k == 0) {
     736           0 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     737           0 :                 goto from_tm;
     738             :         }
     739             : 
     740          23 :         tm = copy;
     741          23 :         k = strptime(t, "%Y-%m-%d", &tm);
     742          23 :         if (k && *k == 0) {
     743           6 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     744           6 :                 goto from_tm;
     745             :         }
     746             : 
     747          17 :         tm = copy;
     748          17 :         k = strptime(t, "%H:%M:%S", &tm);
     749          17 :         if (k) {
     750           6 :                 if (*k == '.')
     751           4 :                         goto parse_usec;
     752           2 :                 else if (*k == 0)
     753           2 :                         goto from_tm;
     754             :         }
     755             : 
     756          11 :         tm = copy;
     757          11 :         k = strptime(t, "%H:%M", &tm);
     758          11 :         if (k && *k == 0) {
     759           3 :                 tm.tm_sec = 0;
     760           3 :                 goto from_tm;
     761             :         }
     762             : 
     763           8 :         return -EINVAL;
     764             : 
     765         201 : parse_usec:
     766             :         {
     767             :                 unsigned add;
     768             : 
     769         201 :                 k++;
     770         201 :                 r = parse_fractional_part_u(&k, 6, &add);
     771         201 :                 if (r < 0)
     772           0 :                         return -EINVAL;
     773             : 
     774         201 :                 if (*k)
     775           0 :                         return -EINVAL;
     776             : 
     777         201 :                 x_usec = add;
     778             :         }
     779             : 
     780         396 : from_tm:
     781         396 :         if (weekday >= 0 && tm.tm_wday != weekday)
     782           0 :                 return -EINVAL;
     783             : 
     784         396 :         x = mktime_or_timegm(&tm, utc);
     785         396 :         if (x < 0)
     786           1 :                 return -EINVAL;
     787             : 
     788         395 :         ret = (usec_t) x * USEC_PER_SEC + x_usec;
     789         395 :         if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
     790           1 :                 return -EINVAL;
     791             : 
     792         394 : finish:
     793         499 :         if (ret + plus < ret) /* overflow? */
     794           0 :                 return -EINVAL;
     795         499 :         ret += plus;
     796         499 :         if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
     797           0 :                 return -EINVAL;
     798             : 
     799         499 :         if (ret >= minus)
     800         498 :                 ret -= minus;
     801             :         else
     802           1 :                 return -EINVAL;
     803             : 
     804         498 :         if (usec)
     805         498 :                 *usec = ret;
     806         498 :         return 0;
     807             : }
     808             : 
     809             : typedef struct ParseTimestampResult {
     810             :         usec_t usec;
     811             :         int return_value;
     812             : } ParseTimestampResult;
     813             : 
     814         594 : int parse_timestamp(const char *t, usec_t *usec) {
     815         594 :         char *last_space, *tz = NULL;
     816             :         ParseTimestampResult *shared, tmp;
     817             :         int r;
     818             : 
     819         594 :         last_space = strrchr(t, ' ');
     820         594 :         if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG))
     821         312 :                 tz = last_space + 1;
     822             : 
     823         594 :         if (!tz || endswith_no_case(t, " UTC"))
     824         513 :                 return parse_timestamp_impl(t, usec, false);
     825             : 
     826          81 :         shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
     827          81 :         if (shared == MAP_FAILED)
     828           0 :                 return negative_errno();
     829             : 
     830          81 :         r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
     831          81 :         if (r < 0) {
     832           0 :                 (void) munmap(shared, sizeof *shared);
     833           0 :                 return r;
     834             :         }
     835          81 :         if (r == 0) {
     836           0 :                 bool with_tz = true;
     837             : 
     838           0 :                 if (setenv("TZ", tz, 1) != 0) {
     839           0 :                         shared->return_value = negative_errno();
     840           0 :                         _exit(EXIT_FAILURE);
     841             :                 }
     842             : 
     843           0 :                 tzset();
     844             : 
     845             :                 /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
     846             :                  * Otherwise just cut it off. */
     847           0 :                 with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
     848             : 
     849             :                 /* Cut off the timezone if we don't need it. */
     850           0 :                 if (with_tz)
     851           0 :                         t = strndupa(t, last_space - t);
     852             : 
     853           0 :                 shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
     854             : 
     855           0 :                 _exit(EXIT_SUCCESS);
     856             :         }
     857             : 
     858          81 :         tmp = *shared;
     859          81 :         if (munmap(shared, sizeof *shared) != 0)
     860           0 :                 return negative_errno();
     861             : 
     862          81 :         if (tmp.return_value == 0 && usec)
     863          78 :                 *usec = tmp.usec;
     864             : 
     865          81 :         return tmp.return_value;
     866             : }
     867             : 
     868         365 : static const char* extract_multiplier(const char *p, usec_t *multiplier) {
     869             :         static const struct {
     870             :                 const char *suffix;
     871             :                 usec_t usec;
     872             :         } table[] = {
     873             :                 { "seconds", USEC_PER_SEC    },
     874             :                 { "second",  USEC_PER_SEC    },
     875             :                 { "sec",     USEC_PER_SEC    },
     876             :                 { "s",       USEC_PER_SEC    },
     877             :                 { "minutes", USEC_PER_MINUTE },
     878             :                 { "minute",  USEC_PER_MINUTE },
     879             :                 { "min",     USEC_PER_MINUTE },
     880             :                 { "months",  USEC_PER_MONTH  },
     881             :                 { "month",   USEC_PER_MONTH  },
     882             :                 { "M",       USEC_PER_MONTH  },
     883             :                 { "msec",    USEC_PER_MSEC   },
     884             :                 { "ms",      USEC_PER_MSEC   },
     885             :                 { "m",       USEC_PER_MINUTE },
     886             :                 { "hours",   USEC_PER_HOUR   },
     887             :                 { "hour",    USEC_PER_HOUR   },
     888             :                 { "hr",      USEC_PER_HOUR   },
     889             :                 { "h",       USEC_PER_HOUR   },
     890             :                 { "days",    USEC_PER_DAY    },
     891             :                 { "day",     USEC_PER_DAY    },
     892             :                 { "d",       USEC_PER_DAY    },
     893             :                 { "weeks",   USEC_PER_WEEK   },
     894             :                 { "week",    USEC_PER_WEEK   },
     895             :                 { "w",       USEC_PER_WEEK   },
     896             :                 { "years",   USEC_PER_YEAR   },
     897             :                 { "year",    USEC_PER_YEAR   },
     898             :                 { "y",       USEC_PER_YEAR   },
     899             :                 { "usec",    1ULL            },
     900             :                 { "us",      1ULL            },
     901             :                 { "µs",      1ULL            },
     902             :         };
     903             :         size_t i;
     904             : 
     905        5712 :         for (i = 0; i < ELEMENTSOF(table); i++) {
     906             :                 char *e;
     907             : 
     908        5676 :                 e = startswith(p, table[i].suffix);
     909        5676 :                 if (e) {
     910         329 :                         *multiplier = table[i].usec;
     911         329 :                         return e;
     912             :                 }
     913             :         }
     914             : 
     915          36 :         return p;
     916             : }
     917             : 
     918         252 : int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
     919             :         const char *p, *s;
     920         252 :         usec_t r = 0;
     921         252 :         bool something = false;
     922             : 
     923         252 :         assert(t);
     924         252 :         assert(default_unit > 0);
     925             : 
     926         252 :         p = t;
     927             : 
     928         252 :         p += strspn(p, WHITESPACE);
     929         252 :         s = startswith(p, "infinity");
     930         252 :         if (s) {
     931           6 :                 s += strspn(s, WHITESPACE);
     932           6 :                 if (*s != 0)
     933           1 :                         return -EINVAL;
     934             : 
     935           5 :                 if (usec)
     936           5 :                         *usec = USEC_INFINITY;
     937           5 :                 return 0;
     938             :         }
     939             : 
     940         351 :         for (;;) {
     941         597 :                 usec_t multiplier = default_unit, k;
     942             :                 long long l;
     943             :                 char *e;
     944             : 
     945         597 :                 p += strspn(p, WHITESPACE);
     946             : 
     947         597 :                 if (*p == 0) {
     948         220 :                         if (!something)
     949          27 :                                 return -EINVAL;
     950             : 
     951         219 :                         break;
     952             :                 }
     953             : 
     954         377 :                 if (*p == '-') /* Don't allow "-0" */
     955           6 :                         return -ERANGE;
     956             : 
     957         371 :                 errno = 0;
     958         371 :                 l = strtoll(p, &e, 10);
     959         371 :                 if (errno > 0)
     960           0 :                         return -errno;
     961         371 :                 if (l < 0)
     962           0 :                         return -ERANGE;
     963             : 
     964         371 :                 if (*e == '.') {
     965          54 :                         p = e + 1;
     966          54 :                         p += strspn(p, DIGITS);
     967         317 :                 } else if (e == p)
     968           6 :                         return -EINVAL;
     969             :                 else
     970         311 :                         p = e;
     971             : 
     972         365 :                 s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
     973         365 :                 if (s == p && *s != '\0')
     974             :                         /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
     975           8 :                         return -EINVAL;
     976             : 
     977         357 :                 p = s;
     978             : 
     979         357 :                 if ((usec_t) l >= USEC_INFINITY / multiplier)
     980           1 :                         return -ERANGE;
     981             : 
     982         356 :                 k = (usec_t) l * multiplier;
     983         356 :                 if (k >= USEC_INFINITY - r)
     984           0 :                         return -ERANGE;
     985             : 
     986         356 :                 r += k;
     987             : 
     988         356 :                 something = true;
     989             : 
     990         356 :                 if (*e == '.') {
     991          47 :                         usec_t m = multiplier / 10;
     992             :                         const char *b;
     993             : 
     994         181 :                         for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
     995         134 :                                 k = (usec_t) (*b - '0') * m;
     996         134 :                                 if (k >= USEC_INFINITY - r)
     997           0 :                                         return -ERANGE;
     998             : 
     999         134 :                                 r += k;
    1000             :                         }
    1001             : 
    1002             :                         /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
    1003          47 :                         if (b == e + 1)
    1004           5 :                                 return -EINVAL;
    1005             :                 }
    1006             :         }
    1007             : 
    1008         219 :         if (usec)
    1009         219 :                 *usec = r;
    1010         219 :         return 0;
    1011             : }
    1012             : 
    1013         237 : int parse_sec(const char *t, usec_t *usec) {
    1014         237 :         return parse_time(t, usec, USEC_PER_SEC);
    1015             : }
    1016             : 
    1017           4 : int parse_sec_fix_0(const char *t, usec_t *ret) {
    1018             :         usec_t k;
    1019             :         int r;
    1020             : 
    1021           4 :         assert(t);
    1022           4 :         assert(ret);
    1023             : 
    1024           4 :         r = parse_sec(t, &k);
    1025           4 :         if (r < 0)
    1026           0 :                 return r;
    1027             : 
    1028           4 :         *ret = k == 0 ? USEC_INFINITY : k;
    1029           4 :         return r;
    1030             : }
    1031             : 
    1032           7 : int parse_sec_def_infinity(const char *t, usec_t *ret) {
    1033           7 :         t += strspn(t, WHITESPACE);
    1034           7 :         if (isempty(t)) {
    1035           2 :                 *ret = USEC_INFINITY;
    1036           2 :                 return 0;
    1037             :         }
    1038           5 :         return parse_sec(t, ret);
    1039             : }
    1040             : 
    1041          43 : static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
    1042             :         static const struct {
    1043             :                 const char *suffix;
    1044             :                 nsec_t nsec;
    1045             :         } table[] = {
    1046             :                 { "seconds", NSEC_PER_SEC    },
    1047             :                 { "second",  NSEC_PER_SEC    },
    1048             :                 { "sec",     NSEC_PER_SEC    },
    1049             :                 { "s",       NSEC_PER_SEC    },
    1050             :                 { "minutes", NSEC_PER_MINUTE },
    1051             :                 { "minute",  NSEC_PER_MINUTE },
    1052             :                 { "min",     NSEC_PER_MINUTE },
    1053             :                 { "months",  NSEC_PER_MONTH  },
    1054             :                 { "month",   NSEC_PER_MONTH  },
    1055             :                 { "M",       NSEC_PER_MONTH  },
    1056             :                 { "msec",    NSEC_PER_MSEC   },
    1057             :                 { "ms",      NSEC_PER_MSEC   },
    1058             :                 { "m",       NSEC_PER_MINUTE },
    1059             :                 { "hours",   NSEC_PER_HOUR   },
    1060             :                 { "hour",    NSEC_PER_HOUR   },
    1061             :                 { "hr",      NSEC_PER_HOUR   },
    1062             :                 { "h",       NSEC_PER_HOUR   },
    1063             :                 { "days",    NSEC_PER_DAY    },
    1064             :                 { "day",     NSEC_PER_DAY    },
    1065             :                 { "d",       NSEC_PER_DAY    },
    1066             :                 { "weeks",   NSEC_PER_WEEK   },
    1067             :                 { "week",    NSEC_PER_WEEK   },
    1068             :                 { "w",       NSEC_PER_WEEK   },
    1069             :                 { "years",   NSEC_PER_YEAR   },
    1070             :                 { "year",    NSEC_PER_YEAR   },
    1071             :                 { "y",       NSEC_PER_YEAR   },
    1072             :                 { "usec",    NSEC_PER_USEC   },
    1073             :                 { "us",      NSEC_PER_USEC   },
    1074             :                 { "µs",      NSEC_PER_USEC   },
    1075             :                 { "nsec",    1ULL            },
    1076             :                 { "ns",      1ULL            },
    1077             :                 { "",        1ULL            }, /* default is nsec */
    1078             :         };
    1079             :         size_t i;
    1080             : 
    1081         773 :         for (i = 0; i < ELEMENTSOF(table); i++) {
    1082             :                 char *e;
    1083             : 
    1084         773 :                 e = startswith(p, table[i].suffix);
    1085         773 :                 if (e) {
    1086          43 :                         *multiplier = table[i].nsec;
    1087          43 :                         return e;
    1088             :                 }
    1089             :         }
    1090             : 
    1091           0 :         return p;
    1092             : }
    1093             : 
    1094          47 : int parse_nsec(const char *t, nsec_t *nsec) {
    1095             :         const char *p, *s;
    1096          47 :         nsec_t r = 0;
    1097          47 :         bool something = false;
    1098             : 
    1099          47 :         assert(t);
    1100          47 :         assert(nsec);
    1101             : 
    1102          47 :         p = t;
    1103             : 
    1104          47 :         p += strspn(p, WHITESPACE);
    1105          47 :         s = startswith(p, "infinity");
    1106          47 :         if (s) {
    1107           4 :                 s += strspn(s, WHITESPACE);
    1108           4 :                 if (*s != 0)
    1109           2 :                         return -EINVAL;
    1110             : 
    1111           2 :                 *nsec = NSEC_INFINITY;
    1112           2 :                 return 0;
    1113             :         }
    1114             : 
    1115          29 :         for (;;) {
    1116          72 :                 nsec_t multiplier = 1, k;
    1117             :                 long long l;
    1118             :                 char *e;
    1119             : 
    1120          72 :                 p += strspn(p, WHITESPACE);
    1121             : 
    1122          72 :                 if (*p == 0) {
    1123          20 :                         if (!something)
    1124          24 :                                 return -EINVAL;
    1125             : 
    1126          19 :                         break;
    1127             :                 }
    1128             : 
    1129          52 :                 if (*p == '-') /* Don't allow "-0" */
    1130           5 :                         return -ERANGE;
    1131             : 
    1132          47 :                 errno = 0;
    1133          47 :                 l = strtoll(p, &e, 10);
    1134          47 :                 if (errno > 0)
    1135           0 :                         return -errno;
    1136          47 :                 if (l < 0)
    1137           0 :                         return -ERANGE;
    1138             : 
    1139          47 :                 if (*e == '.') {
    1140          31 :                         p = e + 1;
    1141          31 :                         p += strspn(p, DIGITS);
    1142          16 :                 } else if (e == p)
    1143           4 :                         return -EINVAL;
    1144             :                 else
    1145          12 :                         p = e;
    1146             : 
    1147          43 :                 s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
    1148          43 :                 if (s == p && *s != '\0')
    1149             :                         /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
    1150           8 :                         return -EINVAL;
    1151             : 
    1152          35 :                 p = s;
    1153             : 
    1154          35 :                 if ((nsec_t) l >= NSEC_INFINITY / multiplier)
    1155           1 :                         return -ERANGE;
    1156             : 
    1157          34 :                 k = (nsec_t) l * multiplier;
    1158          34 :                 if (k >= NSEC_INFINITY - r)
    1159           0 :                         return -ERANGE;
    1160             : 
    1161          34 :                 r += k;
    1162             : 
    1163          34 :                 something = true;
    1164             : 
    1165          34 :                 if (*e == '.') {
    1166          24 :                         nsec_t m = multiplier / 10;
    1167             :                         const char *b;
    1168             : 
    1169          56 :                         for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
    1170          32 :                                 k = (nsec_t) (*b - '0') * m;
    1171          32 :                                 if (k >= NSEC_INFINITY - r)
    1172           0 :                                         return -ERANGE;
    1173             : 
    1174          32 :                                 r += k;
    1175             :                         }
    1176             : 
    1177             :                         /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
    1178          24 :                         if (b == e + 1)
    1179           5 :                                 return -EINVAL;
    1180             :                 }
    1181             :         }
    1182             : 
    1183          19 :         *nsec = r;
    1184             : 
    1185          19 :         return 0;
    1186             : }
    1187             : 
    1188           0 : bool ntp_synced(void) {
    1189           0 :         struct timex txc = {};
    1190             : 
    1191           0 :         if (adjtimex(&txc) < 0)
    1192           0 :                 return false;
    1193             : 
    1194             :         /* Consider the system clock synchronized if the reported maximum error is smaller than the maximum
    1195             :          * value (16 seconds). Ignore the STA_UNSYNC flag as it may have been set to prevent the kernel from
    1196             :          * touching the RTC. */
    1197           0 :         if (txc.maxerror >= 16000000)
    1198           0 :                 return false;
    1199             : 
    1200           0 :         return true;
    1201             : }
    1202             : 
    1203           1 : int get_timezones(char ***ret) {
    1204           1 :         _cleanup_fclose_ FILE *f = NULL;
    1205           1 :         _cleanup_strv_free_ char **zones = NULL;
    1206           1 :         size_t n_zones = 0, n_allocated = 0;
    1207             :         int r;
    1208             : 
    1209           1 :         assert(ret);
    1210             : 
    1211           1 :         zones = strv_new("UTC");
    1212           1 :         if (!zones)
    1213           0 :                 return -ENOMEM;
    1214             : 
    1215           1 :         n_allocated = 2;
    1216           1 :         n_zones = 1;
    1217             : 
    1218           1 :         f = fopen("/usr/share/zoneinfo/zone1970.tab", "re");
    1219           1 :         if (f) {
    1220         383 :                 for (;;) {
    1221         384 :                         _cleanup_free_ char *line = NULL;
    1222             :                         char *p, *w;
    1223             :                         size_t k;
    1224             : 
    1225         384 :                         r = read_line(f, LONG_LINE_MAX, &line);
    1226         384 :                         if (r < 0)
    1227           0 :                                 return r;
    1228         384 :                         if (r == 0)
    1229           1 :                                 break;
    1230             : 
    1231         383 :                         p = strstrip(line);
    1232             : 
    1233         383 :                         if (isempty(p) || *p == '#')
    1234          35 :                                 continue;
    1235             : 
    1236             :                         /* Skip over country code */
    1237         348 :                         p += strcspn(p, WHITESPACE);
    1238         348 :                         p += strspn(p, WHITESPACE);
    1239             : 
    1240             :                         /* Skip over coordinates */
    1241         348 :                         p += strcspn(p, WHITESPACE);
    1242         348 :                         p += strspn(p, WHITESPACE);
    1243             : 
    1244             :                         /* Found timezone name */
    1245         348 :                         k = strcspn(p, WHITESPACE);
    1246         348 :                         if (k <= 0)
    1247           0 :                                 continue;
    1248             : 
    1249         348 :                         w = strndup(p, k);
    1250         348 :                         if (!w)
    1251           0 :                                 return -ENOMEM;
    1252             : 
    1253         348 :                         if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
    1254           0 :                                 free(w);
    1255           0 :                                 return -ENOMEM;
    1256             :                         }
    1257             : 
    1258         348 :                         zones[n_zones++] = w;
    1259         348 :                         zones[n_zones] = NULL;
    1260             :                 }
    1261             : 
    1262           1 :                 strv_sort(zones);
    1263             : 
    1264           0 :         } else if (errno != ENOENT)
    1265           0 :                 return -errno;
    1266             : 
    1267           1 :         *ret = TAKE_PTR(zones);
    1268             : 
    1269           1 :         return 0;
    1270             : }
    1271             : 
    1272        1033 : bool timezone_is_valid(const char *name, int log_level) {
    1273        1033 :         bool slash = false;
    1274             :         const char *p, *t;
    1275        1033 :         _cleanup_close_ int fd = -1;
    1276             :         char buf[4];
    1277             :         int r;
    1278             : 
    1279        1033 :         if (isempty(name))
    1280           2 :                 return false;
    1281             : 
    1282        1031 :         if (name[0] == '/')
    1283           0 :                 return false;
    1284             : 
    1285        8804 :         for (p = name; *p; p++) {
    1286        7863 :                 if (!(*p >= '0' && *p <= '9') &&
    1287        7709 :                     !(*p >= 'a' && *p <= 'z') &&
    1288        2927 :                     !(*p >= 'A' && *p <= 'Z') &&
    1289         539 :                     !IN_SET(*p, '-', '_', '+', '/'))
    1290          90 :                         return false;
    1291             : 
    1292        7773 :                 if (*p == '/') {
    1293             : 
    1294         393 :                         if (slash)
    1295           0 :                                 return false;
    1296             : 
    1297         393 :                         slash = true;
    1298             :                 } else
    1299        7380 :                         slash = false;
    1300             :         }
    1301             : 
    1302         941 :         if (slash)
    1303           0 :                 return false;
    1304             : 
    1305         941 :         if (p - name >= PATH_MAX)
    1306           0 :                 return false;
    1307             : 
    1308        4705 :         t = strjoina("/usr/share/zoneinfo/", name);
    1309             : 
    1310         941 :         fd = open(t, O_RDONLY|O_CLOEXEC);
    1311         941 :         if (fd < 0) {
    1312         267 :                 log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
    1313         267 :                 return false;
    1314             :         }
    1315             : 
    1316         674 :         r = fd_verify_regular(fd);
    1317         674 :         if (r < 0) {
    1318           0 :                 log_full_errno(log_level, r, "Timezone file '%s' is not  a regular file: %m", t);
    1319           0 :                 return false;
    1320             :         }
    1321             : 
    1322         674 :         r = loop_read_exact(fd, buf, 4, false);
    1323         674 :         if (r < 0) {
    1324           0 :                 log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t);
    1325           0 :                 return false;
    1326             :         }
    1327             : 
    1328             :         /* Magic from tzfile(5) */
    1329         674 :         if (memcmp(buf, "TZif", 4) != 0) {
    1330           0 :                 log_full(log_level, "Timezone file '%s' has wrong magic bytes", t);
    1331           0 :                 return false;
    1332             :         }
    1333             : 
    1334         674 :         return true;
    1335             : }
    1336             : 
    1337       52232 : bool clock_boottime_supported(void) {
    1338             :         static int supported = -1;
    1339             : 
    1340             :         /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
    1341             : 
    1342       52232 :         if (supported < 0) {
    1343             :                 int fd;
    1344             : 
    1345          15 :                 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
    1346          15 :                 if (fd < 0)
    1347           0 :                         supported = false;
    1348             :                 else {
    1349          15 :                         safe_close(fd);
    1350          15 :                         supported = true;
    1351             :                 }
    1352             :         }
    1353             : 
    1354       52232 :         return supported;
    1355             : }
    1356             : 
    1357         427 : clockid_t clock_boottime_or_monotonic(void) {
    1358         427 :         if (clock_boottime_supported())
    1359         427 :                 return CLOCK_BOOTTIME;
    1360             :         else
    1361           0 :                 return CLOCK_MONOTONIC;
    1362             : }
    1363             : 
    1364         525 : bool clock_supported(clockid_t clock) {
    1365             :         struct timespec ts;
    1366             : 
    1367         525 :         switch (clock) {
    1368             : 
    1369         505 :         case CLOCK_MONOTONIC:
    1370             :         case CLOCK_REALTIME:
    1371         505 :                 return true;
    1372             : 
    1373          19 :         case CLOCK_BOOTTIME:
    1374          19 :                 return clock_boottime_supported();
    1375             : 
    1376           1 :         case CLOCK_BOOTTIME_ALARM:
    1377           1 :                 if (!clock_boottime_supported())
    1378           0 :                         return false;
    1379             : 
    1380             :                 _fallthrough_;
    1381             :         default:
    1382             :                 /* For everything else, check properly */
    1383           1 :                 return clock_gettime(clock, &ts) >= 0;
    1384             :         }
    1385             : }
    1386             : 
    1387           0 : int get_timezone(char **tz) {
    1388           0 :         _cleanup_free_ char *t = NULL;
    1389             :         const char *e;
    1390             :         char *z;
    1391             :         int r;
    1392             : 
    1393           0 :         r = readlink_malloc("/etc/localtime", &t);
    1394           0 :         if (r < 0)
    1395           0 :                 return r; /* returns EINVAL if not a symlink */
    1396             : 
    1397           0 :         e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
    1398           0 :         if (!e)
    1399           0 :                 return -EINVAL;
    1400             : 
    1401           0 :         if (!timezone_is_valid(e, LOG_DEBUG))
    1402           0 :                 return -EINVAL;
    1403             : 
    1404           0 :         z = strdup(e);
    1405           0 :         if (!z)
    1406           0 :                 return -ENOMEM;
    1407             : 
    1408           0 :         *tz = z;
    1409           0 :         return 0;
    1410             : }
    1411             : 
    1412        2856 : time_t mktime_or_timegm(struct tm *tm, bool utc) {
    1413        2856 :         return utc ? timegm(tm) : mktime(tm);
    1414             : }
    1415             : 
    1416        3810 : struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
    1417        3810 :         return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
    1418             : }
    1419             : 
    1420           0 : static uint32_t sysconf_clock_ticks_cached(void) {
    1421             :         static thread_local uint32_t hz = 0;
    1422             :         long r;
    1423             : 
    1424           0 :         if (hz == 0) {
    1425           0 :                 r = sysconf(_SC_CLK_TCK);
    1426             : 
    1427           0 :                 assert(r > 0);
    1428           0 :                 hz = r;
    1429             :         }
    1430             : 
    1431           0 :         return hz;
    1432             : }
    1433             : 
    1434           0 : uint32_t usec_to_jiffies(usec_t u) {
    1435           0 :         uint32_t hz = sysconf_clock_ticks_cached();
    1436           0 :         return DIV_ROUND_UP(u, USEC_PER_SEC / hz);
    1437             : }
    1438             : 
    1439           0 : usec_t jiffies_to_usec(uint32_t j) {
    1440           0 :         uint32_t hz = sysconf_clock_ticks_cached();
    1441           0 :         return DIV_ROUND_UP(j * USEC_PER_SEC, hz);
    1442             : }
    1443             : 
    1444          12 : usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
    1445             :         usec_t a, b;
    1446             : 
    1447          12 :         if (x == USEC_INFINITY)
    1448           1 :                 return USEC_INFINITY;
    1449          11 :         if (map_clock_id(from) == map_clock_id(to))
    1450           3 :                 return x;
    1451             : 
    1452           8 :         a = now(from);
    1453           8 :         b = now(to);
    1454             : 
    1455           8 :         if (x > a)
    1456             :                 /* x lies in the future */
    1457           6 :                 return usec_add(b, usec_sub_unsigned(x, a));
    1458             :         else
    1459             :                 /* x lies in the past */
    1460           2 :                 return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
    1461             : }
    1462             : 
    1463           2 : bool in_utc_timezone(void) {
    1464           2 :         tzset();
    1465             : 
    1466           2 :         return timezone == 0 && daylight == 0;
    1467             : }
    1468             : 
    1469           0 : int time_change_fd(void) {
    1470             : 
    1471             :         /* We only care for the cancellation event, hence we set the timeout to the latest possible value. */
    1472             :         static const struct itimerspec its = {
    1473             :                 .it_value.tv_sec = TIME_T_MAX,
    1474             :         };
    1475             : 
    1476           0 :         _cleanup_close_ int fd;
    1477             : 
    1478             :         assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
    1479             : 
    1480             :         /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever CLOCK_REALTIME makes a jump relative to
    1481             :          * CLOCK_MONOTONIC. */
    1482             : 
    1483           0 :         fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
    1484           0 :         if (fd < 0)
    1485           0 :                 return -errno;
    1486             : 
    1487           0 :         if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0)
    1488           0 :                 return -errno;
    1489             : 
    1490           0 :         return TAKE_FD(fd);
    1491             : }

Generated by: LCOV version 1.14