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