]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/time-util.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / basic / time-util.c
index 141b91f6378c1eee1417ff98ddeb9ff3564dc8c9..25a5c116e89827bf2e2b62cbb4ad6ba14f6359d9 100644 (file)
 #include <unistd.h>
 
 #include "alloc-util.h"
-#include "def.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
 #include "io-util.h"
 #include "log.h"
 #include "macro.h"
+#include "missing_timerfd.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
-#include "serialize.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -868,7 +867,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
         return tmp.return_value;
 }
 
-static char* extract_multiplier(char *p, usec_t *multiplier) {
+static const char* extract_multiplier(const char *p, usec_t *multiplier) {
         static const struct {
                 const char *suffix;
                 usec_t usec;
@@ -942,8 +941,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
 
         for (;;) {
                 usec_t multiplier = default_unit, k;
-                long long l, z = 0;
-                unsigned n = 0;
+                long long l;
                 char *e;
 
                 p += strspn(p, WHITESPACE);
@@ -966,46 +964,47 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
                         return -ERANGE;
 
                 if (*e == '.') {
-                        char *b = e + 1;
-
-                        /* Don't allow "0.-0", "3.+1" or "3. 1" */
-                        if (IN_SET(*b, '-', '+') || isspace(*b))
-                                return -EINVAL;
-
-                        errno = 0;
-                        z = strtoll(b, &e, 10);
-                        if (errno > 0)
-                                return -errno;
-                        if (z < 0)
-                                return -ERANGE;
-                        if (e == b)
-                                return -EINVAL;
-
-                        n = e - b;
-
+                        p = e + 1;
+                        p += strspn(p, DIGITS);
                 } else if (e == p)
                         return -EINVAL;
+                else
+                        p = e;
 
-                e += strspn(e, WHITESPACE);
-                p = extract_multiplier(e, &multiplier);
+                s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
+                if (s == p && *s != '\0')
+                        /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
+                        return -EINVAL;
 
-                something = true;
+                p = s;
 
+                if ((usec_t) l >= USEC_INFINITY / multiplier)
+                        return -ERANGE;
 
-                k = ((usec_t) -1) / multiplier;
-                if ((usec_t) l + 1 >= k || (usec_t) z >= k)
+                k = (usec_t) l * multiplier;
+                if (k >= USEC_INFINITY - r)
                         return -ERANGE;
 
-                k = (usec_t) z * multiplier;
+                r += k;
 
-                for (; n > 0; n--)
-                        k /= 10;
+                something = true;
 
-                k += (usec_t) l * multiplier;
-                if (k >= ((usec_t) -1) - r)
-                        return -ERANGE;
+                if (*e == '.') {
+                        usec_t m = multiplier / 10;
+                        const char *b;
 
-                r += k;
+                        for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
+                                k = (usec_t) (*b - '0') * m;
+                                if (k >= USEC_INFINITY - r)
+                                        return -ERANGE;
+
+                                r += k;
+                        }
+
+                        /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
+                        if (b == e + 1)
+                                return -EINVAL;
+                }
         }
 
         *usec = r;
@@ -1032,44 +1031,69 @@ int parse_sec_fix_0(const char *t, usec_t *ret) {
         return r;
 }
 
-int parse_nsec(const char *t, nsec_t *nsec) {
+int parse_sec_def_infinity(const char *t, usec_t *ret) {
+        t += strspn(t, WHITESPACE);
+        if (isempty(t)) {
+                *ret = USEC_INFINITY;
+                return 0;
+        }
+        return parse_sec(t, ret);
+}
+
+static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
         static const struct {
                 const char *suffix;
                 nsec_t nsec;
         } table[] = {
-                { "seconds", NSEC_PER_SEC },
-                { "second", NSEC_PER_SEC },
-                { "sec", NSEC_PER_SEC },
-                { "s", NSEC_PER_SEC },
+                { "seconds", NSEC_PER_SEC    },
+                { "second",  NSEC_PER_SEC    },
+                { "sec",     NSEC_PER_SEC    },
+                { "s",       NSEC_PER_SEC    },
                 { "minutes", NSEC_PER_MINUTE },
-                { "minute", NSEC_PER_MINUTE },
-                { "min", NSEC_PER_MINUTE },
-                { "months", NSEC_PER_MONTH },
-                { "month", NSEC_PER_MONTH },
-                { "msec", NSEC_PER_MSEC },
-                { "ms", NSEC_PER_MSEC },
-                { "m", NSEC_PER_MINUTE },
-                { "hours", NSEC_PER_HOUR },
-                { "hour", NSEC_PER_HOUR },
-                { "hr", NSEC_PER_HOUR },
-                { "h", NSEC_PER_HOUR },
-                { "days", NSEC_PER_DAY },
-                { "day", NSEC_PER_DAY },
-                { "d", NSEC_PER_DAY },
-                { "weeks", NSEC_PER_WEEK },
-                { "week", NSEC_PER_WEEK },
-                { "w", NSEC_PER_WEEK },
-                { "years", NSEC_PER_YEAR },
-                { "year", NSEC_PER_YEAR },
-                { "y", NSEC_PER_YEAR },
-                { "usec", NSEC_PER_USEC },
-                { "us", NSEC_PER_USEC },
-                { "µs", NSEC_PER_USEC },
-                { "nsec", 1ULL },
-                { "ns", 1ULL },
-                { "", 1ULL }, /* default is nsec */
+                { "minute",  NSEC_PER_MINUTE },
+                { "min",     NSEC_PER_MINUTE },
+                { "months",  NSEC_PER_MONTH  },
+                { "month",   NSEC_PER_MONTH  },
+                { "M",       NSEC_PER_MONTH  },
+                { "msec",    NSEC_PER_MSEC   },
+                { "ms",      NSEC_PER_MSEC   },
+                { "m",       NSEC_PER_MINUTE },
+                { "hours",   NSEC_PER_HOUR   },
+                { "hour",    NSEC_PER_HOUR   },
+                { "hr",      NSEC_PER_HOUR   },
+                { "h",       NSEC_PER_HOUR   },
+                { "days",    NSEC_PER_DAY    },
+                { "day",     NSEC_PER_DAY    },
+                { "d",       NSEC_PER_DAY    },
+                { "weeks",   NSEC_PER_WEEK   },
+                { "week",    NSEC_PER_WEEK   },
+                { "w",       NSEC_PER_WEEK   },
+                { "years",   NSEC_PER_YEAR   },
+                { "year",    NSEC_PER_YEAR   },
+                { "y",       NSEC_PER_YEAR   },
+                { "usec",    NSEC_PER_USEC   },
+                { "us",      NSEC_PER_USEC   },
+                { "µs",      NSEC_PER_USEC   },
+                { "nsec",    1ULL            },
+                { "ns",      1ULL            },
+                { "",        1ULL            }, /* default is nsec */
         };
+        size_t i;
+
+        for (i = 0; i < ELEMENTSOF(table); i++) {
+                char *e;
 
+                e = startswith(p, table[i].suffix);
+                if (e) {
+                        *multiplier = table[i].nsec;
+                        return e;
+                }
+        }
+
+        return p;
+}
+
+int parse_nsec(const char *t, nsec_t *nsec) {
         const char *p, *s;
         nsec_t r = 0;
         bool something = false;
@@ -1091,8 +1115,8 @@ int parse_nsec(const char *t, nsec_t *nsec) {
         }
 
         for (;;) {
-                long long l, z = 0;
-                size_t n = 0, i;
+                nsec_t multiplier = 1, k;
+                long long l;
                 char *e;
 
                 p += strspn(p, WHITESPACE);
@@ -1104,7 +1128,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
                         break;
                 }
 
-                if (*p == '-')
+                if (*p == '-') /* Don't allow "-0" */
                         return -ERANGE;
 
                 errno = 0;
@@ -1115,54 +1139,47 @@ int parse_nsec(const char *t, nsec_t *nsec) {
                         return -ERANGE;
 
                 if (*e == '.') {
-                        char *b = e + 1;
-
-                        if (IN_SET(*b, '-', '+') || isspace(*b))
-                                return -EINVAL;
-
-                        errno = 0;
-                        z = strtoll(b, &e, 10);
-                        if (errno > 0)
-                                return -errno;
-                        if (z < 0)
-                                return -ERANGE;
-                        if (e == b)
-                                return -EINVAL;
-
-                        n = e - b;
-
+                        p = e + 1;
+                        p += strspn(p, DIGITS);
                 } else if (e == p)
                         return -EINVAL;
+                else
+                        p = e;
 
-                e += strspn(e, WHITESPACE);
+                s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
+                if (s == p && *s != '\0')
+                        /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
+                        return -EINVAL;
 
-                for (i = 0; i < ELEMENTSOF(table); i++)
-                        if (startswith(e, table[i].suffix)) {
-                                nsec_t k;
+                p = s;
 
-                                k = ((nsec_t) -1) / table[i].nsec;
-                                if ((nsec_t) l + 1 >= k || (nsec_t) z >= k)
-                                        return -ERANGE;
+                if ((nsec_t) l >= NSEC_INFINITY / multiplier)
+                        return -ERANGE;
+
+                k = (nsec_t) l * multiplier;
+                if (k >= NSEC_INFINITY - r)
+                        return -ERANGE;
 
-                                k = (nsec_t) z * table[i].nsec;
+                r += k;
+
+                something = true;
 
-                                for (; n > 0; n--)
-                                        k /= 10;
+                if (*e == '.') {
+                        nsec_t m = multiplier / 10;
+                        const char *b;
 
-                                k += (nsec_t) l * table[i].nsec;
-                                if (k >= ((nsec_t) -1) - r)
+                        for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
+                                k = (nsec_t) (*b - '0') * m;
+                                if (k >= NSEC_INFINITY - r)
                                         return -ERANGE;
 
                                 r += k;
-                                p = e + strlen(table[i].suffix);
-
-                                something = true;
-                                break;
                         }
 
-                if (i >= ELEMENTSOF(table))
-                        return -EINVAL;
-
+                        /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
+                        if (b == e + 1)
+                                return -EINVAL;
+                }
         }
 
         *nsec = r;
@@ -1376,9 +1393,7 @@ int get_timezone(char **tz) {
         if (r < 0)
                 return r; /* returns EINVAL if not a symlink */
 
-        e = path_startswith(t, "/usr/share/zoneinfo/");
-        if (!e)
-                e = path_startswith(t, "../usr/share/zoneinfo/");
+        e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
         if (!e)
                 return -EINVAL;