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