LCOV - code coverage report
Current view: top level - basic - parse-util.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 371 422 87.9 %
Date: 2019-08-23 13:36:53 Functions: 25 28 89.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 269 372 72.3 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : #include <inttypes.h>
       5                 :            : #include <linux/oom.h>
       6                 :            : #include <locale.h>
       7                 :            : #include <net/if.h>
       8                 :            : #include <stdio.h>
       9                 :            : #include <stdlib.h>
      10                 :            : #include <string.h>
      11                 :            : #include <sys/socket.h>
      12                 :            : 
      13                 :            : #include "alloc-util.h"
      14                 :            : #include "errno-list.h"
      15                 :            : #include "extract-word.h"
      16                 :            : #include "locale-util.h"
      17                 :            : #include "macro.h"
      18                 :            : #include "missing.h"
      19                 :            : #include "parse-util.h"
      20                 :            : #include "process-util.h"
      21                 :            : #include "stat-util.h"
      22                 :            : #include "string-util.h"
      23                 :            : 
      24                 :        904 : int parse_boolean(const char *v) {
      25         [ -  + ]:        904 :         if (!v)
      26                 :          0 :                 return -EINVAL;
      27                 :            : 
      28   [ +  +  +  +  :        904 :         if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
          +  +  +  +  +  
                +  +  + ]
      29                 :        264 :                 return 1;
      30   [ +  +  +  +  :        640 :         else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
          +  +  +  +  +  
                +  +  + ]
      31                 :        312 :                 return 0;
      32                 :            : 
      33                 :        328 :         return -EINVAL;
      34                 :            : }
      35                 :            : 
      36                 :       1179 : int parse_pid(const char *s, pid_t* ret_pid) {
      37                 :       1179 :         unsigned long ul = 0;
      38                 :            :         pid_t pid;
      39                 :            :         int r;
      40                 :            : 
      41         [ -  + ]:       1179 :         assert(s);
      42         [ -  + ]:       1179 :         assert(ret_pid);
      43                 :            : 
      44                 :       1179 :         r = safe_atolu(s, &ul);
      45         [ +  + ]:       1179 :         if (r < 0)
      46                 :         60 :                 return r;
      47                 :            : 
      48                 :       1119 :         pid = (pid_t) ul;
      49                 :            : 
      50         [ -  + ]:       1119 :         if ((unsigned long) pid != ul)
      51                 :          0 :                 return -ERANGE;
      52                 :            : 
      53         [ +  + ]:       1119 :         if (!pid_is_valid(pid))
      54                 :          4 :                 return -ERANGE;
      55                 :            : 
      56                 :       1115 :         *ret_pid = pid;
      57                 :       1115 :         return 0;
      58                 :            : }
      59                 :            : 
      60                 :         64 : int parse_mode(const char *s, mode_t *ret) {
      61                 :            :         char *x;
      62                 :            :         long l;
      63                 :            : 
      64         [ -  + ]:         64 :         assert(s);
      65         [ -  + ]:         64 :         assert(ret);
      66                 :            : 
      67                 :         64 :         s += strspn(s, WHITESPACE);
      68         [ +  + ]:         64 :         if (s[0] == '-')
      69                 :          8 :                 return -ERANGE;
      70                 :            : 
      71                 :         56 :         errno = 0;
      72                 :         56 :         l = strtol(s, &x, 8);
      73         [ -  + ]:         56 :         if (errno > 0)
      74                 :          0 :                 return -errno;
      75   [ +  -  +  +  :         56 :         if (!x || x == s || *x != 0)
                   +  + ]
      76                 :         24 :                 return -EINVAL;
      77   [ +  -  +  + ]:         32 :         if (l < 0 || l  > 07777)
      78                 :          4 :                 return -ERANGE;
      79                 :            : 
      80                 :         28 :         *ret = (mode_t) l;
      81                 :         28 :         return 0;
      82                 :            : }
      83                 :            : 
      84                 :        844 : int parse_ifindex(const char *s, int *ret) {
      85                 :            :         int ifi, r;
      86                 :            : 
      87         [ -  + ]:        844 :         assert(s);
      88         [ -  + ]:        844 :         assert(ret);
      89                 :            : 
      90                 :        844 :         r = safe_atoi(s, &ifi);
      91         [ +  + ]:        844 :         if (r < 0)
      92                 :          8 :                 return r;
      93         [ -  + ]:        836 :         if (ifi <= 0)
      94                 :          0 :                 return -EINVAL;
      95                 :            : 
      96                 :        836 :         *ret = ifi;
      97                 :        836 :         return 0;
      98                 :            : }
      99                 :            : 
     100                 :          0 : int parse_ifindex_or_ifname(const char *s, int *ret) {
     101                 :            :         int r;
     102                 :            : 
     103         [ #  # ]:          0 :         assert(s);
     104         [ #  # ]:          0 :         assert(ret);
     105                 :            : 
     106                 :          0 :         r = parse_ifindex(s, ret);
     107         [ #  # ]:          0 :         if (r >= 0)
     108                 :          0 :                 return r;
     109                 :            : 
     110                 :          0 :         r = (int) if_nametoindex(s);
     111         [ #  # ]:          0 :         if (r <= 0)
     112                 :          0 :                 return -errno;
     113                 :            : 
     114                 :          0 :         *ret = r;
     115                 :          0 :         return 0;
     116                 :            : }
     117                 :            : 
     118                 :        112 : int parse_mtu(int family, const char *s, uint32_t *ret) {
     119                 :            :         uint64_t u;
     120                 :            :         size_t m;
     121                 :            :         int r;
     122                 :            : 
     123                 :        112 :         r = parse_size(s, 1024, &u);
     124         [ +  + ]:        112 :         if (r < 0)
     125                 :         28 :                 return r;
     126                 :            : 
     127         [ +  + ]:         84 :         if (u > UINT32_MAX)
     128                 :          8 :                 return -ERANGE;
     129                 :            : 
     130         [ +  + ]:         76 :         if (family == AF_INET6)
     131                 :         12 :                 m = IPV6_MIN_MTU; /* This is 1280 */
     132                 :            :         else
     133                 :         64 :                 m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */
     134                 :            : 
     135         [ +  + ]:         76 :         if (u < m)
     136                 :         16 :                 return -ERANGE;
     137                 :            : 
     138                 :         60 :         *ret = (uint32_t) u;
     139                 :         60 :         return 0;
     140                 :            : }
     141                 :            : 
     142                 :        352 : int parse_size(const char *t, uint64_t base, uint64_t *size) {
     143                 :            : 
     144                 :            :         /* Soo, sometimes we want to parse IEC binary suffixes, and
     145                 :            :          * sometimes SI decimal suffixes. This function can parse
     146                 :            :          * both. Which one is the right way depends on the
     147                 :            :          * context. Wikipedia suggests that SI is customary for
     148                 :            :          * hardware metrics and network speeds, while IEC is
     149                 :            :          * customary for most data sizes used by software and volatile
     150                 :            :          * (RAM) memory. Hence be careful which one you pick!
     151                 :            :          *
     152                 :            :          * In either case we use just K, M, G as suffix, and not Ki,
     153                 :            :          * Mi, Gi or so (as IEC would suggest). That's because that's
     154                 :            :          * frickin' ugly. But this means you really need to make sure
     155                 :            :          * to document which base you are parsing when you use this
     156                 :            :          * call. */
     157                 :            : 
     158                 :            :         struct table {
     159                 :            :                 const char *suffix;
     160                 :            :                 unsigned long long factor;
     161                 :            :         };
     162                 :            : 
     163                 :            :         static const struct table iec[] = {
     164                 :            :                 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
     165                 :            :                 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
     166                 :            :                 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
     167                 :            :                 { "G", 1024ULL*1024ULL*1024ULL },
     168                 :            :                 { "M", 1024ULL*1024ULL },
     169                 :            :                 { "K", 1024ULL },
     170                 :            :                 { "B", 1ULL },
     171                 :            :                 { "",  1ULL },
     172                 :            :         };
     173                 :            : 
     174                 :            :         static const struct table si[] = {
     175                 :            :                 { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
     176                 :            :                 { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
     177                 :            :                 { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
     178                 :            :                 { "G", 1000ULL*1000ULL*1000ULL },
     179                 :            :                 { "M", 1000ULL*1000ULL },
     180                 :            :                 { "K", 1000ULL },
     181                 :            :                 { "B", 1ULL },
     182                 :            :                 { "",  1ULL },
     183                 :            :         };
     184                 :            : 
     185                 :            :         const struct table *table;
     186                 :            :         const char *p;
     187                 :        352 :         unsigned long long r = 0;
     188                 :        352 :         unsigned n_entries, start_pos = 0;
     189                 :            : 
     190         [ -  + ]:        352 :         assert(t);
     191   [ +  -  -  + ]:        352 :         assert(IN_SET(base, 1000, 1024));
     192         [ -  + ]:        352 :         assert(size);
     193                 :            : 
     194         [ +  + ]:        352 :         if (base == 1000) {
     195                 :         36 :                 table = si;
     196                 :         36 :                 n_entries = ELEMENTSOF(si);
     197                 :            :         } else {
     198                 :        316 :                 table = iec;
     199                 :        316 :                 n_entries = ELEMENTSOF(iec);
     200                 :            :         }
     201                 :            : 
     202                 :        352 :         p = t;
     203                 :            :         do {
     204                 :            :                 unsigned long long l, tmp;
     205                 :        448 :                 double frac = 0;
     206                 :            :                 char *e;
     207                 :            :                 unsigned i;
     208                 :            : 
     209                 :        448 :                 p += strspn(p, WHITESPACE);
     210                 :            : 
     211                 :        448 :                 errno = 0;
     212                 :        448 :                 l = strtoull(p, &e, 10);
     213         [ +  + ]:        448 :                 if (errno > 0)
     214                 :        112 :                         return -errno;
     215         [ +  + ]:        440 :                 if (e == p)
     216                 :         68 :                         return -EINVAL;
     217         [ +  + ]:        372 :                 if (*p == '-')
     218                 :         28 :                         return -ERANGE;
     219                 :            : 
     220         [ +  + ]:        344 :                 if (*e == '.') {
     221                 :         76 :                         e++;
     222                 :            : 
     223                 :            :                         /* strtoull() itself would accept space/+/- */
     224   [ +  +  +  - ]:         76 :                         if (*e >= '0' && *e <= '9') {
     225                 :            :                                 unsigned long long l2;
     226                 :            :                                 char *e2;
     227                 :            : 
     228                 :         68 :                                 l2 = strtoull(e, &e2, 10);
     229         [ -  + ]:         68 :                                 if (errno > 0)
     230                 :          0 :                                         return -errno;
     231                 :            : 
     232                 :            :                                 /* Ignore failure. E.g. 10.M is valid */
     233                 :         68 :                                 frac = l2;
     234         [ +  + ]:        160 :                                 for (; e < e2; e++)
     235                 :         92 :                                         frac /= 10;
     236                 :            :                         }
     237                 :            :                 }
     238                 :            : 
     239                 :        344 :                 e += strspn(e, WHITESPACE);
     240                 :            : 
     241         [ +  + ]:       2056 :                 for (i = start_pos; i < n_entries; i++)
     242         [ +  + ]:       2052 :                         if (startswith(e, table[i].suffix))
     243                 :        340 :                                 break;
     244                 :            : 
     245         [ +  + ]:        344 :                 if (i >= n_entries)
     246                 :          4 :                         return -EINVAL;
     247                 :            : 
     248         [ +  + ]:        340 :                 if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
     249                 :          4 :                         return -ERANGE;
     250                 :            : 
     251                 :        336 :                 tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
     252         [ -  + ]:        336 :                 if (tmp > ULLONG_MAX - r)
     253                 :          0 :                         return -ERANGE;
     254                 :            : 
     255                 :        336 :                 r += tmp;
     256                 :            :                 if ((unsigned long long) (uint64_t) r != r)
     257                 :            :                         return -ERANGE;
     258                 :            : 
     259                 :        336 :                 p = e + strlen(table[i].suffix);
     260                 :            : 
     261                 :        336 :                 start_pos = i + 1;
     262                 :            : 
     263         [ +  + ]:        336 :         } while (*p);
     264                 :            : 
     265                 :        240 :         *size = r;
     266                 :            : 
     267                 :        240 :         return 0;
     268                 :            : }
     269                 :            : 
     270                 :        416 : int parse_range(const char *t, unsigned *lower, unsigned *upper) {
     271                 :        416 :         _cleanup_free_ char *word = NULL;
     272                 :            :         unsigned l, u;
     273                 :            :         int r;
     274                 :            : 
     275         [ -  + ]:        416 :         assert(lower);
     276         [ -  + ]:        416 :         assert(upper);
     277                 :            : 
     278                 :            :         /* Extract the lower bound. */
     279                 :        416 :         r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
     280         [ -  + ]:        416 :         if (r < 0)
     281                 :          0 :                 return r;
     282         [ -  + ]:        416 :         if (r == 0)
     283                 :          0 :                 return -EINVAL;
     284                 :            : 
     285                 :        416 :         r = safe_atou(word, &l);
     286         [ +  + ]:        416 :         if (r < 0)
     287                 :         72 :                 return r;
     288                 :            : 
     289                 :            :         /* Check for the upper bound and extract it if needed */
     290         [ +  + ]:        344 :         if (!t)
     291                 :            :                 /* Single number with no dashes. */
     292                 :        208 :                 u = l;
     293         [ +  + ]:        136 :         else if (!*t)
     294                 :            :                 /* Trailing dash is an error. */
     295                 :          4 :                 return -EINVAL;
     296                 :            :         else {
     297                 :        132 :                 r = safe_atou(t, &u);
     298         [ +  + ]:        132 :                 if (r < 0)
     299                 :         44 :                         return r;
     300                 :            :         }
     301                 :            : 
     302                 :        296 :         *lower = l;
     303                 :        296 :         *upper = u;
     304                 :        296 :         return 0;
     305                 :            : }
     306                 :            : 
     307                 :        120 : int parse_errno(const char *t) {
     308                 :            :         int r, e;
     309                 :            : 
     310         [ -  + ]:        120 :         assert(t);
     311                 :            : 
     312                 :        120 :         r = errno_from_name(t);
     313         [ +  + ]:        120 :         if (r > 0)
     314                 :         16 :                 return r;
     315                 :            : 
     316                 :        104 :         r = safe_atoi(t, &e);
     317         [ +  + ]:        104 :         if (r < 0)
     318                 :         60 :                 return r;
     319                 :            : 
     320                 :            :         /* 0 is also allowed here */
     321   [ +  +  +  + ]:         44 :         if (!errno_is_valid(e) && e != 0)
     322                 :         20 :                 return -ERANGE;
     323                 :            : 
     324                 :         24 :         return e;
     325                 :            : }
     326                 :            : 
     327                 :         64 : int parse_syscall_and_errno(const char *in, char **name, int *error) {
     328                 :         64 :         _cleanup_free_ char *n = NULL;
     329                 :            :         char *p;
     330                 :         64 :         int e = -1;
     331                 :            : 
     332         [ -  + ]:         64 :         assert(in);
     333         [ -  + ]:         64 :         assert(name);
     334         [ -  + ]:         64 :         assert(error);
     335                 :            : 
     336                 :            :         /*
     337                 :            :          * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255".
     338                 :            :          * If errno is omitted, then error is set to -1.
     339                 :            :          * Empty syscall name is not allowed.
     340                 :            :          * Here, we do not check that the syscall name is valid or not.
     341                 :            :          */
     342                 :            : 
     343                 :         64 :         p = strchr(in, ':');
     344         [ +  + ]:         64 :         if (p) {
     345                 :         56 :                 e = parse_errno(p + 1);
     346         [ +  + ]:         56 :                 if (e < 0)
     347                 :         36 :                         return e;
     348                 :            : 
     349                 :         20 :                 n = strndup(in, p - in);
     350                 :            :         } else
     351                 :          8 :                 n = strdup(in);
     352                 :            : 
     353         [ -  + ]:         28 :         if (!n)
     354                 :          0 :                 return -ENOMEM;
     355                 :            : 
     356         [ +  + ]:         28 :         if (isempty(n))
     357                 :          8 :                 return -EINVAL;
     358                 :            : 
     359                 :         20 :         *error = e;
     360                 :         20 :         *name = TAKE_PTR(n);
     361                 :            : 
     362                 :         20 :         return 0;
     363                 :            : }
     364                 :            : 
     365                 :     419236 : int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
     366                 :     419236 :         char *x = NULL;
     367                 :            :         unsigned long l;
     368                 :            : 
     369         [ -  + ]:     419236 :         assert(s);
     370         [ -  + ]:     419236 :         assert(ret_u);
     371         [ -  + ]:     419236 :         assert(base <= 16);
     372                 :            : 
     373                 :            :         /* strtoul() is happy to parse negative values, and silently
     374                 :            :          * converts them to unsigned values without generating an
     375                 :            :          * error. We want a clean error, hence let's look for the "-"
     376                 :            :          * prefix on our own, and generate an error. But let's do so
     377                 :            :          * only after strtoul() validated that the string is clean
     378                 :            :          * otherwise, so that we return EINVAL preferably over
     379                 :            :          * ERANGE. */
     380                 :            : 
     381                 :     419236 :         s += strspn(s, WHITESPACE);
     382                 :            : 
     383                 :     419236 :         errno = 0;
     384                 :     419236 :         l = strtoul(s, &x, base);
     385         [ +  + ]:     419236 :         if (errno > 0)
     386                 :          8 :                 return -errno;
     387   [ +  -  +  +  :     419228 :         if (!x || x == s || *x != 0)
                   +  + ]
     388                 :        452 :                 return -EINVAL;
     389         [ +  + ]:     418776 :         if (s[0] == '-')
     390                 :         16 :                 return -ERANGE;
     391         [ -  + ]:     418760 :         if ((unsigned long) (unsigned) l != l)
     392                 :          0 :                 return -ERANGE;
     393                 :            : 
     394                 :     418760 :         *ret_u = (unsigned) l;
     395                 :     418760 :         return 0;
     396                 :            : }
     397                 :            : 
     398                 :       3472 : int safe_atoi(const char *s, int *ret_i) {
     399                 :       3472 :         char *x = NULL;
     400                 :            :         long l;
     401                 :            : 
     402         [ -  + ]:       3472 :         assert(s);
     403         [ -  + ]:       3472 :         assert(ret_i);
     404                 :            : 
     405                 :       3472 :         errno = 0;
     406                 :       3472 :         l = strtol(s, &x, 0);
     407         [ +  + ]:       3472 :         if (errno > 0)
     408                 :          8 :                 return -errno;
     409   [ +  -  +  +  :       3464 :         if (!x || x == s || *x != 0)
                   +  + ]
     410                 :        924 :                 return -EINVAL;
     411         [ +  + ]:       2540 :         if ((long) (int) l != l)
     412                 :         12 :                 return -ERANGE;
     413                 :            : 
     414                 :       2528 :         *ret_i = (int) l;
     415                 :       2528 :         return 0;
     416                 :            : }
     417                 :            : 
     418                 :      12626 : int safe_atollu(const char *s, long long unsigned *ret_llu) {
     419                 :      12626 :         char *x = NULL;
     420                 :            :         unsigned long long l;
     421                 :            : 
     422         [ -  + ]:      12626 :         assert(s);
     423         [ -  + ]:      12626 :         assert(ret_llu);
     424                 :            : 
     425                 :      12626 :         s += strspn(s, WHITESPACE);
     426                 :            : 
     427                 :      12626 :         errno = 0;
     428                 :      12626 :         l = strtoull(s, &x, 0);
     429         [ +  + ]:      12626 :         if (errno > 0)
     430                 :          8 :                 return -errno;
     431   [ +  -  +  +  :      12618 :         if (!x || x == s || *x != 0)
                   +  + ]
     432                 :         80 :                 return -EINVAL;
     433         [ +  + ]:      12538 :         if (*s == '-')
     434                 :         12 :                 return -ERANGE;
     435                 :            : 
     436                 :      12526 :         *ret_llu = l;
     437                 :      12526 :         return 0;
     438                 :            : }
     439                 :            : 
     440                 :         80 : int safe_atolli(const char *s, long long int *ret_lli) {
     441                 :         80 :         char *x = NULL;
     442                 :            :         long long l;
     443                 :            : 
     444         [ -  + ]:         80 :         assert(s);
     445         [ -  + ]:         80 :         assert(ret_lli);
     446                 :            : 
     447                 :         80 :         errno = 0;
     448                 :         80 :         l = strtoll(s, &x, 0);
     449         [ +  + ]:         80 :         if (errno > 0)
     450                 :         16 :                 return -errno;
     451   [ +  -  +  +  :         64 :         if (!x || x == s || *x != 0)
                   +  + ]
     452                 :         32 :                 return -EINVAL;
     453                 :            : 
     454                 :         32 :         *ret_lli = l;
     455                 :         32 :         return 0;
     456                 :            : }
     457                 :            : 
     458                 :        460 : int safe_atou8(const char *s, uint8_t *ret) {
     459                 :        460 :         char *x = NULL;
     460                 :            :         unsigned long l;
     461                 :            : 
     462         [ -  + ]:        460 :         assert(s);
     463         [ -  + ]:        460 :         assert(ret);
     464                 :            : 
     465                 :        460 :         s += strspn(s, WHITESPACE);
     466                 :            : 
     467                 :        460 :         errno = 0;
     468                 :        460 :         l = strtoul(s, &x, 0);
     469         [ -  + ]:        460 :         if (errno > 0)
     470                 :          0 :                 return -errno;
     471   [ +  -  +  +  :        460 :         if (!x || x == s || *x != 0)
                   -  + ]
     472                 :          4 :                 return -EINVAL;
     473         [ +  + ]:        456 :         if (s[0] == '-')
     474                 :         20 :                 return -ERANGE;
     475         [ +  + ]:        436 :         if ((unsigned long) (uint8_t) l != l)
     476                 :          4 :                 return -ERANGE;
     477                 :            : 
     478                 :        432 :         *ret = (uint8_t) l;
     479                 :        432 :         return 0;
     480                 :            : }
     481                 :            : 
     482                 :        208 : int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
     483                 :        208 :         char *x = NULL;
     484                 :            :         unsigned long l;
     485                 :            : 
     486         [ -  + ]:        208 :         assert(s);
     487         [ -  + ]:        208 :         assert(ret);
     488         [ -  + ]:        208 :         assert(base <= 16);
     489                 :            : 
     490                 :        208 :         s += strspn(s, WHITESPACE);
     491                 :            : 
     492                 :        208 :         errno = 0;
     493                 :        208 :         l = strtoul(s, &x, base);
     494         [ -  + ]:        208 :         if (errno > 0)
     495                 :          0 :                 return -errno;
     496   [ +  -  +  +  :        208 :         if (!x || x == s || *x != 0)
                   +  + ]
     497                 :         56 :                 return -EINVAL;
     498         [ +  + ]:        152 :         if (s[0] == '-')
     499                 :         16 :                 return -ERANGE;
     500         [ +  + ]:        136 :         if ((unsigned long) (uint16_t) l != l)
     501                 :         20 :                 return -ERANGE;
     502                 :            : 
     503                 :        116 :         *ret = (uint16_t) l;
     504                 :        116 :         return 0;
     505                 :            : }
     506                 :            : 
     507                 :         40 : int safe_atoi16(const char *s, int16_t *ret) {
     508                 :         40 :         char *x = NULL;
     509                 :            :         long l;
     510                 :            : 
     511         [ -  + ]:         40 :         assert(s);
     512         [ -  + ]:         40 :         assert(ret);
     513                 :            : 
     514                 :         40 :         errno = 0;
     515                 :         40 :         l = strtol(s, &x, 0);
     516         [ -  + ]:         40 :         if (errno > 0)
     517                 :          0 :                 return -errno;
     518   [ +  -  +  +  :         40 :         if (!x || x == s || *x != 0)
                   +  + ]
     519                 :         16 :                 return -EINVAL;
     520         [ +  + ]:         24 :         if ((long) (int16_t) l != l)
     521                 :          8 :                 return -ERANGE;
     522                 :            : 
     523                 :         16 :         *ret = (int16_t) l;
     524                 :         16 :         return 0;
     525                 :            : }
     526                 :            : 
     527                 :         40 : int safe_atod(const char *s, double *ret_d) {
     528                 :         40 :         _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
     529                 :         40 :         char *x = NULL;
     530                 :         40 :         double d = 0;
     531                 :            : 
     532         [ -  + ]:         40 :         assert(s);
     533         [ -  + ]:         40 :         assert(ret_d);
     534                 :            : 
     535                 :         40 :         loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
     536         [ -  + ]:         40 :         if (loc == (locale_t) 0)
     537                 :          0 :                 return -errno;
     538                 :            : 
     539                 :         40 :         errno = 0;
     540                 :         40 :         d = strtod_l(s, &x, loc);
     541         [ -  + ]:         40 :         if (errno > 0)
     542                 :          0 :                 return -errno;
     543   [ +  -  +  +  :         40 :         if (!x || x == s || *x != 0)
                   +  + ]
     544                 :         28 :                 return -EINVAL;
     545                 :            : 
     546                 :         12 :         *ret_d = (double) d;
     547                 :         12 :         return 0;
     548                 :            : }
     549                 :            : 
     550                 :        821 : int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
     551                 :            :         size_t i;
     552                 :        821 :         unsigned val = 0;
     553                 :            :         const char *s;
     554                 :            : 
     555                 :        821 :         s = *p;
     556                 :            : 
     557                 :            :         /* accept any number of digits, strtoull is limited to 19 */
     558         [ +  + ]:       5507 :         for (i=0; i < digits; i++,s++) {
     559   [ +  +  -  + ]:       4742 :                 if (*s < '0' || *s > '9') {
     560         [ -  + ]:         56 :                         if (i == 0)
     561                 :          0 :                                 return -EINVAL;
     562                 :            : 
     563                 :            :                         /* too few digits, pad with 0 */
     564         [ +  + ]:        296 :                         for (; i < digits; i++)
     565                 :        240 :                                 val *= 10;
     566                 :            : 
     567                 :         56 :                         break;
     568                 :            :                 }
     569                 :            : 
     570                 :       4686 :                 val *= 10;
     571                 :       4686 :                 val += *s - '0';
     572                 :            :         }
     573                 :            : 
     574                 :            :         /* maybe round up */
     575   [ +  +  +  - ]:        821 :         if (*s >= '5' && *s <= '9')
     576                 :         16 :                 val++;
     577                 :            : 
     578                 :        821 :         s += strspn(s, DIGITS);
     579                 :            : 
     580                 :        821 :         *p = s;
     581                 :        821 :         *res = val;
     582                 :            : 
     583                 :        821 :         return 0;
     584                 :            : }
     585                 :            : 
     586                 :         72 : int parse_percent_unbounded(const char *p) {
     587                 :            :         const char *pc, *n;
     588                 :            :         int r, v;
     589                 :            : 
     590                 :         72 :         pc = endswith(p, "%");
     591         [ +  + ]:         72 :         if (!pc)
     592                 :         28 :                 return -EINVAL;
     593                 :            : 
     594                 :         44 :         n = strndupa(p, pc - p);
     595                 :         44 :         r = safe_atoi(n, &v);
     596         [ +  + ]:         44 :         if (r < 0)
     597                 :         16 :                 return r;
     598         [ +  + ]:         28 :         if (v < 0)
     599                 :          4 :                 return -ERANGE;
     600                 :            : 
     601                 :         24 :         return v;
     602                 :            : }
     603                 :            : 
     604                 :         64 : int parse_percent(const char *p) {
     605                 :            :         int v;
     606                 :            : 
     607                 :         64 :         v = parse_percent_unbounded(p);
     608         [ +  + ]:         64 :         if (v > 100)
     609                 :          4 :                 return -ERANGE;
     610                 :            : 
     611                 :         60 :         return v;
     612                 :            : }
     613                 :            : 
     614                 :        184 : int parse_permille_unbounded(const char *p) {
     615                 :            :         const char *pc, *pm, *dot, *n;
     616                 :            :         int r, q, v;
     617                 :            : 
     618                 :        184 :         pm = endswith(p, "‰");
     619         [ +  + ]:        184 :         if (pm) {
     620                 :         60 :                 n = strndupa(p, pm - p);
     621                 :         60 :                 r = safe_atoi(n, &v);
     622         [ +  + ]:         60 :                 if (r < 0)
     623                 :         28 :                         return r;
     624         [ +  + ]:         32 :                 if (v < 0)
     625                 :          4 :                         return -ERANGE;
     626                 :            :         } else {
     627                 :        124 :                 pc = endswith(p, "%");
     628         [ +  + ]:        124 :                 if (!pc)
     629                 :         60 :                         return -EINVAL;
     630                 :            : 
     631                 :         64 :                 dot = memchr(p, '.', pc - p);
     632         [ +  + ]:         64 :                 if (dot) {
     633         [ +  + ]:         24 :                         if (dot + 2 != pc)
     634                 :          4 :                                 return -EINVAL;
     635   [ +  -  -  + ]:         20 :                         if (dot[1] < '0' || dot[1] > '9')
     636                 :          0 :                                 return -EINVAL;
     637                 :         20 :                         q = dot[1] - '0';
     638                 :         20 :                         n = strndupa(p, dot - p);
     639                 :            :                 } else {
     640                 :         40 :                         q = 0;
     641                 :         40 :                         n = strndupa(p, pc - p);
     642                 :            :                 }
     643                 :         60 :                 r = safe_atoi(n, &v);
     644         [ +  + ]:         60 :                 if (r < 0)
     645                 :         12 :                         return r;
     646         [ +  + ]:         48 :                 if (v < 0)
     647                 :          4 :                         return -ERANGE;
     648         [ +  + ]:         44 :                 if (v > (INT_MAX - q) / 10)
     649                 :         12 :                         return -ERANGE;
     650                 :            : 
     651                 :         32 :                 v = v * 10 + q;
     652                 :            :         }
     653                 :            : 
     654                 :         60 :         return v;
     655                 :            : }
     656                 :            : 
     657                 :        136 : int parse_permille(const char *p) {
     658                 :            :         int v;
     659                 :            : 
     660                 :        136 :         v = parse_permille_unbounded(p);
     661         [ +  + ]:        136 :         if (v > 1000)
     662                 :          8 :                 return -ERANGE;
     663                 :            : 
     664                 :        128 :         return v;
     665                 :            : }
     666                 :            : 
     667                 :         84 : int parse_nice(const char *p, int *ret) {
     668                 :            :         int n, r;
     669                 :            : 
     670                 :         84 :         r = safe_atoi(p, &n);
     671         [ +  + ]:         84 :         if (r < 0)
     672                 :         16 :                 return r;
     673                 :            : 
     674         [ +  + ]:         68 :         if (!nice_is_valid(n))
     675                 :         24 :                 return -ERANGE;
     676                 :            : 
     677                 :         44 :         *ret = n;
     678                 :         44 :         return 0;
     679                 :            : }
     680                 :            : 
     681                 :        132 : int parse_ip_port(const char *s, uint16_t *ret) {
     682                 :            :         uint16_t l;
     683                 :            :         int r;
     684                 :            : 
     685                 :        132 :         r = safe_atou16(s, &l);
     686         [ +  + ]:        132 :         if (r < 0)
     687                 :         36 :                 return r;
     688                 :            : 
     689         [ +  + ]:         96 :         if (l == 0)
     690                 :         12 :                 return -EINVAL;
     691                 :            : 
     692                 :         84 :         *ret = (uint16_t) l;
     693                 :            : 
     694                 :         84 :         return 0;
     695                 :            : }
     696                 :            : 
     697                 :          0 : int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
     698                 :            :         unsigned l, h;
     699                 :            :         int r;
     700                 :            : 
     701                 :          0 :         r = parse_range(s, &l, &h);
     702         [ #  # ]:          0 :         if (r < 0)
     703                 :          0 :                 return r;
     704                 :            : 
     705   [ #  #  #  #  :          0 :         if (l <= 0 || l > 65535 || h <= 0 || h > 65535)
             #  #  #  # ]
     706                 :          0 :                 return -EINVAL;
     707                 :            : 
     708         [ #  # ]:          0 :         if (h < l)
     709                 :          0 :                 return -EINVAL;
     710                 :            : 
     711                 :          0 :         *low = l;
     712                 :          0 :         *high = h;
     713                 :            : 
     714                 :          0 :         return 0;
     715                 :            : }
     716                 :            : 
     717                 :       1952 : int parse_dev(const char *s, dev_t *ret) {
     718                 :            :         const char *major;
     719                 :            :         unsigned x, y;
     720                 :            :         size_t n;
     721                 :            :         int r;
     722                 :            : 
     723                 :       1952 :         n = strspn(s, DIGITS);
     724         [ +  + ]:       1952 :         if (n == 0)
     725                 :         16 :                 return -EINVAL;
     726         [ +  + ]:       1936 :         if (s[n] != ':')
     727                 :          8 :                 return -EINVAL;
     728                 :            : 
     729                 :       1928 :         major = strndupa(s, n);
     730                 :       1928 :         r = safe_atou(major, &x);
     731         [ -  + ]:       1928 :         if (r < 0)
     732                 :          0 :                 return r;
     733                 :            : 
     734                 :       1928 :         r = safe_atou(s + n + 1, &y);
     735         [ +  + ]:       1928 :         if (r < 0)
     736                 :          4 :                 return r;
     737                 :            : 
     738   [ +  -  +  -  :       1924 :         if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
          +  -  +  -  +  
                -  -  + ]
     739                 :          0 :                 return -ERANGE;
     740                 :            : 
     741                 :       1924 :         *ret = makedev(x, y);
     742                 :       1924 :         return 0;
     743                 :            : }
     744                 :            : 
     745                 :          0 : int parse_oom_score_adjust(const char *s, int *ret) {
     746                 :            :         int r, v;
     747                 :            : 
     748         [ #  # ]:          0 :         assert(s);
     749         [ #  # ]:          0 :         assert(ret);
     750                 :            : 
     751                 :          0 :         r = safe_atoi(s, &v);
     752         [ #  # ]:          0 :         if (r < 0)
     753                 :          0 :                 return r;
     754                 :            : 
     755   [ #  #  #  # ]:          0 :         if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
     756                 :          0 :                 return -ERANGE;
     757                 :            : 
     758                 :          0 :         *ret = v;
     759                 :          0 :         return 0;
     760                 :            : }

Generated by: LCOV version 1.14