]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/parse-util.c
network: add SuppressPrefixLength option to RoutingPolicyRule (#14736)
[thirdparty/systemd.git] / src / basic / parse-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
6bedfcbb 2
11c3a366
TA
3#include <errno.h>
4#include <inttypes.h>
49f61033 5#include <linux/oom.h>
88465a4e 6#include <net/if.h>
11c3a366
TA
7#include <stdio.h>
8#include <stdlib.h>
f91c6093 9#include <sys/socket.h>
11c3a366 10
28cb17ef 11#include "alloc-util.h"
cf26c4a7 12#include "errno-list.h"
28cb17ef 13#include "extract-word.h"
e520e0fc 14#include "locale-util.h"
11c3a366 15#include "macro.h"
f5947a5e 16#include "missing_network.h"
93cc7779 17#include "parse-util.h"
41bf0590 18#include "process-util.h"
de06c0cf 19#include "stat-util.h"
6bedfcbb 20#include "string-util.h"
6bedfcbb
LP
21
22int parse_boolean(const char *v) {
b06f0cc6
LP
23 if (!v)
24 return -EINVAL;
6bedfcbb
LP
25
26 if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
27 return 1;
28 else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
29 return 0;
30
31 return -EINVAL;
32}
33
34int parse_pid(const char *s, pid_t* ret_pid) {
35 unsigned long ul = 0;
36 pid_t pid;
37 int r;
38
39 assert(s);
40 assert(ret_pid);
41
42 r = safe_atolu(s, &ul);
43 if (r < 0)
44 return r;
45
46 pid = (pid_t) ul;
47
48 if ((unsigned long) pid != ul)
49 return -ERANGE;
50
54191eb3 51 if (!pid_is_valid(pid))
6bedfcbb
LP
52 return -ERANGE;
53
54 *ret_pid = pid;
55 return 0;
56}
57
58int parse_mode(const char *s, mode_t *ret) {
59 char *x;
60 long l;
61
62 assert(s);
63 assert(ret);
64
2d49a208
LP
65 s += strspn(s, WHITESPACE);
66 if (s[0] == '-')
67 return -ERANGE;
68
6bedfcbb
LP
69 errno = 0;
70 l = strtol(s, &x, 8);
b3267152 71 if (errno > 0)
6bedfcbb 72 return -errno;
b5ffbc55 73 if (!x || x == s || *x != 0)
6bedfcbb
LP
74 return -EINVAL;
75 if (l < 0 || l > 07777)
76 return -ERANGE;
77
78 *ret = (mode_t) l;
79 return 0;
80}
81
597da51b 82int parse_ifindex(const char *s) {
6ad623a3
LP
83 int ifi, r;
84
f5072281 85 assert(s);
f5072281 86
6ad623a3
LP
87 r = safe_atoi(s, &ifi);
88 if (r < 0)
89 return r;
90 if (ifi <= 0)
91 return -EINVAL;
92
597da51b 93 return ifi;
88465a4e
YW
94}
95
f91c6093
LP
96int 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
6bedfcbb
LP
120int 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);
4c701096 169 assert(IN_SET(base, 1000, 1024));
6bedfcbb
LP
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);
6bedfcbb
LP
188
189 errno = 0;
190 l = strtoull(p, &e, 10);
b3267152 191 if (errno > 0)
6bedfcbb
LP
192 return -errno;
193 if (e == p)
194 return -EINVAL;
2d49a208
LP
195 if (*p == '-')
196 return -ERANGE;
6bedfcbb
LP
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);
b3267152 207 if (errno > 0)
6bedfcbb
LP
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
28cb17ef
FB
248int parse_range(const char *t, unsigned *lower, unsigned *upper) {
249 _cleanup_free_ char *word = NULL;
250 unsigned l, u;
251 int r;
252
253 assert(lower);
254 assert(upper);
255
256 /* Extract the lower bound. */
257 r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
258 if (r < 0)
259 return r;
260 if (r == 0)
261 return -EINVAL;
262
263 r = safe_atou(word, &l);
264 if (r < 0)
265 return r;
266
267 /* Check for the upper bound and extract it if needed */
268 if (!t)
269 /* Single number with no dashes. */
270 u = l;
271 else if (!*t)
272 /* Trailing dash is an error. */
273 return -EINVAL;
274 else {
275 r = safe_atou(t, &u);
276 if (r < 0)
277 return r;
278 }
279
280 *lower = l;
281 *upper = u;
282 return 0;
283}
284
cf26c4a7
YW
285int parse_errno(const char *t) {
286 int r, e;
287
288 assert(t);
289
290 r = errno_from_name(t);
291 if (r > 0)
292 return r;
293
294 r = safe_atoi(t, &e);
295 if (r < 0)
296 return r;
297
33d12153
YW
298 /* 0 is also allowed here */
299 if (!errno_is_valid(e) && e != 0)
cf26c4a7
YW
300 return -ERANGE;
301
302 return e;
303}
304
305int parse_syscall_and_errno(const char *in, char **name, int *error) {
306 _cleanup_free_ char *n = NULL;
307 char *p;
308 int e = -1;
309
310 assert(in);
311 assert(name);
312 assert(error);
313
314 /*
315 * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255".
316 * If errno is omitted, then error is set to -1.
317 * Empty syscall name is not allowed.
318 * Here, we do not check that the syscall name is valid or not.
319 */
320
321 p = strchr(in, ':');
322 if (p) {
323 e = parse_errno(p + 1);
324 if (e < 0)
325 return e;
326
327 n = strndup(in, p - in);
328 } else
329 n = strdup(in);
330
331 if (!n)
332 return -ENOMEM;
333
334 if (isempty(n))
335 return -EINVAL;
336
337 *error = e;
ae2a15bc 338 *name = TAKE_PTR(n);
cf26c4a7
YW
339
340 return 0;
341}
342
65baa289 343int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
6bedfcbb
LP
344 char *x = NULL;
345 unsigned long l;
346
347 assert(s);
65baa289 348 assert(base <= 16);
6bedfcbb 349
2d49a208
LP
350 /* strtoul() is happy to parse negative values, and silently
351 * converts them to unsigned values without generating an
352 * error. We want a clean error, hence let's look for the "-"
353 * prefix on our own, and generate an error. But let's do so
354 * only after strtoul() validated that the string is clean
355 * otherwise, so that we return EINVAL preferably over
356 * ERANGE. */
6bedfcbb 357
2d49a208 358 s += strspn(s, WHITESPACE);
6bedfcbb 359
2d49a208 360 errno = 0;
65baa289 361 l = strtoul(s, &x, base);
b3267152 362 if (errno > 0)
2d49a208 363 return -errno;
b5ffbc55 364 if (!x || x == s || *x != 0)
2d49a208
LP
365 return -EINVAL;
366 if (s[0] == '-')
367 return -ERANGE;
6bedfcbb
LP
368 if ((unsigned long) (unsigned) l != l)
369 return -ERANGE;
370
22810041
LP
371 if (ret_u)
372 *ret_u = (unsigned) l;
373
6bedfcbb
LP
374 return 0;
375}
376
377int safe_atoi(const char *s, int *ret_i) {
378 char *x = NULL;
379 long l;
380
381 assert(s);
6bedfcbb
LP
382
383 errno = 0;
384 l = strtol(s, &x, 0);
b3267152 385 if (errno > 0)
2d49a208 386 return -errno;
b5ffbc55 387 if (!x || x == s || *x != 0)
2d49a208 388 return -EINVAL;
6bedfcbb
LP
389 if ((long) (int) l != l)
390 return -ERANGE;
391
22810041
LP
392 if (ret_i)
393 *ret_i = (int) l;
394
6bedfcbb
LP
395 return 0;
396}
397
398int safe_atollu(const char *s, long long unsigned *ret_llu) {
399 char *x = NULL;
400 unsigned long long l;
401
402 assert(s);
6bedfcbb 403
2d49a208
LP
404 s += strspn(s, WHITESPACE);
405
6bedfcbb
LP
406 errno = 0;
407 l = strtoull(s, &x, 0);
b3267152 408 if (errno > 0)
2d49a208 409 return -errno;
b5ffbc55 410 if (!x || x == s || *x != 0)
2d49a208
LP
411 return -EINVAL;
412 if (*s == '-')
413 return -ERANGE;
6bedfcbb 414
22810041
LP
415 if (ret_llu)
416 *ret_llu = l;
417
6bedfcbb
LP
418 return 0;
419}
420
421int safe_atolli(const char *s, long long int *ret_lli) {
422 char *x = NULL;
423 long long l;
424
425 assert(s);
6bedfcbb
LP
426
427 errno = 0;
428 l = strtoll(s, &x, 0);
b3267152 429 if (errno > 0)
2d49a208 430 return -errno;
b5ffbc55 431 if (!x || x == s || *x != 0)
2d49a208 432 return -EINVAL;
6bedfcbb 433
22810041
LP
434 if (ret_lli)
435 *ret_lli = l;
436
6bedfcbb
LP
437 return 0;
438}
439
440int safe_atou8(const char *s, uint8_t *ret) {
441 char *x = NULL;
442 unsigned long l;
443
444 assert(s);
6bedfcbb 445
2d49a208
LP
446 s += strspn(s, WHITESPACE);
447
6bedfcbb
LP
448 errno = 0;
449 l = strtoul(s, &x, 0);
b3267152 450 if (errno > 0)
2d49a208 451 return -errno;
b5ffbc55 452 if (!x || x == s || *x != 0)
2d49a208
LP
453 return -EINVAL;
454 if (s[0] == '-')
455 return -ERANGE;
6bedfcbb
LP
456 if ((unsigned long) (uint8_t) l != l)
457 return -ERANGE;
458
22810041
LP
459 if (ret)
460 *ret = (uint8_t) l;
6bedfcbb
LP
461 return 0;
462}
463
5ef56aa2 464int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
6bedfcbb
LP
465 char *x = NULL;
466 unsigned long l;
467
468 assert(s);
469 assert(ret);
5ef56aa2 470 assert(base <= 16);
6bedfcbb 471
2d49a208
LP
472 s += strspn(s, WHITESPACE);
473
6bedfcbb 474 errno = 0;
5ef56aa2 475 l = strtoul(s, &x, base);
b3267152 476 if (errno > 0)
2d49a208 477 return -errno;
b5ffbc55 478 if (!x || x == s || *x != 0)
2d49a208
LP
479 return -EINVAL;
480 if (s[0] == '-')
481 return -ERANGE;
6bedfcbb
LP
482 if ((unsigned long) (uint16_t) l != l)
483 return -ERANGE;
484
485 *ret = (uint16_t) l;
486 return 0;
487}
488
489int safe_atoi16(const char *s, int16_t *ret) {
490 char *x = NULL;
491 long l;
492
493 assert(s);
6bedfcbb
LP
494
495 errno = 0;
496 l = strtol(s, &x, 0);
b3267152 497 if (errno > 0)
2d49a208 498 return -errno;
b5ffbc55 499 if (!x || x == s || *x != 0)
2d49a208 500 return -EINVAL;
6bedfcbb
LP
501 if ((long) (int16_t) l != l)
502 return -ERANGE;
503
22810041
LP
504 if (ret)
505 *ret = (int16_t) l;
506
6bedfcbb
LP
507 return 0;
508}
509
510int safe_atod(const char *s, double *ret_d) {
e520e0fc 511 _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
6bedfcbb
LP
512 char *x = NULL;
513 double d = 0;
6bedfcbb
LP
514
515 assert(s);
6bedfcbb
LP
516
517 loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
518 if (loc == (locale_t) 0)
519 return -errno;
520
521 errno = 0;
522 d = strtod_l(s, &x, loc);
e520e0fc 523 if (errno > 0)
2d49a208 524 return -errno;
e520e0fc 525 if (!x || x == s || *x != 0)
2d49a208 526 return -EINVAL;
6bedfcbb 527
22810041
LP
528 if (ret_d)
529 *ret_d = (double) d;
530
6bedfcbb
LP
531 return 0;
532}
436dd70f
HV
533
534int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
535 size_t i;
536 unsigned val = 0;
537 const char *s;
538
539 s = *p;
540
f21f31b2 541 /* accept any number of digits, strtoull is limited to 19 */
9ed794a3 542 for (i=0; i < digits; i++,s++) {
436dd70f
HV
543 if (*s < '0' || *s > '9') {
544 if (i == 0)
545 return -EINVAL;
546
547 /* too few digits, pad with 0 */
548 for (; i < digits; i++)
549 val *= 10;
550
551 break;
552 }
553
554 val *= 10;
555 val += *s - '0';
556 }
557
558 /* maybe round up */
559 if (*s >= '5' && *s <= '9')
560 val++;
561
562 s += strspn(s, DIGITS);
563
564 *p = s;
565 *res = val;
566
567 return 0;
568}
9184ca48 569
5124866d 570int parse_percent_unbounded(const char *p) {
9184ca48 571 const char *pc, *n;
bac794f6 572 int r, v;
9184ca48
LP
573
574 pc = endswith(p, "%");
575 if (!pc)
576 return -EINVAL;
577
578 n = strndupa(p, pc - p);
bac794f6 579 r = safe_atoi(n, &v);
9184ca48
LP
580 if (r < 0)
581 return r;
bac794f6
LP
582 if (v < 0)
583 return -ERANGE;
5124866d 584
bac794f6 585 return v;
5124866d
DM
586}
587
588int parse_percent(const char *p) {
41bf0590 589 int v;
5124866d 590
41bf0590 591 v = parse_percent_unbounded(p);
9184ca48
LP
592 if (v > 100)
593 return -ERANGE;
594
5124866d 595 return v;
9184ca48 596}
41bf0590 597
958acea1
MKB
598int parse_permille_unbounded(const char *p) {
599 const char *pc, *pm, *dot, *n;
600 int r, q, v;
601
602 pm = endswith(p, "‰");
603 if (pm) {
604 n = strndupa(p, pm - p);
605 r = safe_atoi(n, &v);
606 if (r < 0)
607 return r;
8cbc92d5
LP
608 if (v < 0)
609 return -ERANGE;
958acea1
MKB
610 } else {
611 pc = endswith(p, "%");
612 if (!pc)
613 return -EINVAL;
614
615 dot = memchr(p, '.', pc - p);
616 if (dot) {
617 if (dot + 2 != pc)
618 return -EINVAL;
619 if (dot[1] < '0' || dot[1] > '9')
620 return -EINVAL;
621 q = dot[1] - '0';
622 n = strndupa(p, dot - p);
623 } else {
624 q = 0;
625 n = strndupa(p, pc - p);
626 }
627 r = safe_atoi(n, &v);
628 if (r < 0)
629 return r;
8cbc92d5
LP
630 if (v < 0)
631 return -ERANGE;
fbbe6d65 632 if (v > (INT_MAX - q) / 10)
958acea1
MKB
633 return -ERANGE;
634
635 v = v * 10 + q;
636 }
637
958acea1
MKB
638 return v;
639}
640
641int parse_permille(const char *p) {
642 int v;
643
644 v = parse_permille_unbounded(p);
645 if (v > 1000)
646 return -ERANGE;
647
648 return v;
649}
650
41bf0590
LP
651int parse_nice(const char *p, int *ret) {
652 int n, r;
653
654 r = safe_atoi(p, &n);
655 if (r < 0)
656 return r;
657
658 if (!nice_is_valid(n))
659 return -ERANGE;
660
661 *ret = n;
662 return 0;
663}
10452f7c
SS
664
665int parse_ip_port(const char *s, uint16_t *ret) {
666 uint16_t l;
667 int r;
668
669 r = safe_atou16(s, &l);
670 if (r < 0)
671 return r;
672
673 if (l == 0)
674 return -EINVAL;
675
676 *ret = (uint16_t) l;
677
678 return 0;
679}
fbcc7f41 680
926062f0
SS
681int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
682 unsigned l, h;
683 int r;
684
685 r = parse_range(s, &l, &h);
686 if (r < 0)
687 return r;
688
689 if (l <= 0 || l > 65535 || h <= 0 || h > 65535)
690 return -EINVAL;
691
692 if (h < l)
693 return -EINVAL;
694
695 *low = l;
696 *high = h;
697
698 return 0;
699}
700
53e1ba28
NF
701int parse_ip_prefix_length(const char *s, int *ret) {
702 unsigned l;
703 int r;
704
705 r = safe_atou(s, &l);
706 if (r < 0)
707 return r;
708
709 if (l > 128)
710 return -ERANGE;
711
712 *ret = (int) l;
713
714 return 0;
715}
716
fbcc7f41 717int parse_dev(const char *s, dev_t *ret) {
de06c0cf 718 const char *major;
fbcc7f41 719 unsigned x, y;
de06c0cf
LP
720 size_t n;
721 int r;
fbcc7f41 722
de06c0cf
LP
723 n = strspn(s, DIGITS);
724 if (n == 0)
fbcc7f41 725 return -EINVAL;
de06c0cf 726 if (s[n] != ':')
fbcc7f41
FB
727 return -EINVAL;
728
de06c0cf
LP
729 major = strndupa(s, n);
730 r = safe_atou(major, &x);
731 if (r < 0)
732 return r;
733
734 r = safe_atou(s + n + 1, &y);
735 if (r < 0)
736 return r;
737
738 if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
739 return -ERANGE;
740
741 *ret = makedev(x, y);
fbcc7f41
FB
742 return 0;
743}
e9eb2c02
LP
744
745int parse_oom_score_adjust(const char *s, int *ret) {
746 int r, v;
747
748 assert(s);
749 assert(ret);
750
751 r = safe_atoi(s, &v);
752 if (r < 0)
753 return r;
754
755 if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
756 return -ERANGE;
757
758 *ret = v;
759 return 0;
760}