LCOV - code coverage report
Current view: top level - basic - time-util.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 356 503 70.8 %
Date: 2015-07-29 18:47:03 Functions: 14 25 56.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2010 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <time.h>
      23             : #include <string.h>
      24             : #include <sys/timex.h>
      25             : #include <sys/timerfd.h>
      26             : 
      27             : #include "util.h"
      28             : #include "time-util.h"
      29             : #include "strv.h"
      30             : 
      31       70948 : usec_t now(clockid_t clock_id) {
      32             :         struct timespec ts;
      33             : 
      34       70948 :         assert_se(clock_gettime(clock_id, &ts) == 0);
      35             : 
      36       70948 :         return timespec_load(&ts);
      37             : }
      38             : 
      39       12264 : dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
      40       12264 :         assert(ts);
      41             : 
      42       12264 :         ts->realtime = now(CLOCK_REALTIME);
      43       12264 :         ts->monotonic = now(CLOCK_MONOTONIC);
      44             : 
      45       12264 :         return ts;
      46             : }
      47             : 
      48           0 : dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
      49             :         int64_t delta;
      50           0 :         assert(ts);
      51             : 
      52           0 :         if (u == USEC_INFINITY || u <= 0) {
      53           0 :                 ts->realtime = ts->monotonic = u;
      54           0 :                 return ts;
      55             :         }
      56             : 
      57           0 :         ts->realtime = u;
      58             : 
      59           0 :         delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
      60           0 :         ts->monotonic = now(CLOCK_MONOTONIC);
      61             : 
      62           0 :         if ((int64_t) ts->monotonic > delta)
      63           0 :                 ts->monotonic -= delta;
      64             :         else
      65           0 :                 ts->monotonic = 0;
      66             : 
      67           0 :         return ts;
      68             : }
      69             : 
      70           0 : dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
      71             :         int64_t delta;
      72           0 :         assert(ts);
      73             : 
      74           0 :         if (u == USEC_INFINITY) {
      75           0 :                 ts->realtime = ts->monotonic = USEC_INFINITY;
      76           0 :                 return ts;
      77             :         }
      78             : 
      79           0 :         ts->monotonic = u;
      80           0 :         delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
      81             : 
      82           0 :         ts->realtime = now(CLOCK_REALTIME);
      83           0 :         if ((int64_t) ts->realtime > delta)
      84           0 :                 ts->realtime -= delta;
      85             :         else
      86           0 :                 ts->realtime = 0;
      87             : 
      88           0 :         return ts;
      89             : }
      90             : 
      91       71096 : usec_t timespec_load(const struct timespec *ts) {
      92       71096 :         assert(ts);
      93             : 
      94       71096 :         if (ts->tv_sec == (time_t) -1 &&
      95           0 :             ts->tv_nsec == (long) -1)
      96           0 :                 return USEC_INFINITY;
      97             : 
      98       71096 :         if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
      99           0 :                 return USEC_INFINITY;
     100             : 
     101             :         return
     102      142192 :                 (usec_t) ts->tv_sec * USEC_PER_SEC +
     103       71096 :                 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
     104             : }
     105             : 
     106          74 : struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
     107          74 :         assert(ts);
     108             : 
     109          74 :         if (u == USEC_INFINITY) {
     110           0 :                 ts->tv_sec = (time_t) -1;
     111           0 :                 ts->tv_nsec = (long) -1;
     112           0 :                 return ts;
     113             :         }
     114             : 
     115          74 :         ts->tv_sec = (time_t) (u / USEC_PER_SEC);
     116          74 :         ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
     117             : 
     118          74 :         return ts;
     119             : }
     120             : 
     121           0 : usec_t timeval_load(const struct timeval *tv) {
     122           0 :         assert(tv);
     123             : 
     124           0 :         if (tv->tv_sec == (time_t) -1 &&
     125           0 :             tv->tv_usec == (suseconds_t) -1)
     126           0 :                 return USEC_INFINITY;
     127             : 
     128           0 :         if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
     129           0 :                 return USEC_INFINITY;
     130             : 
     131             :         return
     132           0 :                 (usec_t) tv->tv_sec * USEC_PER_SEC +
     133           0 :                 (usec_t) tv->tv_usec;
     134             : }
     135             : 
     136           0 : struct timeval *timeval_store(struct timeval *tv, usec_t u) {
     137           0 :         assert(tv);
     138             : 
     139           0 :         if (u == USEC_INFINITY) {
     140           0 :                 tv->tv_sec = (time_t) -1;
     141           0 :                 tv->tv_usec = (suseconds_t) -1;
     142             :         } else {
     143           0 :                 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
     144           0 :                 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
     145             :         }
     146             : 
     147           0 :         return tv;
     148             : }
     149             : 
     150        1353 : static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
     151             :         struct tm tm;
     152             :         time_t sec;
     153             : 
     154        1353 :         assert(buf);
     155        1353 :         assert(l > 0);
     156             : 
     157        1353 :         if (t <= 0 || t == USEC_INFINITY)
     158         804 :                 return NULL;
     159             : 
     160         549 :         sec = (time_t) (t / USEC_PER_SEC);
     161             : 
     162         549 :         if (utc)
     163           0 :                 gmtime_r(&sec, &tm);
     164             :         else
     165         549 :                 localtime_r(&sec, &tm);
     166         549 :         if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
     167           0 :                 return NULL;
     168             : 
     169         549 :         return buf;
     170             : }
     171             : 
     172        1353 : char *format_timestamp(char *buf, size_t l, usec_t t) {
     173        1353 :         return format_timestamp_internal(buf, l, t, false);
     174             : }
     175             : 
     176           0 : char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
     177           0 :         return format_timestamp_internal(buf, l, t, true);
     178             : }
     179             : 
     180           0 : static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
     181             :         struct tm tm;
     182             :         time_t sec;
     183             : 
     184           0 :         assert(buf);
     185           0 :         assert(l > 0);
     186             : 
     187           0 :         if (t <= 0 || t == USEC_INFINITY)
     188           0 :                 return NULL;
     189             : 
     190           0 :         sec = (time_t) (t / USEC_PER_SEC);
     191           0 :         if (utc)
     192           0 :                 gmtime_r(&sec, &tm);
     193             :         else
     194           0 :                 localtime_r(&sec, &tm);
     195             : 
     196           0 :         if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
     197           0 :                 return NULL;
     198           0 :         snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
     199           0 :         if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
     200           0 :                 return NULL;
     201             : 
     202           0 :         return buf;
     203             : }
     204             : 
     205           0 : char *format_timestamp_us(char *buf, size_t l, usec_t t) {
     206           0 :         return format_timestamp_internal_us(buf, l, t, false);
     207             : }
     208             : 
     209           0 : char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
     210           0 :         return format_timestamp_internal_us(buf, l, t, true);
     211             : }
     212             : 
     213          16 : char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
     214             :         const char *s;
     215             :         usec_t n, d;
     216             : 
     217          16 :         if (t <= 0 || t == USEC_INFINITY)
     218           0 :                 return NULL;
     219             : 
     220          16 :         n = now(CLOCK_REALTIME);
     221          16 :         if (n > t) {
     222          13 :                 d = n - t;
     223          13 :                 s = "ago";
     224             :         } else {
     225           3 :                 d = t - n;
     226           3 :                 s = "left";
     227             :         }
     228             : 
     229          16 :         if (d >= USEC_PER_YEAR)
     230           8 :                 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
     231             :                          d / USEC_PER_YEAR,
     232           8 :                          (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
     233           8 :         else if (d >= USEC_PER_MONTH)
     234           1 :                 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
     235             :                          d / USEC_PER_MONTH,
     236           1 :                          (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
     237           7 :         else if (d >= USEC_PER_WEEK)
     238           0 :                 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
     239             :                          d / USEC_PER_WEEK,
     240           0 :                          (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
     241           7 :         else if (d >= 2*USEC_PER_DAY)
     242           0 :                 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
     243           7 :         else if (d >= 25*USEC_PER_HOUR)
     244           2 :                 snprintf(buf, l, "1 day " USEC_FMT "h %s",
     245           2 :                          (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
     246           5 :         else if (d >= 6*USEC_PER_HOUR)
     247           1 :                 snprintf(buf, l, USEC_FMT "h %s",
     248             :                          d / USEC_PER_HOUR, s);
     249           4 :         else if (d >= USEC_PER_HOUR)
     250           2 :                 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
     251             :                          d / USEC_PER_HOUR,
     252           2 :                          (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
     253           2 :         else if (d >= 5*USEC_PER_MINUTE)
     254           0 :                 snprintf(buf, l, USEC_FMT "min %s",
     255             :                          d / USEC_PER_MINUTE, s);
     256           2 :         else if (d >= USEC_PER_MINUTE)
     257           1 :                 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
     258             :                          d / USEC_PER_MINUTE,
     259           1 :                          (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
     260           1 :         else if (d >= USEC_PER_SEC)
     261           0 :                 snprintf(buf, l, USEC_FMT "s %s",
     262             :                          d / USEC_PER_SEC, s);
     263           1 :         else if (d >= USEC_PER_MSEC)
     264           1 :                 snprintf(buf, l, USEC_FMT "ms %s",
     265             :                          d / USEC_PER_MSEC, s);
     266           0 :         else if (d > 0)
     267           0 :                 snprintf(buf, l, USEC_FMT"us %s",
     268             :                          d, s);
     269             :         else
     270           0 :                 snprintf(buf, l, "now");
     271             : 
     272          16 :         buf[l-1] = 0;
     273          16 :         return buf;
     274             : }
     275             : 
     276          93 : char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
     277             :         static const struct {
     278             :                 const char *suffix;
     279             :                 usec_t usec;
     280             :         } table[] = {
     281             :                 { "y", USEC_PER_YEAR },
     282             :                 { "month", USEC_PER_MONTH },
     283             :                 { "w", USEC_PER_WEEK },
     284             :                 { "d", USEC_PER_DAY },
     285             :                 { "h", USEC_PER_HOUR },
     286             :                 { "min", USEC_PER_MINUTE },
     287             :                 { "s", USEC_PER_SEC },
     288             :                 { "ms", USEC_PER_MSEC },
     289             :                 { "us", 1 },
     290             :         };
     291             : 
     292             :         unsigned i;
     293          93 :         char *p = buf;
     294          93 :         bool something = false;
     295             : 
     296          93 :         assert(buf);
     297          93 :         assert(l > 0);
     298             : 
     299          93 :         if (t == USEC_INFINITY) {
     300           7 :                 strncpy(p, "infinity", l-1);
     301           7 :                 p[l-1] = 0;
     302           7 :                 return p;
     303             :         }
     304             : 
     305          86 :         if (t <= 0) {
     306           7 :                 strncpy(p, "0", l-1);
     307           7 :                 p[l-1] = 0;
     308           7 :                 return p;
     309             :         }
     310             : 
     311             :         /* The result of this function can be parsed with parse_sec */
     312             : 
     313         666 :         for (i = 0; i < ELEMENTSOF(table); i++) {
     314         657 :                 int k = 0;
     315             :                 size_t n;
     316         657 :                 bool done = false;
     317             :                 usec_t a, b;
     318             : 
     319         657 :                 if (t <= 0)
     320          70 :                         break;
     321             : 
     322         587 :                 if (t < accuracy && something)
     323           0 :                         break;
     324             : 
     325         587 :                 if (t < table[i].usec)
     326         477 :                         continue;
     327             : 
     328         110 :                 if (l <= 1)
     329           0 :                         break;
     330             : 
     331         110 :                 a = t / table[i].usec;
     332         110 :                 b = t % table[i].usec;
     333             : 
     334             :                 /* Let's see if we should shows this in dot notation */
     335         110 :                 if (t < USEC_PER_MINUTE && b > 0) {
     336             :                         usec_t cc;
     337             :                         int j;
     338             : 
     339          55 :                         j = 0;
     340         349 :                         for (cc = table[i].usec; cc > 1; cc /= 10)
     341         294 :                                 j++;
     342             : 
     343         196 :                         for (cc = accuracy; cc > 1; cc /= 10) {
     344         141 :                                 b /= 10;
     345         141 :                                 j--;
     346             :                         }
     347             : 
     348          55 :                         if (j > 0) {
     349          36 :                                 k = snprintf(p, l,
     350             :                                              "%s"USEC_FMT".%0*llu%s",
     351             :                                              p > buf ? " " : "",
     352             :                                              a,
     353             :                                              j,
     354             :                                              (unsigned long long) b,
     355             :                                              table[i].suffix);
     356             : 
     357          36 :                                 t = 0;
     358          36 :                                 done = true;
     359             :                         }
     360             :                 }
     361             : 
     362             :                 /* No? Then let's show it normally */
     363         110 :                 if (!done) {
     364          74 :                         k = snprintf(p, l,
     365             :                                      "%s"USEC_FMT"%s",
     366             :                                      p > buf ? " " : "",
     367             :                                      a,
     368             :                                      table[i].suffix);
     369             : 
     370          74 :                         t = b;
     371             :                 }
     372             : 
     373         110 :                 n = MIN((size_t) k, l);
     374             : 
     375         110 :                 l -= n;
     376         110 :                 p += n;
     377             : 
     378         110 :                 something = true;
     379             :         }
     380             : 
     381          79 :         *p = 0;
     382             : 
     383          79 :         return buf;
     384             : }
     385             : 
     386           0 : void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
     387             : 
     388           0 :         assert(f);
     389           0 :         assert(name);
     390           0 :         assert(t);
     391             : 
     392           0 :         if (!dual_timestamp_is_set(t))
     393           0 :                 return;
     394             : 
     395           0 :         fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
     396             :                 name,
     397             :                 t->realtime,
     398             :                 t->monotonic);
     399             : }
     400             : 
     401           0 : int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
     402             :         unsigned long long a, b;
     403             : 
     404           0 :         assert(value);
     405           0 :         assert(t);
     406             : 
     407           0 :         if (sscanf(value, "%llu %llu", &a, &b) != 2) {
     408           0 :                 log_debug("Failed to parse finish timestamp value %s.", value);
     409           0 :                 return -EINVAL;
     410             :         }
     411             : 
     412           0 :         t->realtime = a;
     413           0 :         t->monotonic = b;
     414             : 
     415           0 :         return 0;
     416             : }
     417             : 
     418          48 : int parse_timestamp(const char *t, usec_t *usec) {
     419             :         static const struct {
     420             :                 const char *name;
     421             :                 const int nr;
     422             :         } day_nr[] = {
     423             :                 { "Sunday",    0 },
     424             :                 { "Sun",       0 },
     425             :                 { "Monday",    1 },
     426             :                 { "Mon",       1 },
     427             :                 { "Tuesday",   2 },
     428             :                 { "Tue",       2 },
     429             :                 { "Wednesday", 3 },
     430             :                 { "Wed",       3 },
     431             :                 { "Thursday",  4 },
     432             :                 { "Thu",       4 },
     433             :                 { "Friday",    5 },
     434             :                 { "Fri",       5 },
     435             :                 { "Saturday",  6 },
     436             :                 { "Sat",       6 },
     437             :         };
     438             : 
     439             :         const char *k;
     440             :         struct tm tm, copy;
     441             :         time_t x;
     442          48 :         usec_t plus = 0, minus = 0, ret;
     443          48 :         int r, weekday = -1;
     444             :         unsigned i;
     445             : 
     446             :         /*
     447             :          * Allowed syntaxes:
     448             :          *
     449             :          *   2012-09-22 16:34:22
     450             :          *   2012-09-22 16:34     (seconds will be set to 0)
     451             :          *   2012-09-22           (time will be set to 00:00:00)
     452             :          *   16:34:22             (date will be set to today)
     453             :          *   16:34                (date will be set to today, seconds to 0)
     454             :          *   now
     455             :          *   yesterday            (time is set to 00:00:00)
     456             :          *   today                (time is set to 00:00:00)
     457             :          *   tomorrow             (time is set to 00:00:00)
     458             :          *   +5min
     459             :          *   -5days
     460             :          *   @2147483647          (seconds since epoch)
     461             :          *
     462             :          */
     463             : 
     464          48 :         assert(t);
     465          48 :         assert(usec);
     466             : 
     467          48 :         x = time(NULL);
     468          48 :         assert_se(localtime_r(&x, &tm));
     469          48 :         tm.tm_isdst = -1;
     470             : 
     471          48 :         if (streq(t, "now"))
     472           1 :                 goto finish;
     473             : 
     474          47 :         else if (streq(t, "today")) {
     475           1 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     476           1 :                 goto finish;
     477             : 
     478          46 :         } else if (streq(t, "yesterday")) {
     479           1 :                 tm.tm_mday --;
     480           1 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     481           1 :                 goto finish;
     482             : 
     483          45 :         } else if (streq(t, "tomorrow")) {
     484           1 :                 tm.tm_mday ++;
     485           1 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     486           1 :                 goto finish;
     487             : 
     488          44 :         } else if (t[0] == '+') {
     489           2 :                 r = parse_sec(t+1, &plus);
     490           2 :                 if (r < 0)
     491           0 :                         return r;
     492             : 
     493           2 :                 goto finish;
     494             : 
     495          42 :         } else if (t[0] == '-') {
     496           0 :                 r = parse_sec(t+1, &minus);
     497           0 :                 if (r < 0)
     498           0 :                         return r;
     499             : 
     500           0 :                 goto finish;
     501             : 
     502          42 :         } else if (t[0] == '@')
     503           1 :                 return parse_sec(t + 1, usec);
     504             : 
     505          41 :         else if (endswith(t, " ago")) {
     506           1 :                 _cleanup_free_ char *z;
     507             : 
     508           1 :                 z = strndup(t, strlen(t) - 4);
     509           1 :                 if (!z)
     510           0 :                         return -ENOMEM;
     511             : 
     512           1 :                 r = parse_sec(z, &minus);
     513           1 :                 if (r < 0)
     514           0 :                         return r;
     515             : 
     516           1 :                 goto finish;
     517          40 :         } else if (endswith(t, " left")) {
     518           0 :                 _cleanup_free_ char *z;
     519             : 
     520           0 :                 z = strndup(t, strlen(t) - 4);
     521           0 :                 if (!z)
     522           0 :                         return -ENOMEM;
     523             : 
     524           0 :                 r = parse_sec(z, &plus);
     525           0 :                 if (r < 0)
     526           0 :                         return r;
     527             : 
     528           0 :                 goto finish;
     529             :         }
     530             : 
     531         351 :         for (i = 0; i < ELEMENTSOF(day_nr); i++) {
     532             :                 size_t skip;
     533             : 
     534         344 :                 if (!startswith_no_case(t, day_nr[i].name))
     535         311 :                         continue;
     536             : 
     537          33 :                 skip = strlen(day_nr[i].name);
     538          33 :                 if (t[skip] != ' ')
     539           0 :                         continue;
     540             : 
     541          33 :                 weekday = day_nr[i].nr;
     542          33 :                 t += skip + 1;
     543          33 :                 break;
     544             :         }
     545             : 
     546          40 :         copy = tm;
     547          40 :         k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
     548          40 :         if (k && *k == 0)
     549           2 :                 goto finish;
     550             : 
     551          38 :         tm = copy;
     552          38 :         k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
     553          38 :         if (k && *k == 0)
     554          32 :                 goto finish;
     555             : 
     556           6 :         tm = copy;
     557           6 :         k = strptime(t, "%y-%m-%d %H:%M", &tm);
     558           6 :         if (k && *k == 0) {
     559           1 :                 tm.tm_sec = 0;
     560           1 :                 goto finish;
     561             :         }
     562             : 
     563           5 :         tm = copy;
     564           5 :         k = strptime(t, "%Y-%m-%d %H:%M", &tm);
     565           5 :         if (k && *k == 0) {
     566           1 :                 tm.tm_sec = 0;
     567           1 :                 goto finish;
     568             :         }
     569             : 
     570           4 :         tm = copy;
     571           4 :         k = strptime(t, "%y-%m-%d", &tm);
     572           4 :         if (k && *k == 0) {
     573           0 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     574           0 :                 goto finish;
     575             :         }
     576             : 
     577           4 :         tm = copy;
     578           4 :         k = strptime(t, "%Y-%m-%d", &tm);
     579           4 :         if (k && *k == 0) {
     580           2 :                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
     581           2 :                 goto finish;
     582             :         }
     583             : 
     584           2 :         tm = copy;
     585           2 :         k = strptime(t, "%H:%M:%S", &tm);
     586           2 :         if (k && *k == 0)
     587           1 :                 goto finish;
     588             : 
     589           1 :         tm = copy;
     590           1 :         k = strptime(t, "%H:%M", &tm);
     591           1 :         if (k && *k == 0) {
     592           1 :                 tm.tm_sec = 0;
     593           1 :                 goto finish;
     594             :         }
     595             : 
     596           0 :         return -EINVAL;
     597             : 
     598             : finish:
     599          47 :         x = mktime(&tm);
     600          47 :         if (x == (time_t) -1)
     601           0 :                 return -EINVAL;
     602             : 
     603          47 :         if (weekday >= 0 && tm.tm_wday != weekday)
     604           0 :                 return -EINVAL;
     605             : 
     606          47 :         ret = (usec_t) x * USEC_PER_SEC;
     607             : 
     608          47 :         ret += plus;
     609          47 :         if (ret > minus)
     610          47 :                 ret -= minus;
     611             :         else
     612           0 :                 ret = 0;
     613             : 
     614          47 :         *usec = ret;
     615             : 
     616          47 :         return 0;
     617             : }
     618             : 
     619          98 : int parse_sec(const char *t, usec_t *usec) {
     620             :         static const struct {
     621             :                 const char *suffix;
     622             :                 usec_t usec;
     623             :         } table[] = {
     624             :                 { "seconds", USEC_PER_SEC },
     625             :                 { "second", USEC_PER_SEC },
     626             :                 { "sec", USEC_PER_SEC },
     627             :                 { "s", USEC_PER_SEC },
     628             :                 { "minutes", USEC_PER_MINUTE },
     629             :                 { "minute", USEC_PER_MINUTE },
     630             :                 { "min", USEC_PER_MINUTE },
     631             :                 { "months", USEC_PER_MONTH },
     632             :                 { "month", USEC_PER_MONTH },
     633             :                 { "msec", USEC_PER_MSEC },
     634             :                 { "ms", USEC_PER_MSEC },
     635             :                 { "m", USEC_PER_MINUTE },
     636             :                 { "hours", USEC_PER_HOUR },
     637             :                 { "hour", USEC_PER_HOUR },
     638             :                 { "hr", USEC_PER_HOUR },
     639             :                 { "h", USEC_PER_HOUR },
     640             :                 { "days", USEC_PER_DAY },
     641             :                 { "day", USEC_PER_DAY },
     642             :                 { "d", USEC_PER_DAY },
     643             :                 { "weeks", USEC_PER_WEEK },
     644             :                 { "week", USEC_PER_WEEK },
     645             :                 { "w", USEC_PER_WEEK },
     646             :                 { "years", USEC_PER_YEAR },
     647             :                 { "year", USEC_PER_YEAR },
     648             :                 { "y", USEC_PER_YEAR },
     649             :                 { "usec", 1ULL },
     650             :                 { "us", 1ULL },
     651             :                 { "", USEC_PER_SEC }, /* default is sec */
     652             :         };
     653             : 
     654             :         const char *p, *s;
     655          98 :         usec_t r = 0;
     656          98 :         bool something = false;
     657             : 
     658          98 :         assert(t);
     659          98 :         assert(usec);
     660             : 
     661          98 :         p = t;
     662             : 
     663          98 :         p += strspn(p, WHITESPACE);
     664          98 :         s = startswith(p, "infinity");
     665          98 :         if (s) {
     666           6 :                 s += strspn(s, WHITESPACE);
     667           6 :                 if (*s != 0)
     668           1 :                         return -EINVAL;
     669             : 
     670           5 :                 *usec = USEC_INFINITY;
     671           5 :                 return 0;
     672             :         }
     673             : 
     674             :         for (;;) {
     675         200 :                 long long l, z = 0;
     676             :                 char *e;
     677         200 :                 unsigned i, n = 0;
     678             : 
     679         200 :                 p += strspn(p, WHITESPACE);
     680             : 
     681         200 :                 if (*p == 0) {
     682          84 :                         if (!something)
     683          10 :                                 return -EINVAL;
     684             : 
     685          83 :                         break;
     686             :                 }
     687             : 
     688         116 :                 errno = 0;
     689         116 :                 l = strtoll(p, &e, 10);
     690             : 
     691         116 :                 if (errno > 0)
     692           0 :                         return -errno;
     693             : 
     694         116 :                 if (l < 0)
     695           1 :                         return -ERANGE;
     696             : 
     697         115 :                 if (*e == '.') {
     698          37 :                         char *b = e + 1;
     699             : 
     700          37 :                         errno = 0;
     701          37 :                         z = strtoll(b, &e, 10);
     702          37 :                         if (errno > 0)
     703           0 :                                 return -errno;
     704             : 
     705          37 :                         if (z < 0)
     706           0 :                                 return -ERANGE;
     707             : 
     708          37 :                         if (e == b)
     709           3 :                                 return -EINVAL;
     710             : 
     711          34 :                         n = e - b;
     712             : 
     713          78 :                 } else if (e == p)
     714           4 :                         return -EINVAL;
     715             : 
     716         108 :                 e += strspn(e, WHITESPACE);
     717             : 
     718        1310 :                 for (i = 0; i < ELEMENTSOF(table); i++)
     719        1310 :                         if (startswith(e, table[i].suffix)) {
     720         108 :                                 usec_t k = (usec_t) z * table[i].usec;
     721             : 
     722         229 :                                 for (; n > 0; n--)
     723         121 :                                         k /= 10;
     724             : 
     725         108 :                                 r += (usec_t) l * table[i].usec + k;
     726         108 :                                 p = e + strlen(table[i].suffix);
     727             : 
     728         108 :                                 something = true;
     729         108 :                                 break;
     730             :                         }
     731             : 
     732         108 :                 if (i >= ELEMENTSOF(table))
     733           0 :                         return -EINVAL;
     734             : 
     735         108 :         }
     736             : 
     737          83 :         *usec = r;
     738             : 
     739          83 :         return 0;
     740             : }
     741             : 
     742          25 : int parse_nsec(const char *t, nsec_t *nsec) {
     743             :         static const struct {
     744             :                 const char *suffix;
     745             :                 nsec_t nsec;
     746             :         } table[] = {
     747             :                 { "seconds", NSEC_PER_SEC },
     748             :                 { "second", NSEC_PER_SEC },
     749             :                 { "sec", NSEC_PER_SEC },
     750             :                 { "s", NSEC_PER_SEC },
     751             :                 { "minutes", NSEC_PER_MINUTE },
     752             :                 { "minute", NSEC_PER_MINUTE },
     753             :                 { "min", NSEC_PER_MINUTE },
     754             :                 { "months", NSEC_PER_MONTH },
     755             :                 { "month", NSEC_PER_MONTH },
     756             :                 { "msec", NSEC_PER_MSEC },
     757             :                 { "ms", NSEC_PER_MSEC },
     758             :                 { "m", NSEC_PER_MINUTE },
     759             :                 { "hours", NSEC_PER_HOUR },
     760             :                 { "hour", NSEC_PER_HOUR },
     761             :                 { "hr", NSEC_PER_HOUR },
     762             :                 { "h", NSEC_PER_HOUR },
     763             :                 { "days", NSEC_PER_DAY },
     764             :                 { "day", NSEC_PER_DAY },
     765             :                 { "d", NSEC_PER_DAY },
     766             :                 { "weeks", NSEC_PER_WEEK },
     767             :                 { "week", NSEC_PER_WEEK },
     768             :                 { "w", NSEC_PER_WEEK },
     769             :                 { "years", NSEC_PER_YEAR },
     770             :                 { "year", NSEC_PER_YEAR },
     771             :                 { "y", NSEC_PER_YEAR },
     772             :                 { "usec", NSEC_PER_USEC },
     773             :                 { "us", NSEC_PER_USEC },
     774             :                 { "nsec", 1ULL },
     775             :                 { "ns", 1ULL },
     776             :                 { "", 1ULL }, /* default is nsec */
     777             :         };
     778             : 
     779             :         const char *p, *s;
     780          25 :         nsec_t r = 0;
     781          25 :         bool something = false;
     782             : 
     783          25 :         assert(t);
     784          25 :         assert(nsec);
     785             : 
     786          25 :         p = t;
     787             : 
     788          25 :         p += strspn(p, WHITESPACE);
     789          25 :         s = startswith(p, "infinity");
     790          25 :         if (s) {
     791           3 :                 s += strspn(s, WHITESPACE);
     792           3 :                 if (*s != 0)
     793           1 :                         return -EINVAL;
     794             : 
     795           2 :                 *nsec = NSEC_INFINITY;
     796           2 :                 return 0;
     797             :         }
     798             : 
     799             :         for (;;) {
     800          41 :                 long long l, z = 0;
     801             :                 char *e;
     802          41 :                 unsigned i, n = 0;
     803             : 
     804          41 :                 p += strspn(p, WHITESPACE);
     805             : 
     806          41 :                 if (*p == 0) {
     807          14 :                         if (!something)
     808          10 :                                 return -EINVAL;
     809             : 
     810          13 :                         break;
     811             :                 }
     812             : 
     813          27 :                 errno = 0;
     814          27 :                 l = strtoll(p, &e, 10);
     815             : 
     816          27 :                 if (errno > 0)
     817           0 :                         return -errno;
     818             : 
     819          27 :                 if (l < 0)
     820           1 :                         return -ERANGE;
     821             : 
     822          26 :                 if (*e == '.') {
     823          11 :                         char *b = e + 1;
     824             : 
     825          11 :                         errno = 0;
     826          11 :                         z = strtoll(b, &e, 10);
     827          11 :                         if (errno > 0)
     828           0 :                                 return -errno;
     829             : 
     830          11 :                         if (z < 0)
     831           0 :                                 return -ERANGE;
     832             : 
     833          11 :                         if (e == b)
     834           3 :                                 return -EINVAL;
     835             : 
     836           8 :                         n = e - b;
     837             : 
     838          15 :                 } else if (e == p)
     839           4 :                         return -EINVAL;
     840             : 
     841          19 :                 e += strspn(e, WHITESPACE);
     842             : 
     843         258 :                 for (i = 0; i < ELEMENTSOF(table); i++)
     844         258 :                         if (startswith(e, table[i].suffix)) {
     845          19 :                                 nsec_t k = (nsec_t) z * table[i].nsec;
     846             : 
     847          29 :                                 for (; n > 0; n--)
     848          10 :                                         k /= 10;
     849             : 
     850          19 :                                 r += (nsec_t) l * table[i].nsec + k;
     851          19 :                                 p = e + strlen(table[i].suffix);
     852             : 
     853          19 :                                 something = true;
     854          19 :                                 break;
     855             :                         }
     856             : 
     857          19 :                 if (i >= ELEMENTSOF(table))
     858           0 :                         return -EINVAL;
     859             : 
     860          19 :         }
     861             : 
     862          13 :         *nsec = r;
     863             : 
     864          13 :         return 0;
     865             : }
     866             : 
     867           0 : bool ntp_synced(void) {
     868           0 :         struct timex txc = {};
     869             : 
     870           0 :         if (adjtimex(&txc) < 0)
     871           0 :                 return false;
     872             : 
     873           0 :         if (txc.status & STA_UNSYNC)
     874           0 :                 return false;
     875             : 
     876           0 :         return true;
     877             : }
     878             : 
     879           1 : int get_timezones(char ***ret) {
     880           2 :         _cleanup_fclose_ FILE *f = NULL;
     881           2 :         _cleanup_strv_free_ char **zones = NULL;
     882           1 :         size_t n_zones = 0, n_allocated = 0;
     883             : 
     884           1 :         assert(ret);
     885             : 
     886           1 :         zones = strv_new("UTC", NULL);
     887           1 :         if (!zones)
     888           0 :                 return -ENOMEM;
     889             : 
     890           1 :         n_allocated = 2;
     891           1 :         n_zones = 1;
     892             : 
     893           1 :         f = fopen("/usr/share/zoneinfo/zone.tab", "re");
     894           1 :         if (f) {
     895             :                 char l[LINE_MAX];
     896             : 
     897         441 :                 FOREACH_LINE(l, f, return -errno) {
     898             :                         char *p, *w;
     899             :                         size_t k;
     900             : 
     901         440 :                         p = strstrip(l);
     902             : 
     903         440 :                         if (isempty(p) || *p == '#')
     904          24 :                                 continue;
     905             : 
     906             :                         /* Skip over country code */
     907         416 :                         p += strcspn(p, WHITESPACE);
     908         416 :                         p += strspn(p, WHITESPACE);
     909             : 
     910             :                         /* Skip over coordinates */
     911         416 :                         p += strcspn(p, WHITESPACE);
     912         416 :                         p += strspn(p, WHITESPACE);
     913             : 
     914             :                         /* Found timezone name */
     915         416 :                         k = strcspn(p, WHITESPACE);
     916         416 :                         if (k <= 0)
     917           0 :                                 continue;
     918             : 
     919         416 :                         w = strndup(p, k);
     920         416 :                         if (!w)
     921           0 :                                 return -ENOMEM;
     922             : 
     923         416 :                         if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
     924           0 :                                 free(w);
     925           0 :                                 return -ENOMEM;
     926             :                         }
     927             : 
     928         416 :                         zones[n_zones++] = w;
     929         416 :                         zones[n_zones] = NULL;
     930         440 :                 }
     931             : 
     932           1 :                 strv_sort(zones);
     933             : 
     934           0 :         } else if (errno != ENOENT)
     935           0 :                 return -errno;
     936             : 
     937           1 :         *ret = zones;
     938           1 :         zones = NULL;
     939             : 
     940           1 :         return 0;
     941             : }
     942             : 
     943         420 : bool timezone_is_valid(const char *name) {
     944         420 :         bool slash = false;
     945             :         const char *p, *t;
     946             :         struct stat st;
     947             : 
     948         420 :         if (!name || *name == 0 || *name == '/')
     949           0 :                 return false;
     950             : 
     951        6932 :         for (p = name; *p; p++) {
     952       13026 :                 if (!(*p >= '0' && *p <= '9') &&
     953       13026 :                     !(*p >= 'a' && *p <= 'z') &&
     954        2955 :                     !(*p >= 'A' && *p <= 'Z') &&
     955        1021 :                     !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
     956           1 :                         return false;
     957             : 
     958        6512 :                 if (*p == '/') {
     959             : 
     960         444 :                         if (slash)
     961           0 :                                 return false;
     962             : 
     963         444 :                         slash = true;
     964             :                 } else
     965        6068 :                         slash = false;
     966             :         }
     967             : 
     968         419 :         if (slash)
     969           0 :                 return false;
     970             : 
     971         419 :         t = strjoina("/usr/share/zoneinfo/", name);
     972         419 :         if (stat(t, &st) < 0)
     973           0 :                 return false;
     974             : 
     975         419 :         if (!S_ISREG(st.st_mode))
     976           0 :                 return false;
     977             : 
     978         419 :         return true;
     979             : }
     980             : 
     981          69 : clockid_t clock_boottime_or_monotonic(void) {
     982             :         static clockid_t clock = -1;
     983             :         int fd;
     984             : 
     985          69 :         if (clock != -1)
     986          65 :                 return clock;
     987             : 
     988           4 :         fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
     989           4 :         if (fd < 0)
     990           0 :                 clock = CLOCK_MONOTONIC;
     991             :         else {
     992           4 :                 safe_close(fd);
     993           4 :                 clock = CLOCK_BOOTTIME;
     994             :         }
     995             : 
     996           4 :         return clock;
     997             : }

Generated by: LCOV version 1.11