]> 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 1ee57836803fb6d4de82576eb626379bbaae3236..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);
@@ -67,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)
@@ -81,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
@@ -149,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++;
@@ -168,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 */
@@ -294,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;
 
@@ -316,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;
 
@@ -334,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;
@@ -353,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;
@@ -368,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;
 
@@ -388,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;
 
@@ -410,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;
 
@@ -435,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;
+}