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