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