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