]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/parse-util.c
resolved: cache stringified transaction key once per transaction
[thirdparty/systemd.git] / src / basic / parse-util.c
index 2437fee60cc729b27cf16c42f2e24c82e233b9fd..618ef5d56430bc02543f6b016ca48bca371b91d3 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <errno.h>
+#include <inttypes.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xlocale.h>
+
+#include "alloc-util.h"
+#include "extract-word.h"
+#include "macro.h"
 #include "parse-util.h"
 #include "string-util.h"
-#include "util.h"
 
 int parse_boolean(const char *v) {
         assert(v);
@@ -65,11 +75,14 @@ int parse_mode(const char *s, mode_t *ret) {
         assert(s);
         assert(ret);
 
+        s += strspn(s, WHITESPACE);
+        if (s[0] == '-')
+                return -ERANGE;
+
         errno = 0;
         l = strtol(s, &x, 8);
         if (errno != 0)
                 return -errno;
-
         if (!x || x == s || *x)
                 return -EINVAL;
         if (l < 0 || l  > 07777)
@@ -79,6 +92,19 @@ int parse_mode(const char *s, mode_t *ret) {
         return 0;
 }
 
+int parse_ifindex(const char *s, int *ret) {
+        int ifi, r;
+
+        r = safe_atoi(s, &ifi);
+        if (r < 0)
+                return r;
+        if (ifi <= 0)
+                return -EINVAL;
+
+        *ret = ifi;
+        return 0;
+}
+
 int parse_size(const char *t, uint64_t base, uint64_t *size) {
 
         /* Soo, sometimes we want to parse IEC binary suffixes, and
@@ -147,15 +173,15 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
                 unsigned i;
 
                 p += strspn(p, WHITESPACE);
-                if (*p == '-')
-                        return -ERANGE;
 
                 errno = 0;
                 l = strtoull(p, &e, 10);
-                if (errno > 0)
+                if (errno != 0)
                         return -errno;
                 if (e == p)
                         return -EINVAL;
+                if (*p == '-')
+                        return -ERANGE;
 
                 if (*e == '.') {
                         e++;
@@ -166,7 +192,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
                                 char *e2;
 
                                 l2 = strtoull(e, &e2, 10);
-                                if (errno > 0)
+                                if (errno != 0)
                                         return -errno;
 
                                 /* Ignore failure. E.g. 10.M is valid */
@@ -207,6 +233,43 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
         return 0;
 }
 
+int parse_range(const char *t, unsigned *lower, unsigned *upper) {
+        _cleanup_free_ char *word = NULL;
+        unsigned l, u;
+        int r;
+
+        assert(lower);
+        assert(upper);
+
+        /* Extract the lower bound. */
+        r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EINVAL;
+
+        r = safe_atou(word, &l);
+        if (r < 0)
+                return r;
+
+        /* Check for the upper bound and extract it if needed */
+        if (!t)
+                /* Single number with no dashes. */
+                u = l;
+        else if (!*t)
+                /* Trailing dash is an error. */
+                return -EINVAL;
+        else {
+                r = safe_atou(t, &u);
+                if (r < 0)
+                        return r;
+        }
+
+        *lower = l;
+        *upper = u;
+        return 0;
+}
+
 char *format_bytes(char *buf, size_t l, uint64_t t) {
         unsigned i;
 
@@ -255,12 +318,24 @@ int safe_atou(const char *s, unsigned *ret_u) {
         assert(s);
         assert(ret_u);
 
-        errno = 0;
-        l = strtoul(s, &x, 0);
+        /* strtoul() is happy to parse negative values, and silently
+         * converts them to unsigned values without generating an
+         * error. We want a clean error, hence let's look for the "-"
+         * prefix on our own, and generate an error. But let's do so
+         * only after strtoul() validated that the string is clean
+         * otherwise, so that we return EINVAL preferably over
+         * ERANGE. */
 
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
+        s += strspn(s, WHITESPACE);
 
+        errno = 0;
+        l = strtoul(s, &x, 0);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (s[0] == '-')
+                return -ERANGE;
         if ((unsigned long) (unsigned) l != l)
                 return -ERANGE;
 
@@ -277,10 +352,10 @@ int safe_atoi(const char *s, int *ret_i) {
 
         errno = 0;
         l = strtol(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
         if ((long) (int) l != l)
                 return -ERANGE;
 
@@ -295,11 +370,16 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
         assert(s);
         assert(ret_llu);
 
+        s += strspn(s, WHITESPACE);
+
         errno = 0;
         l = strtoull(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno ? -errno : -EINVAL;
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (*s == '-')
+                return -ERANGE;
 
         *ret_llu = l;
         return 0;
@@ -314,9 +394,10 @@ int safe_atolli(const char *s, long long int *ret_lli) {
 
         errno = 0;
         l = strtoll(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno ? -errno : -EINVAL;
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
 
         *ret_lli = l;
         return 0;
@@ -329,12 +410,16 @@ int safe_atou8(const char *s, uint8_t *ret) {
         assert(s);
         assert(ret);
 
+        s += strspn(s, WHITESPACE);
+
         errno = 0;
         l = strtoul(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (s[0] == '-')
+                return -ERANGE;
         if ((unsigned long) (uint8_t) l != l)
                 return -ERANGE;
 
@@ -349,12 +434,16 @@ int safe_atou16(const char *s, uint16_t *ret) {
         assert(s);
         assert(ret);
 
+        s += strspn(s, WHITESPACE);
+
         errno = 0;
         l = strtoul(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (s[0] == '-')
+                return -ERANGE;
         if ((unsigned long) (uint16_t) l != l)
                 return -ERANGE;
 
@@ -371,10 +460,10 @@ int safe_atoi16(const char *s, int16_t *ret) {
 
         errno = 0;
         l = strtol(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
         if ((long) (int16_t) l != l)
                 return -ERANGE;
 
@@ -396,13 +485,52 @@ int safe_atod(const char *s, double *ret_d) {
 
         errno = 0;
         d = strtod_l(s, &x, loc);
-
-        if (!x || x == s || *x || errno) {
+        if (errno != 0) {
                 freelocale(loc);
-                return errno ? -errno : -EINVAL;
+                return -errno;
+        }
+        if (!x || x == s || *x) {
+                freelocale(loc);
+                return -EINVAL;
         }
 
         freelocale(loc);
         *ret_d = (double) d;
         return 0;
 }
+
+int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
+        size_t i;
+        unsigned val = 0;
+        const char *s;
+
+        s = *p;
+
+        /* accept any number of digits, strtoull is limted to 19 */
+        for(i=0; i < digits; i++,s++) {
+                if (*s < '0' || *s > '9') {
+                        if (i == 0)
+                                return -EINVAL;
+
+                        /* too few digits, pad with 0 */
+                        for (; i < digits; i++)
+                                val *= 10;
+
+                        break;
+                }
+
+                val *= 10;
+                val += *s - '0';
+        }
+
+        /* maybe round up */
+        if (*s >= '5' && *s <= '9')
+                val++;
+
+        s += strspn(s, DIGITS);
+
+        *p = s;
+        *res = val;
+
+        return 0;
+}