X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Ftime-util.c;h=fc79c569f4bceb52450a4a7be17ea09d6b8c817b;hb=a1948c7bfeb87b54bc7715a44490c01593ee6e23;hp=c66763872d77536a83d7c89c41a26153018625aa;hpb=de0671ee7fe465e108f62dcbbbe9366f81dd9e9a;p=elogind.git diff --git a/src/shared/time-util.c b/src/shared/time-util.c index c66763872..fc79c569f 100644 --- a/src/shared/time-util.c +++ b/src/shared/time-util.c @@ -25,6 +25,7 @@ #include "util.h" #include "time-util.h" +#include "strv.h" usec_t now(clockid_t clock_id) { struct timespec ts; @@ -183,7 +184,7 @@ char *format_timestamp_us(char *buf, size_t l, usec_t t) { if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) return NULL; - snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", t % USEC_PER_SEC); + snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC)); if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0) return NULL; @@ -208,41 +209,41 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t) { } if (d >= USEC_PER_YEAR) - snprintf(buf, l, "%llu years %llu months %s", + snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s", d / USEC_PER_YEAR, (d % USEC_PER_YEAR) / USEC_PER_MONTH, s); else if (d >= USEC_PER_MONTH) - snprintf(buf, l, "%llu months %llu days %s", + snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s", d / USEC_PER_MONTH, (d % USEC_PER_MONTH) / USEC_PER_DAY, s); else if (d >= USEC_PER_WEEK) - snprintf(buf, l, "%llu weeks %llu days %s", + snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s", d / USEC_PER_WEEK, (d % USEC_PER_WEEK) / USEC_PER_DAY, s); else if (d >= 2*USEC_PER_DAY) - snprintf(buf, l, "%llu days %s", d / USEC_PER_DAY, s); + snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s); else if (d >= 25*USEC_PER_HOUR) - snprintf(buf, l, "1 day %lluh %s", + snprintf(buf, l, "1 day " USEC_FMT "h %s", (d - USEC_PER_DAY) / USEC_PER_HOUR, s); else if (d >= 6*USEC_PER_HOUR) - snprintf(buf, l, "%lluh %s", + snprintf(buf, l, USEC_FMT "h %s", d / USEC_PER_HOUR, s); else if (d >= USEC_PER_HOUR) - snprintf(buf, l, "%lluh %llumin %s", + snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s", d / USEC_PER_HOUR, (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s); else if (d >= 5*USEC_PER_MINUTE) - snprintf(buf, l, "%llumin %s", + snprintf(buf, l, USEC_FMT "min %s", d / USEC_PER_MINUTE, s); else if (d >= USEC_PER_MINUTE) - snprintf(buf, l, "%llumin %llus %s", + snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s", d / USEC_PER_MINUTE, (d % USEC_PER_MINUTE) / USEC_PER_SEC, s); else if (d >= USEC_PER_SEC) - snprintf(buf, l, "%llus %s", + snprintf(buf, l, USEC_FMT "s %s", d / USEC_PER_SEC, s); else if (d >= USEC_PER_MSEC) - snprintf(buf, l, "%llums %s", + snprintf(buf, l, USEC_FMT "ms %s", d / USEC_PER_MSEC, s); else if (d > 0) snprintf(buf, l, USEC_FMT"us %s", @@ -826,3 +827,105 @@ bool ntp_synced(void) { return true; } + +int get_timezones(char ***ret) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **zones = NULL; + size_t n_zones = 0, n_allocated = 0; + + assert(ret); + + zones = strv_new("UTC", NULL); + if (!zones) + return -ENOMEM; + + n_allocated = 2; + n_zones = 1; + + f = fopen("/usr/share/zoneinfo/zone.tab", "re"); + if (f) { + char l[LINE_MAX]; + + FOREACH_LINE(l, f, return -errno) { + char *p, *w; + size_t k; + + p = strstrip(l); + + if (isempty(p) || *p == '#') + continue; + + /* Skip over country code */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Skip over coordinates */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Found timezone name */ + k = strcspn(p, WHITESPACE); + if (k <= 0) + continue; + + w = strndup(p, k); + if (!w) + return -ENOMEM; + + if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) { + free(w); + return -ENOMEM; + } + + zones[n_zones++] = w; + zones[n_zones] = NULL; + } + + strv_sort(zones); + + } else if (errno != ENOENT) + return -errno; + + *ret = zones; + zones = NULL; + + return 0; +} + +bool timezone_is_valid(const char *name) { + bool slash = false; + const char *p, *t; + struct stat st; + + if (!name || *name == 0 || *name == '/') + return false; + + for (p = name; *p; p++) { + if (!(*p >= '0' && *p <= '9') && + !(*p >= 'a' && *p <= 'z') && + !(*p >= 'A' && *p <= 'Z') && + !(*p == '-' || *p == '_' || *p == '+' || *p == '/')) + return false; + + if (*p == '/') { + + if (slash) + return false; + + slash = true; + } else + slash = false; + } + + if (slash) + return false; + + t = strappenda("/usr/share/zoneinfo/", name); + if (stat(t, &st) < 0) + return false; + + if (!S_ISREG(st.st_mode)) + return false; + + return true; +}