LCOV - code coverage report
Current view: top level - basic - time-util.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 559 738 75.7 %
Date: 2019-08-23 13:36:53 Functions: 34 46 73.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 362 543 66.7 %

           Branch data     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                 :    1034357 : 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      [ +  +  + ]:    1034357 :         switch (c) {
      40                 :            : 
      41                 :          4 :         case CLOCK_BOOTTIME_ALARM:
      42                 :          4 :                 return CLOCK_BOOTTIME;
      43                 :            : 
      44                 :         32 :         case CLOCK_REALTIME_ALARM:
      45                 :         32 :                 return CLOCK_REALTIME;
      46                 :            : 
      47                 :    1034321 :         default:
      48                 :    1034321 :                 return c;
      49                 :            :         }
      50                 :            : }
      51                 :            : 
      52                 :    1034269 : usec_t now(clockid_t clock_id) {
      53                 :            :         struct timespec ts;
      54                 :            : 
      55         [ -  + ]:    1034269 :         assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
      56                 :            : 
      57                 :    1034269 :         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                 :      32488 : dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
      69         [ -  + ]:      32488 :         assert(ts);
      70                 :            : 
      71                 :      32488 :         ts->realtime = now(CLOCK_REALTIME);
      72                 :      32488 :         ts->monotonic = now(CLOCK_MONOTONIC);
      73                 :            : 
      74                 :      32488 :         return ts;
      75                 :            : }
      76                 :            : 
      77                 :     206290 : triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
      78         [ -  + ]:     206290 :         assert(ts);
      79                 :            : 
      80                 :     206290 :         ts->realtime = now(CLOCK_REALTIME);
      81                 :     206290 :         ts->monotonic = now(CLOCK_MONOTONIC);
      82         [ +  - ]:     206290 :         ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY;
      83                 :            : 
      84                 :     206290 :         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                 :          4 : dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
     123                 :            :         int64_t delta;
     124         [ -  + ]:          4 :         assert(ts);
     125                 :            : 
     126         [ -  + ]:          4 :         if (u == USEC_INFINITY) {
     127                 :          0 :                 ts->realtime = ts->monotonic = USEC_INFINITY;
     128                 :          0 :                 return ts;
     129                 :            :         }
     130                 :            : 
     131                 :          4 :         ts->monotonic = u;
     132                 :          4 :         delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
     133                 :          4 :         ts->realtime = usec_sub_signed(now(CLOCK_REALTIME), delta);
     134                 :            : 
     135                 :          4 :         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                 :        244 : usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) {
     155                 :            : 
     156   [ +  +  +  - ]:        244 :         switch (clock) {
     157                 :            : 
     158                 :         28 :         case CLOCK_REALTIME:
     159                 :            :         case CLOCK_REALTIME_ALARM:
     160                 :         28 :                 return ts->realtime;
     161                 :            : 
     162                 :         28 :         case CLOCK_MONOTONIC:
     163                 :         28 :                 return ts->monotonic;
     164                 :            : 
     165                 :        188 :         case CLOCK_BOOTTIME:
     166                 :            :         case CLOCK_BOOTTIME_ALARM:
     167                 :        188 :                 return ts->boottime;
     168                 :            : 
     169                 :          0 :         default:
     170                 :          0 :                 return USEC_INFINITY;
     171                 :            :         }
     172                 :            : }
     173                 :            : 
     174                 :    1043697 : usec_t timespec_load(const struct timespec *ts) {
     175         [ -  + ]:    1043697 :         assert(ts);
     176                 :            : 
     177   [ +  -  -  + ]:    1043697 :         if (ts->tv_sec < 0 || ts->tv_nsec < 0)
     178                 :          0 :                 return USEC_INFINITY;
     179                 :            : 
     180         [ -  + ]:    1043697 :         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                 :    2087394 :                 (usec_t) ts->tv_sec * USEC_PER_SEC +
     185                 :    1043697 :                 (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                 :        532 : struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
     201         [ -  + ]:        532 :         assert(ts);
     202                 :            : 
     203         [ -  + ]:        532 :         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                 :        532 :         ts->tv_sec = (time_t) (u / USEC_PER_SEC);
     211                 :        532 :         ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
     212                 :            : 
     213                 :        532 :         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                 :        571 : struct timeval *timeval_store(struct timeval *tv, usec_t u) {
     231         [ -  + ]:        571 :         assert(tv);
     232                 :            : 
     233         [ -  + ]:        571 :         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                 :        571 :                 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
     239                 :        571 :                 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
     240                 :            :         }
     241                 :            : 
     242                 :        571 :         return tv;
     243                 :            : }
     244                 :            : 
     245                 :      26240 : 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         [ -  + ]:      26240 :         assert(buf);
     269                 :            : 
     270   [ +  +  -  + ]:      26240 :         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   [ +  +  +  + ]:      26240 :         if (t <= 0 || t == USEC_INFINITY)
     278                 :      12800 :                 return NULL; /* Timestamp is unset */
     279                 :            : 
     280                 :            :         /* Let's not format times with years > 9999 */
     281         [ +  + ]:      13440 :         if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) {
     282         [ -  + ]:          4 :                 assert(l >= STRLEN("--- XXXX-XX-XX XX:XX:XX") + 1);
     283                 :          4 :                 strcpy(buf, "--- XXXX-XX-XX XX:XX:XX");
     284                 :          4 :                 return buf;
     285                 :            :         }
     286                 :            : 
     287                 :      13436 :         sec = (time_t) (t / USEC_PER_SEC); /* Round down */
     288                 :            : 
     289         [ -  + ]:      13436 :         if (!localtime_or_gmtime_r(&sec, &tm, utc))
     290                 :          0 :                 return NULL;
     291                 :            : 
     292                 :            :         /* Start with the week day */
     293         [ -  + ]:      13436 :         assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
     294                 :      13436 :         memcpy(buf, weekdays[tm.tm_wday], 4);
     295                 :            : 
     296                 :            :         /* Add the main components */
     297         [ -  + ]:      13436 :         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         [ +  + ]:      13436 :         if (us) {
     302                 :       1056 :                 n = strlen(buf);
     303         [ -  + ]:       1056 :                 if (n + 8 > l)
     304                 :          0 :                         return NULL; /* Microseconds part doesn't fit. */
     305                 :            : 
     306                 :       1056 :                 sprintf(buf + n, ".%06"PRI_USEC, t % USEC_PER_SEC);
     307                 :            :         }
     308                 :            : 
     309                 :            :         /* Append the timezone */
     310                 :      13436 :         n = strlen(buf);
     311         [ +  + ]:      13436 :         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         [ -  + ]:        812 :                 if (n + 5 > l)
     315                 :          0 :                         return NULL; /* "UTC" doesn't fit. */
     316                 :            : 
     317                 :        812 :                 strcpy(buf + n, " UTC");
     318                 :            : 
     319         [ +  - ]:      12624 :         } 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                 :      12624 :                 tn = strlen(tm.tm_zone);
     324         [ -  + ]:      12624 :                 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                 :      12624 :                         buf[n++] = ' ';
     336                 :      12624 :                         strcpy(buf + n, tm.tm_zone);
     337                 :            :                 }
     338                 :            :         }
     339                 :            : 
     340                 :      13436 :         return buf;
     341                 :            : }
     342                 :            : 
     343                 :      24760 : char *format_timestamp(char *buf, size_t l, usec_t t) {
     344                 :      24760 :         return format_timestamp_internal(buf, l, t, false, false);
     345                 :            : }
     346                 :            : 
     347                 :        424 : char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
     348                 :        424 :         return format_timestamp_internal(buf, l, t, true, false);
     349                 :            : }
     350                 :            : 
     351                 :        656 : char *format_timestamp_us(char *buf, size_t l, usec_t t) {
     352                 :        656 :         return format_timestamp_internal(buf, l, t, false, true);
     353                 :            : }
     354                 :            : 
     355                 :        400 : char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
     356                 :        400 :         return format_timestamp_internal(buf, l, t, true, true);
     357                 :            : }
     358                 :            : 
     359                 :        548 : char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
     360                 :            :         const char *s;
     361                 :            :         usec_t n, d;
     362                 :            : 
     363   [ +  -  -  + ]:        548 :         if (t <= 0 || t == USEC_INFINITY)
     364                 :          0 :                 return NULL;
     365                 :            : 
     366                 :        548 :         n = now(CLOCK_REALTIME);
     367         [ +  + ]:        548 :         if (n > t) {
     368                 :        383 :                 d = n - t;
     369                 :        383 :                 s = "ago";
     370                 :            :         } else {
     371                 :        165 :                 d = t - n;
     372                 :        165 :                 s = "left";
     373                 :            :         }
     374                 :            : 
     375         [ +  + ]:        548 :         if (d >= USEC_PER_YEAR)
     376                 :        457 :                 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
     377                 :            :                          d / USEC_PER_YEAR,
     378                 :        457 :                          (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
     379         [ +  + ]:         91 :         else if (d >= USEC_PER_MONTH)
     380                 :         15 :                 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
     381                 :            :                          d / USEC_PER_MONTH,
     382                 :         15 :                          (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
     383         [ -  + ]:         76 :         else if (d >= USEC_PER_WEEK)
     384                 :          0 :                 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
     385                 :            :                          d / USEC_PER_WEEK,
     386                 :          0 :                          (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
     387         [ -  + ]:         76 :         else if (d >= 2*USEC_PER_DAY)
     388                 :          0 :                 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
     389         [ +  + ]:         76 :         else if (d >= 25*USEC_PER_HOUR)
     390                 :         12 :                 snprintf(buf, l, "1 day " USEC_FMT "h %s",
     391                 :         12 :                          (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
     392         [ +  + ]:         64 :         else if (d >= 6*USEC_PER_HOUR)
     393                 :         40 :                 snprintf(buf, l, USEC_FMT "h %s",
     394                 :            :                          d / USEC_PER_HOUR, s);
     395         [ +  + ]:         24 :         else if (d >= USEC_PER_HOUR)
     396                 :         20 :                 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
     397                 :            :                          d / USEC_PER_HOUR,
     398                 :         20 :                          (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
     399         [ -  + ]:          4 :         else if (d >= 5*USEC_PER_MINUTE)
     400                 :          0 :                 snprintf(buf, l, USEC_FMT "min %s",
     401                 :            :                          d / USEC_PER_MINUTE, s);
     402         [ -  + ]:          4 :         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         [ -  + ]:          4 :         else if (d >= USEC_PER_SEC)
     407                 :          0 :                 snprintf(buf, l, USEC_FMT "s %s",
     408                 :            :                          d / USEC_PER_SEC, s);
     409         [ -  + ]:          4 :         else if (d >= USEC_PER_MSEC)
     410                 :          0 :                 snprintf(buf, l, USEC_FMT "ms %s",
     411                 :            :                          d / USEC_PER_MSEC, s);
     412         [ +  - ]:          4 :         else if (d > 0)
     413                 :          4 :                 snprintf(buf, l, USEC_FMT"us %s",
     414                 :            :                          d, s);
     415                 :            :         else
     416                 :          0 :                 snprintf(buf, l, "now");
     417                 :            : 
     418                 :        548 :         buf[l-1] = 0;
     419                 :        548 :         return buf;
     420                 :            : }
     421                 :            : 
     422                 :       3716 : 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                 :       3716 :         char *p = buf;
     440                 :       3716 :         bool something = false;
     441                 :            : 
     442         [ -  + ]:       3716 :         assert(buf);
     443         [ -  + ]:       3716 :         assert(l > 0);
     444                 :            : 
     445         [ +  + ]:       3716 :         if (t == USEC_INFINITY) {
     446                 :       1820 :                 strncpy(p, "infinity", l-1);
     447                 :       1820 :                 p[l-1] = 0;
     448                 :       1820 :                 return p;
     449                 :            :         }
     450                 :            : 
     451         [ +  + ]:       1896 :         if (t <= 0) {
     452                 :        204 :                 strncpy(p, "0", l-1);
     453                 :        204 :                 p[l-1] = 0;
     454                 :        204 :                 return p;
     455                 :            :         }
     456                 :            : 
     457                 :            :         /* The result of this function can be parsed with parse_sec */
     458                 :            : 
     459         [ +  + ]:      13781 :         for (i = 0; i < ELEMENTSOF(table); i++) {
     460                 :      13745 :                 int k = 0;
     461                 :            :                 size_t n;
     462                 :      13745 :                 bool done = false;
     463                 :            :                 usec_t a, b;
     464                 :            : 
     465         [ +  + ]:      13745 :                 if (t <= 0)
     466                 :       1656 :                         break;
     467                 :            : 
     468   [ +  +  -  + ]:      12089 :                 if (t < accuracy && something)
     469                 :          0 :                         break;
     470                 :            : 
     471         [ +  + ]:      12089 :                 if (t < table[i].usec)
     472                 :       9105 :                         continue;
     473                 :            : 
     474         [ -  + ]:       2984 :                 if (l <= 1)
     475                 :          0 :                         break;
     476                 :            : 
     477                 :       2984 :                 a = t / table[i].usec;
     478                 :       2984 :                 b = t % table[i].usec;
     479                 :            : 
     480                 :            :                 /* Let's see if we should shows this in dot notation */
     481   [ +  +  +  + ]:       2984 :                 if (t < USEC_PER_MINUTE && b > 0) {
     482                 :            :                         usec_t cc;
     483                 :            :                         signed char j;
     484                 :            : 
     485                 :        504 :                         j = 0;
     486         [ +  + ]:       3357 :                         for (cc = table[i].usec; cc > 1; cc /= 10)
     487                 :       2853 :                                 j++;
     488                 :            : 
     489         [ +  + ]:       2244 :                         for (cc = accuracy; cc > 1; cc /= 10) {
     490                 :       1740 :                                 b /= 10;
     491                 :       1740 :                                 j--;
     492                 :            :                         }
     493                 :            : 
     494         [ +  + ]:        504 :                         if (j > 0) {
     495         [ +  + ]:        324 :                                 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                 :        324 :                                 t = 0;
     504                 :        324 :                                 done = true;
     505                 :            :                         }
     506                 :            :                 }
     507                 :            : 
     508                 :            :                 /* No? Then let's show it normally */
     509         [ +  + ]:       2984 :                 if (!done) {
     510         [ +  + ]:       2660 :                         k = snprintf(p, l,
     511                 :            :                                      "%s"USEC_FMT"%s",
     512                 :            :                                      p > buf ? " " : "",
     513                 :            :                                      a,
     514                 :            :                                      table[i].suffix);
     515                 :            : 
     516                 :       2660 :                         t = b;
     517                 :            :                 }
     518                 :            : 
     519                 :       2984 :                 n = MIN((size_t) k, l);
     520                 :            : 
     521                 :       2984 :                 l -= n;
     522                 :       2984 :                 p += n;
     523                 :            : 
     524                 :       2984 :                 something = true;
     525                 :            :         }
     526                 :            : 
     527                 :       1692 :         *p = 0;
     528                 :            : 
     529                 :       1692 :         return buf;
     530                 :            : }
     531                 :            : 
     532                 :       1918 : 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                 :       1918 :         const char *k, *utc = NULL, *tzn = NULL;
     554                 :            :         struct tm tm, copy;
     555                 :            :         time_t x;
     556                 :       1918 :         usec_t x_usec, plus = 0, minus = 0, ret;
     557                 :       1918 :         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         [ -  + ]:       1918 :         assert(t);
     577                 :            : 
     578   [ +  +  +  - ]:       1918 :         if (t[0] == '@' && !with_tz)
     579                 :          8 :                 return parse_sec(t + 1, usec);
     580                 :            : 
     581                 :       1910 :         ret = now(CLOCK_REALTIME);
     582                 :            : 
     583         [ +  - ]:       1910 :         if (!with_tz) {
     584         [ +  + ]:       1910 :                 if (streq(t, "now"))
     585                 :          4 :                         goto finish;
     586                 :            : 
     587         [ +  + ]:       1906 :                 else if (t[0] == '+') {
     588                 :         16 :                         r = parse_sec(t+1, &plus);
     589         [ +  + ]:         16 :                         if (r < 0)
     590                 :          8 :                                 return r;
     591                 :            : 
     592                 :          8 :                         goto finish;
     593                 :            : 
     594         [ +  + ]:       1890 :                 } else if (t[0] == '-') {
     595                 :          4 :                         r = parse_sec(t+1, &minus);
     596         [ -  + ]:          4 :                         if (r < 0)
     597                 :          0 :                                 return r;
     598                 :            : 
     599                 :          4 :                         goto finish;
     600                 :            : 
     601         [ +  + ]:       1886 :                 } else if ((k = endswith(t, " ago"))) {
     602                 :        299 :                         t = strndupa(t, k - t);
     603                 :            : 
     604                 :        299 :                         r = parse_sec(t, &minus);
     605         [ -  + ]:        299 :                         if (r < 0)
     606                 :          0 :                                 return r;
     607                 :            : 
     608                 :        299 :                         goto finish;
     609                 :            : 
     610         [ +  + ]:       1587 :                 } else if ((k = endswith(t, " left"))) {
     611                 :        105 :                         t = strndupa(t, k - t);
     612                 :            : 
     613                 :        105 :                         r = parse_sec(t, &plus);
     614         [ -  + ]:        105 :                         if (r < 0)
     615                 :          0 :                                 return r;
     616                 :            : 
     617                 :        105 :                         goto finish;
     618                 :            :                 }
     619                 :            : 
     620                 :            :                 /* See if the timestamp is suffixed with UTC */
     621                 :       1482 :                 utc = endswith_no_case(t, " UTC");
     622         [ +  + ]:       1482 :                 if (utc)
     623                 :        912 :                         t = strndupa(t, utc - t);
     624                 :            :                 else {
     625                 :        570 :                         const char *e = NULL;
     626                 :            :                         int j;
     627                 :            : 
     628                 :        570 :                         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         [ +  + ]:       1192 :                         for (j = 0; j <= 1; j++) {
     637                 :            : 
     638         [ -  + ]:       1140 :                                 if (isempty(tzname[j]))
     639                 :          0 :                                         continue;
     640                 :            : 
     641                 :       1140 :                                 e = endswith_no_case(t, tzname[j]);
     642         [ +  + ]:       1140 :                                 if (!e)
     643                 :        622 :                                         continue;
     644         [ -  + ]:        518 :                                 if (e == t)
     645                 :          0 :                                         continue;
     646         [ -  + ]:        518 :                                 if (e[-1] != ' ')
     647                 :          0 :                                         continue;
     648                 :            : 
     649                 :        518 :                                 break;
     650                 :            :                         }
     651                 :            : 
     652   [ +  +  +  + ]:        570 :                         if (IN_SET(j, 0, 1)) {
     653                 :            :                                 /* Found one of the two timezones specified. */
     654                 :        518 :                                 t = strndupa(t, e - t - 1);
     655                 :        518 :                                 dst = j;
     656                 :        518 :                                 tzn = tzname[j];
     657                 :            :                         }
     658                 :            :                 }
     659                 :            :         }
     660                 :            : 
     661                 :       1482 :         x = (time_t) (ret / USEC_PER_SEC);
     662                 :       1482 :         x_usec = 0;
     663                 :            : 
     664         [ -  + ]:       1482 :         if (!localtime_or_gmtime_r(&x, &tm, utc))
     665                 :          0 :                 return -EINVAL;
     666                 :            : 
     667                 :       1482 :         tm.tm_isdst = dst;
     668   [ +  -  +  + ]:       1482 :         if (!with_tz && tzn)
     669                 :        518 :                 tm.tm_zone = tzn;
     670                 :            : 
     671         [ +  + ]:       1482 :         if (streq(t, "today")) {
     672                 :          8 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     673                 :          8 :                 goto from_tm;
     674                 :            : 
     675         [ +  + ]:       1474 :         } else if (streq(t, "yesterday")) {
     676                 :          8 :                 tm.tm_mday--;
     677                 :          8 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     678                 :          8 :                 goto from_tm;
     679                 :            : 
     680         [ +  + ]:       1466 :         } else if (streq(t, "tomorrow")) {
     681                 :          8 :                 tm.tm_mday++;
     682                 :          8 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     683                 :          8 :                 goto from_tm;
     684                 :            :         }
     685                 :            : 
     686         [ +  + ]:      12748 :         for (i = 0; i < ELEMENTSOF(day_nr); i++) {
     687                 :            :                 size_t skip;
     688                 :            : 
     689         [ +  + ]:      12616 :                 if (!startswith_no_case(t, day_nr[i].name))
     690                 :      11290 :                         continue;
     691                 :            : 
     692                 :       1326 :                 skip = strlen(day_nr[i].name);
     693         [ -  + ]:       1326 :                 if (t[skip] != ' ')
     694                 :          0 :                         continue;
     695                 :            : 
     696                 :       1326 :                 weekday = day_nr[i].nr;
     697                 :       1326 :                 t += skip + 1;
     698                 :       1326 :                 break;
     699                 :            :         }
     700                 :            : 
     701                 :       1458 :         copy = tm;
     702                 :       1458 :         k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
     703         [ +  + ]:       1458 :         if (k) {
     704         [ -  + ]:         16 :                 if (*k == '.')
     705                 :          0 :                         goto parse_usec;
     706         [ +  - ]:         16 :                 else if (*k == 0)
     707                 :         16 :                         goto from_tm;
     708                 :            :         }
     709                 :            : 
     710                 :       1442 :         tm = copy;
     711                 :       1442 :         k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
     712         [ +  + ]:       1442 :         if (k) {
     713         [ +  + ]:       1334 :                 if (*k == '.')
     714                 :        721 :                         goto parse_usec;
     715         [ +  - ]:        613 :                 else if (*k == 0)
     716                 :        613 :                         goto from_tm;
     717                 :            :         }
     718                 :            : 
     719                 :        108 :         tm = copy;
     720                 :        108 :         k = strptime(t, "%y-%m-%d %H:%M", &tm);
     721   [ +  +  +  - ]:        108 :         if (k && *k == 0) {
     722                 :          8 :                 tm.tm_sec = 0;
     723                 :          8 :                 goto from_tm;
     724                 :            :         }
     725                 :            : 
     726                 :        100 :         tm = copy;
     727                 :        100 :         k = strptime(t, "%Y-%m-%d %H:%M", &tm);
     728   [ +  +  +  + ]:        100 :         if (k && *k == 0) {
     729                 :          8 :                 tm.tm_sec = 0;
     730                 :          8 :                 goto from_tm;
     731                 :            :         }
     732                 :            : 
     733                 :         92 :         tm = copy;
     734                 :         92 :         k = strptime(t, "%y-%m-%d", &tm);
     735   [ -  +  #  # ]:         92 :         if (k && *k == 0) {
     736                 :          0 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     737                 :          0 :                 goto from_tm;
     738                 :            :         }
     739                 :            : 
     740                 :         92 :         tm = copy;
     741                 :         92 :         k = strptime(t, "%Y-%m-%d", &tm);
     742   [ +  +  +  + ]:         92 :         if (k && *k == 0) {
     743                 :         24 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     744                 :         24 :                 goto from_tm;
     745                 :            :         }
     746                 :            : 
     747                 :         68 :         tm = copy;
     748                 :         68 :         k = strptime(t, "%H:%M:%S", &tm);
     749         [ +  + ]:         68 :         if (k) {
     750         [ +  + ]:         24 :                 if (*k == '.')
     751                 :         16 :                         goto parse_usec;
     752         [ +  - ]:          8 :                 else if (*k == 0)
     753                 :          8 :                         goto from_tm;
     754                 :            :         }
     755                 :            : 
     756                 :         44 :         tm = copy;
     757                 :         44 :         k = strptime(t, "%H:%M", &tm);
     758   [ +  +  +  + ]:         44 :         if (k && *k == 0) {
     759                 :         12 :                 tm.tm_sec = 0;
     760                 :         12 :                 goto from_tm;
     761                 :            :         }
     762                 :            : 
     763                 :         32 :         return -EINVAL;
     764                 :            : 
     765                 :        737 : parse_usec:
     766                 :            :         {
     767                 :            :                 unsigned add;
     768                 :            : 
     769                 :        737 :                 k++;
     770                 :        737 :                 r = parse_fractional_part_u(&k, 6, &add);
     771         [ -  + ]:        737 :                 if (r < 0)
     772                 :          0 :                         return -EINVAL;
     773                 :            : 
     774         [ -  + ]:        737 :                 if (*k)
     775                 :          0 :                         return -EINVAL;
     776                 :            : 
     777                 :        737 :                 x_usec = add;
     778                 :            :         }
     779                 :            : 
     780                 :       1450 : from_tm:
     781   [ +  +  -  + ]:       1450 :         if (weekday >= 0 && tm.tm_wday != weekday)
     782                 :          0 :                 return -EINVAL;
     783                 :            : 
     784                 :       1450 :         x = mktime_or_timegm(&tm, utc);
     785         [ +  + ]:       1450 :         if (x < 0)
     786                 :          4 :                 return -EINVAL;
     787                 :            : 
     788                 :       1446 :         ret = (usec_t) x * USEC_PER_SEC + x_usec;
     789         [ +  + ]:       1446 :         if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
     790                 :          4 :                 return -EINVAL;
     791                 :            : 
     792                 :       1442 : finish:
     793         [ -  + ]:       1862 :         if (ret + plus < ret) /* overflow? */
     794                 :          0 :                 return -EINVAL;
     795                 :       1862 :         ret += plus;
     796         [ -  + ]:       1862 :         if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
     797                 :          0 :                 return -EINVAL;
     798                 :            : 
     799         [ +  + ]:       1862 :         if (ret >= minus)
     800                 :       1858 :                 ret -= minus;
     801                 :            :         else
     802                 :          4 :                 return -EINVAL;
     803                 :            : 
     804         [ +  - ]:       1858 :         if (usec)
     805                 :       1858 :                 *usec = ret;
     806                 :       1858 :         return 0;
     807                 :            : }
     808                 :            : 
     809                 :            : typedef struct ParseTimestampResult {
     810                 :            :         usec_t usec;
     811                 :            :         int return_value;
     812                 :            : } ParseTimestampResult;
     813                 :            : 
     814                 :       2376 : int parse_timestamp(const char *t, usec_t *usec) {
     815                 :       2376 :         char *last_space, *tz = NULL;
     816                 :            :         ParseTimestampResult *shared, tmp;
     817                 :            :         int r;
     818                 :            : 
     819                 :       2376 :         last_space = strrchr(t, ' ');
     820   [ +  +  +  + ]:       2376 :         if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG))
     821                 :       1382 :                 tz = last_space + 1;
     822                 :            : 
     823   [ +  +  +  + ]:       2376 :         if (!tz || endswith_no_case(t, " UTC"))
     824                 :       1918 :                 return parse_timestamp_impl(t, usec, false);
     825                 :            : 
     826                 :        458 :         shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
     827         [ -  + ]:        458 :         if (shared == MAP_FAILED)
     828                 :          0 :                 return negative_errno();
     829                 :            : 
     830                 :        458 :         r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
     831         [ -  + ]:        458 :         if (r < 0) {
     832                 :          0 :                 (void) munmap(shared, sizeof *shared);
     833                 :          0 :                 return r;
     834                 :            :         }
     835         [ -  + ]:        458 :         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                 :        458 :         tmp = *shared;
     859         [ -  + ]:        458 :         if (munmap(shared, sizeof *shared) != 0)
     860                 :          0 :                 return negative_errno();
     861                 :            : 
     862   [ +  +  +  - ]:        458 :         if (tmp.return_value == 0 && usec)
     863                 :        446 :                 *usec = tmp.usec;
     864                 :            : 
     865                 :        458 :         return tmp.return_value;
     866                 :            : }
     867                 :            : 
     868                 :       1460 : 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         [ +  + ]:      22778 :         for (i = 0; i < ELEMENTSOF(table); i++) {
     906                 :            :                 char *e;
     907                 :            : 
     908                 :      22634 :                 e = startswith(p, table[i].suffix);
     909         [ +  + ]:      22634 :                 if (e) {
     910                 :       1316 :                         *multiplier = table[i].usec;
     911                 :       1316 :                         return e;
     912                 :            :                 }
     913                 :            :         }
     914                 :            : 
     915                 :        144 :         return p;
     916                 :            : }
     917                 :            : 
     918                 :       1008 : int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
     919                 :            :         const char *p, *s;
     920                 :       1008 :         usec_t r = 0;
     921                 :       1008 :         bool something = false;
     922                 :            : 
     923         [ -  + ]:       1008 :         assert(t);
     924         [ -  + ]:       1008 :         assert(default_unit > 0);
     925                 :            : 
     926                 :       1008 :         p = t;
     927                 :            : 
     928                 :       1008 :         p += strspn(p, WHITESPACE);
     929                 :       1008 :         s = startswith(p, "infinity");
     930         [ +  + ]:       1008 :         if (s) {
     931                 :         24 :                 s += strspn(s, WHITESPACE);
     932         [ +  + ]:         24 :                 if (*s != 0)
     933                 :          4 :                         return -EINVAL;
     934                 :            : 
     935         [ +  - ]:         20 :                 if (usec)
     936                 :         20 :                         *usec = USEC_INFINITY;
     937                 :         20 :                 return 0;
     938                 :            :         }
     939                 :            : 
     940                 :       1404 :         for (;;) {
     941                 :       2388 :                 usec_t multiplier = default_unit, k;
     942                 :            :                 long long l;
     943                 :            :                 char *e;
     944                 :            : 
     945                 :       2388 :                 p += strspn(p, WHITESPACE);
     946                 :            : 
     947         [ +  + ]:       2388 :                 if (*p == 0) {
     948         [ +  + ]:        880 :                         if (!something)
     949                 :        108 :                                 return -EINVAL;
     950                 :            : 
     951                 :        876 :                         break;
     952                 :            :                 }
     953                 :            : 
     954         [ +  + ]:       1508 :                 if (*p == '-') /* Don't allow "-0" */
     955                 :         24 :                         return -ERANGE;
     956                 :            : 
     957                 :       1484 :                 errno = 0;
     958                 :       1484 :                 l = strtoll(p, &e, 10);
     959         [ -  + ]:       1484 :                 if (errno > 0)
     960                 :          0 :                         return -errno;
     961         [ -  + ]:       1484 :                 if (l < 0)
     962                 :          0 :                         return -ERANGE;
     963                 :            : 
     964         [ +  + ]:       1484 :                 if (*e == '.') {
     965                 :        216 :                         p = e + 1;
     966                 :        216 :                         p += strspn(p, DIGITS);
     967         [ +  + ]:       1268 :                 } else if (e == p)
     968                 :         24 :                         return -EINVAL;
     969                 :            :                 else
     970                 :       1244 :                         p = e;
     971                 :            : 
     972                 :       1460 :                 s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
     973   [ +  +  +  + ]:       1460 :                 if (s == p && *s != '\0')
     974                 :            :                         /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
     975                 :         32 :                         return -EINVAL;
     976                 :            : 
     977                 :       1428 :                 p = s;
     978                 :            : 
     979         [ +  + ]:       1428 :                 if ((usec_t) l >= USEC_INFINITY / multiplier)
     980                 :          4 :                         return -ERANGE;
     981                 :            : 
     982                 :       1424 :                 k = (usec_t) l * multiplier;
     983         [ -  + ]:       1424 :                 if (k >= USEC_INFINITY - r)
     984                 :          0 :                         return -ERANGE;
     985                 :            : 
     986                 :       1424 :                 r += k;
     987                 :            : 
     988                 :       1424 :                 something = true;
     989                 :            : 
     990         [ +  + ]:       1424 :                 if (*e == '.') {
     991                 :        188 :                         usec_t m = multiplier / 10;
     992                 :            :                         const char *b;
     993                 :            : 
     994   [ +  +  +  + ]:        724 :                         for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
     995                 :        536 :                                 k = (usec_t) (*b - '0') * m;
     996         [ -  + ]:        536 :                                 if (k >= USEC_INFINITY - r)
     997                 :          0 :                                         return -ERANGE;
     998                 :            : 
     999                 :        536 :                                 r += k;
    1000                 :            :                         }
    1001                 :            : 
    1002                 :            :                         /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
    1003         [ +  + ]:        188 :                         if (b == e + 1)
    1004                 :         20 :                                 return -EINVAL;
    1005                 :            :                 }
    1006                 :            :         }
    1007                 :            : 
    1008         [ +  - ]:        876 :         if (usec)
    1009                 :        876 :                 *usec = r;
    1010                 :        876 :         return 0;
    1011                 :            : }
    1012                 :            : 
    1013                 :        948 : int parse_sec(const char *t, usec_t *usec) {
    1014                 :        948 :         return parse_time(t, usec, USEC_PER_SEC);
    1015                 :            : }
    1016                 :            : 
    1017                 :         16 : int parse_sec_fix_0(const char *t, usec_t *ret) {
    1018                 :            :         usec_t k;
    1019                 :            :         int r;
    1020                 :            : 
    1021         [ -  + ]:         16 :         assert(t);
    1022         [ -  + ]:         16 :         assert(ret);
    1023                 :            : 
    1024                 :         16 :         r = parse_sec(t, &k);
    1025         [ -  + ]:         16 :         if (r < 0)
    1026                 :          0 :                 return r;
    1027                 :            : 
    1028         [ +  + ]:         16 :         *ret = k == 0 ? USEC_INFINITY : k;
    1029                 :         16 :         return r;
    1030                 :            : }
    1031                 :            : 
    1032                 :         28 : int parse_sec_def_infinity(const char *t, usec_t *ret) {
    1033                 :         28 :         t += strspn(t, WHITESPACE);
    1034         [ +  + ]:         28 :         if (isempty(t)) {
    1035                 :          8 :                 *ret = USEC_INFINITY;
    1036                 :          8 :                 return 0;
    1037                 :            :         }
    1038                 :         20 :         return parse_sec(t, ret);
    1039                 :            : }
    1040                 :            : 
    1041                 :        172 : 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         [ +  - ]:       3092 :         for (i = 0; i < ELEMENTSOF(table); i++) {
    1082                 :            :                 char *e;
    1083                 :            : 
    1084                 :       3092 :                 e = startswith(p, table[i].suffix);
    1085         [ +  + ]:       3092 :                 if (e) {
    1086                 :        172 :                         *multiplier = table[i].nsec;
    1087                 :        172 :                         return e;
    1088                 :            :                 }
    1089                 :            :         }
    1090                 :            : 
    1091                 :          0 :         return p;
    1092                 :            : }
    1093                 :            : 
    1094                 :        188 : int parse_nsec(const char *t, nsec_t *nsec) {
    1095                 :            :         const char *p, *s;
    1096                 :        188 :         nsec_t r = 0;
    1097                 :        188 :         bool something = false;
    1098                 :            : 
    1099         [ -  + ]:        188 :         assert(t);
    1100         [ -  + ]:        188 :         assert(nsec);
    1101                 :            : 
    1102                 :        188 :         p = t;
    1103                 :            : 
    1104                 :        188 :         p += strspn(p, WHITESPACE);
    1105                 :        188 :         s = startswith(p, "infinity");
    1106         [ +  + ]:        188 :         if (s) {
    1107                 :         16 :                 s += strspn(s, WHITESPACE);
    1108         [ +  + ]:         16 :                 if (*s != 0)
    1109                 :          8 :                         return -EINVAL;
    1110                 :            : 
    1111                 :          8 :                 *nsec = NSEC_INFINITY;
    1112                 :          8 :                 return 0;
    1113                 :            :         }
    1114                 :            : 
    1115                 :        116 :         for (;;) {
    1116                 :        288 :                 nsec_t multiplier = 1, k;
    1117                 :            :                 long long l;
    1118                 :            :                 char *e;
    1119                 :            : 
    1120                 :        288 :                 p += strspn(p, WHITESPACE);
    1121                 :            : 
    1122         [ +  + ]:        288 :                 if (*p == 0) {
    1123         [ +  + ]:         80 :                         if (!something)
    1124                 :         96 :                                 return -EINVAL;
    1125                 :            : 
    1126                 :         76 :                         break;
    1127                 :            :                 }
    1128                 :            : 
    1129         [ +  + ]:        208 :                 if (*p == '-') /* Don't allow "-0" */
    1130                 :         20 :                         return -ERANGE;
    1131                 :            : 
    1132                 :        188 :                 errno = 0;
    1133                 :        188 :                 l = strtoll(p, &e, 10);
    1134         [ -  + ]:        188 :                 if (errno > 0)
    1135                 :          0 :                         return -errno;
    1136         [ -  + ]:        188 :                 if (l < 0)
    1137                 :          0 :                         return -ERANGE;
    1138                 :            : 
    1139         [ +  + ]:        188 :                 if (*e == '.') {
    1140                 :        124 :                         p = e + 1;
    1141                 :        124 :                         p += strspn(p, DIGITS);
    1142         [ +  + ]:         64 :                 } else if (e == p)
    1143                 :         16 :                         return -EINVAL;
    1144                 :            :                 else
    1145                 :         48 :                         p = e;
    1146                 :            : 
    1147                 :        172 :                 s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
    1148   [ +  +  +  + ]:        172 :                 if (s == p && *s != '\0')
    1149                 :            :                         /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
    1150                 :         32 :                         return -EINVAL;
    1151                 :            : 
    1152                 :        140 :                 p = s;
    1153                 :            : 
    1154         [ +  + ]:        140 :                 if ((nsec_t) l >= NSEC_INFINITY / multiplier)
    1155                 :          4 :                         return -ERANGE;
    1156                 :            : 
    1157                 :        136 :                 k = (nsec_t) l * multiplier;
    1158         [ -  + ]:        136 :                 if (k >= NSEC_INFINITY - r)
    1159                 :          0 :                         return -ERANGE;
    1160                 :            : 
    1161                 :        136 :                 r += k;
    1162                 :            : 
    1163                 :        136 :                 something = true;
    1164                 :            : 
    1165         [ +  + ]:        136 :                 if (*e == '.') {
    1166                 :         96 :                         nsec_t m = multiplier / 10;
    1167                 :            :                         const char *b;
    1168                 :            : 
    1169   [ +  +  +  + ]:        224 :                         for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
    1170                 :        128 :                                 k = (nsec_t) (*b - '0') * m;
    1171         [ -  + ]:        128 :                                 if (k >= NSEC_INFINITY - r)
    1172                 :          0 :                                         return -ERANGE;
    1173                 :            : 
    1174                 :        128 :                                 r += k;
    1175                 :            :                         }
    1176                 :            : 
    1177                 :            :                         /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
    1178         [ +  + ]:         96 :                         if (b == e + 1)
    1179                 :         20 :                                 return -EINVAL;
    1180                 :            :                 }
    1181                 :            :         }
    1182                 :            : 
    1183                 :         76 :         *nsec = r;
    1184                 :            : 
    1185                 :         76 :         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                 :          4 : int get_timezones(char ***ret) {
    1204                 :          4 :         _cleanup_fclose_ FILE *f = NULL;
    1205                 :          4 :         _cleanup_strv_free_ char **zones = NULL;
    1206                 :          4 :         size_t n_zones = 0, n_allocated = 0;
    1207                 :            :         int r;
    1208                 :            : 
    1209         [ -  + ]:          4 :         assert(ret);
    1210                 :            : 
    1211                 :          4 :         zones = strv_new("UTC");
    1212         [ -  + ]:          4 :         if (!zones)
    1213                 :          0 :                 return -ENOMEM;
    1214                 :            : 
    1215                 :          4 :         n_allocated = 2;
    1216                 :          4 :         n_zones = 1;
    1217                 :            : 
    1218                 :          4 :         f = fopen("/usr/share/zoneinfo/zone1970.tab", "re");
    1219         [ +  - ]:          4 :         if (f) {
    1220                 :       1532 :                 for (;;) {
    1221   [ +  -  +  + ]:       1536 :                         _cleanup_free_ char *line = NULL;
    1222                 :            :                         char *p, *w;
    1223                 :            :                         size_t k;
    1224                 :            : 
    1225                 :       1536 :                         r = read_line(f, LONG_LINE_MAX, &line);
    1226         [ -  + ]:       1536 :                         if (r < 0)
    1227                 :          0 :                                 return r;
    1228         [ +  + ]:       1536 :                         if (r == 0)
    1229                 :          4 :                                 break;
    1230                 :            : 
    1231                 :       1532 :                         p = strstrip(line);
    1232                 :            : 
    1233   [ +  -  +  + ]:       1532 :                         if (isempty(p) || *p == '#')
    1234                 :        140 :                                 continue;
    1235                 :            : 
    1236                 :            :                         /* Skip over country code */
    1237                 :       1392 :                         p += strcspn(p, WHITESPACE);
    1238                 :       1392 :                         p += strspn(p, WHITESPACE);
    1239                 :            : 
    1240                 :            :                         /* Skip over coordinates */
    1241                 :       1392 :                         p += strcspn(p, WHITESPACE);
    1242                 :       1392 :                         p += strspn(p, WHITESPACE);
    1243                 :            : 
    1244                 :            :                         /* Found timezone name */
    1245                 :       1392 :                         k = strcspn(p, WHITESPACE);
    1246         [ -  + ]:       1392 :                         if (k <= 0)
    1247                 :          0 :                                 continue;
    1248                 :            : 
    1249                 :       1392 :                         w = strndup(p, k);
    1250         [ -  + ]:       1392 :                         if (!w)
    1251                 :          0 :                                 return -ENOMEM;
    1252                 :            : 
    1253         [ -  + ]:       1392 :                         if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
    1254                 :          0 :                                 free(w);
    1255                 :          0 :                                 return -ENOMEM;
    1256                 :            :                         }
    1257                 :            : 
    1258                 :       1392 :                         zones[n_zones++] = w;
    1259                 :       1392 :                         zones[n_zones] = NULL;
    1260                 :            :                 }
    1261                 :            : 
    1262                 :          4 :                 strv_sort(zones);
    1263                 :            : 
    1264         [ #  # ]:          0 :         } else if (errno != ENOENT)
    1265                 :          0 :                 return -errno;
    1266                 :            : 
    1267                 :          4 :         *ret = TAKE_PTR(zones);
    1268                 :            : 
    1269                 :          4 :         return 0;
    1270                 :            : }
    1271                 :            : 
    1272                 :       4132 : bool timezone_is_valid(const char *name, int log_level) {
    1273                 :       4132 :         bool slash = false;
    1274                 :            :         const char *p, *t;
    1275                 :       4132 :         _cleanup_close_ int fd = -1;
    1276                 :            :         char buf[4];
    1277                 :            :         int r;
    1278                 :            : 
    1279         [ +  + ]:       4132 :         if (isempty(name))
    1280                 :          8 :                 return false;
    1281                 :            : 
    1282         [ -  + ]:       4124 :         if (name[0] == '/')
    1283                 :          0 :                 return false;
    1284                 :            : 
    1285         [ +  + ]:      35035 :         for (p = name; *p; p++) {
    1286   [ +  +  +  + ]:      31271 :                 if (!(*p >= '0' && *p <= '9') &&
    1287   [ +  +  -  + ]:      30655 :                     !(*p >= 'a' && *p <= 'z') &&
    1288   [ +  +  +  + ]:      11574 :                     !(*p >= 'A' && *p <= 'Z') &&
    1289   [ +  +  +  + ]:       2156 :                     !IN_SET(*p, '-', '_', '+', '/'))
    1290                 :        360 :                         return false;
    1291                 :            : 
    1292         [ +  + ]:      30911 :                 if (*p == '/') {
    1293                 :            : 
    1294         [ -  + ]:       1572 :                         if (slash)
    1295                 :          0 :                                 return false;
    1296                 :            : 
    1297                 :       1572 :                         slash = true;
    1298                 :            :                 } else
    1299                 :      29339 :                         slash = false;
    1300                 :            :         }
    1301                 :            : 
    1302         [ -  + ]:       3764 :         if (slash)
    1303                 :          0 :                 return false;
    1304                 :            : 
    1305         [ -  + ]:       3764 :         if (p - name >= PATH_MAX)
    1306                 :          0 :                 return false;
    1307                 :            : 
    1308   [ +  +  +  -  :      18820 :         t = strjoina("/usr/share/zoneinfo/", name);
          -  +  -  +  +  
                +  +  - ]
    1309                 :            : 
    1310                 :       3764 :         fd = open(t, O_RDONLY|O_CLOEXEC);
    1311         [ +  + ]:       3764 :         if (fd < 0) {
    1312         [ +  + ]:        934 :                 log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
    1313                 :        934 :                 return false;
    1314                 :            :         }
    1315                 :            : 
    1316                 :       2830 :         r = fd_verify_regular(fd);
    1317         [ -  + ]:       2830 :         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                 :       2830 :         r = loop_read_exact(fd, buf, 4, false);
    1323         [ -  + ]:       2830 :         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         [ -  + ]:       2830 :         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                 :       2830 :         return true;
    1335                 :            : }
    1336                 :            : 
    1337                 :     208242 : 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         [ +  + ]:     208242 :         if (supported < 0) {
    1343                 :            :                 int fd;
    1344                 :            : 
    1345                 :         60 :                 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
    1346         [ -  + ]:         60 :                 if (fd < 0)
    1347                 :          0 :                         supported = false;
    1348                 :            :                 else {
    1349                 :         60 :                         safe_close(fd);
    1350                 :         60 :                         supported = true;
    1351                 :            :                 }
    1352                 :            :         }
    1353                 :            : 
    1354                 :     208242 :         return supported;
    1355                 :            : }
    1356                 :            : 
    1357                 :       1680 : clockid_t clock_boottime_or_monotonic(void) {
    1358         [ +  - ]:       1680 :         if (clock_boottime_supported())
    1359                 :       1680 :                 return CLOCK_BOOTTIME;
    1360                 :            :         else
    1361                 :          0 :                 return CLOCK_MONOTONIC;
    1362                 :            : }
    1363                 :            : 
    1364                 :       2100 : bool clock_supported(clockid_t clock) {
    1365                 :            :         struct timespec ts;
    1366                 :            : 
    1367   [ +  +  +  - ]:       2100 :         switch (clock) {
    1368                 :            : 
    1369                 :       2020 :         case CLOCK_MONOTONIC:
    1370                 :            :         case CLOCK_REALTIME:
    1371                 :       2020 :                 return true;
    1372                 :            : 
    1373                 :         76 :         case CLOCK_BOOTTIME:
    1374                 :         76 :                 return clock_boottime_supported();
    1375                 :            : 
    1376                 :          4 :         case CLOCK_BOOTTIME_ALARM:
    1377         [ -  + ]:          4 :                 if (!clock_boottime_supported())
    1378                 :          0 :                         return false;
    1379                 :            : 
    1380                 :            :                 _fallthrough_;
    1381                 :            :         default:
    1382                 :            :                 /* For everything else, check properly */
    1383                 :          4 :                 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                 :      11075 : time_t mktime_or_timegm(struct tm *tm, bool utc) {
    1413         [ +  + ]:      11075 :         return utc ? timegm(tm) : mktime(tm);
    1414                 :            : }
    1415                 :            : 
    1416                 :      15250 : struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
    1417         [ +  + ]:      15250 :         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                 :         48 : usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
    1445                 :            :         usec_t a, b;
    1446                 :            : 
    1447         [ +  + ]:         48 :         if (x == USEC_INFINITY)
    1448                 :          4 :                 return USEC_INFINITY;
    1449         [ +  + ]:         44 :         if (map_clock_id(from) == map_clock_id(to))
    1450                 :         12 :                 return x;
    1451                 :            : 
    1452                 :         32 :         a = now(from);
    1453                 :         32 :         b = now(to);
    1454                 :            : 
    1455         [ +  + ]:         32 :         if (x > a)
    1456                 :            :                 /* x lies in the future */
    1457                 :         24 :                 return usec_add(b, usec_sub_unsigned(x, a));
    1458                 :            :         else
    1459                 :            :                 /* x lies in the past */
    1460                 :          8 :                 return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
    1461                 :            : }
    1462                 :            : 
    1463                 :          8 : bool in_utc_timezone(void) {
    1464                 :          8 :         tzset();
    1465                 :            : 
    1466   [ +  +  +  - ]:          8 :         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