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