]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/parse-util.c
networkd: tunnel ignore wrong conf rather than assert
[thirdparty/systemd.git] / src / basic / parse-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
6bedfcbb
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6bedfcbb
LP
6***/
7
11c3a366
TA
8#include <errno.h>
9#include <inttypes.h>
10#include <locale.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
f91c6093 14#include <sys/socket.h>
11c3a366 15
28cb17ef 16#include "alloc-util.h"
cf26c4a7 17#include "errno-list.h"
28cb17ef 18#include "extract-word.h"
e520e0fc 19#include "locale-util.h"
11c3a366 20#include "macro.h"
f91c6093 21#include "missing.h"
93cc7779 22#include "parse-util.h"
41bf0590 23#include "process-util.h"
6bedfcbb 24#include "string-util.h"
6bedfcbb
LP
25
26int parse_boolean(const char *v) {
27 assert(v);
28
29 if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
30 return 1;
31 else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
32 return 0;
33
34 return -EINVAL;
35}
36
37int parse_pid(const char *s, pid_t* ret_pid) {
38 unsigned long ul = 0;
39 pid_t pid;
40 int r;
41
42 assert(s);
43 assert(ret_pid);
44
45 r = safe_atolu(s, &ul);
46 if (r < 0)
47 return r;
48
49 pid = (pid_t) ul;
50
51 if ((unsigned long) pid != ul)
52 return -ERANGE;
53
54191eb3 54 if (!pid_is_valid(pid))
6bedfcbb
LP
55 return -ERANGE;
56
57 *ret_pid = pid;
58 return 0;
59}
60
61int parse_mode(const char *s, mode_t *ret) {
62 char *x;
63 long l;
64
65 assert(s);
66 assert(ret);
67
2d49a208
LP
68 s += strspn(s, WHITESPACE);
69 if (s[0] == '-')
70 return -ERANGE;
71
6bedfcbb
LP
72 errno = 0;
73 l = strtol(s, &x, 8);
b3267152 74 if (errno > 0)
6bedfcbb 75 return -errno;
b5ffbc55 76 if (!x || x == s || *x != 0)
6bedfcbb
LP
77 return -EINVAL;
78 if (l < 0 || l > 07777)
79 return -ERANGE;
80
81 *ret = (mode_t) l;
82 return 0;
83}
84
6ad623a3
LP
85int parse_ifindex(const char *s, int *ret) {
86 int ifi, r;
87
88 r = safe_atoi(s, &ifi);
89 if (r < 0)
90 return r;
91 if (ifi <= 0)
92 return -EINVAL;
93
94 *ret = ifi;
95 return 0;
96}
97
f91c6093
LP
98int parse_mtu(int family, const char *s, uint32_t *ret) {
99 uint64_t u;
100 size_t m;
101 int r;
102
103 r = parse_size(s, 1024, &u);
104 if (r < 0)
105 return r;
106
107 if (u > UINT32_MAX)
108 return -ERANGE;
109
110 if (family == AF_INET6)
111 m = IPV6_MIN_MTU; /* This is 1280 */
112 else
113 m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */
114
115 if (u < m)
116 return -ERANGE;
117
118 *ret = (uint32_t) u;
119 return 0;
120}
121
6bedfcbb
LP
122int parse_size(const char *t, uint64_t base, uint64_t *size) {
123
124 /* Soo, sometimes we want to parse IEC binary suffixes, and
125 * sometimes SI decimal suffixes. This function can parse
126 * both. Which one is the right way depends on the
127 * context. Wikipedia suggests that SI is customary for
128 * hardware metrics and network speeds, while IEC is
129 * customary for most data sizes used by software and volatile
130 * (RAM) memory. Hence be careful which one you pick!
131 *
132 * In either case we use just K, M, G as suffix, and not Ki,
133 * Mi, Gi or so (as IEC would suggest). That's because that's
134 * frickin' ugly. But this means you really need to make sure
135 * to document which base you are parsing when you use this
136 * call. */
137
138 struct table {
139 const char *suffix;
140 unsigned long long factor;
141 };
142
143 static const struct table iec[] = {
144 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
145 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
146 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
147 { "G", 1024ULL*1024ULL*1024ULL },
148 { "M", 1024ULL*1024ULL },
149 { "K", 1024ULL },
150 { "B", 1ULL },
151 { "", 1ULL },
152 };
153
154 static const struct table si[] = {
155 { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
156 { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
157 { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
158 { "G", 1000ULL*1000ULL*1000ULL },
159 { "M", 1000ULL*1000ULL },
160 { "K", 1000ULL },
161 { "B", 1ULL },
162 { "", 1ULL },
163 };
164
165 const struct table *table;
166 const char *p;
167 unsigned long long r = 0;
168 unsigned n_entries, start_pos = 0;
169
170 assert(t);
4c701096 171 assert(IN_SET(base, 1000, 1024));
6bedfcbb
LP
172 assert(size);
173
174 if (base == 1000) {
175 table = si;
176 n_entries = ELEMENTSOF(si);
177 } else {
178 table = iec;
179 n_entries = ELEMENTSOF(iec);
180 }
181
182 p = t;
183 do {
184 unsigned long long l, tmp;
185 double frac = 0;
186 char *e;
187 unsigned i;
188
189 p += strspn(p, WHITESPACE);
6bedfcbb
LP
190
191 errno = 0;
192 l = strtoull(p, &e, 10);
b3267152 193 if (errno > 0)
6bedfcbb
LP
194 return -errno;
195 if (e == p)
196 return -EINVAL;
2d49a208
LP
197 if (*p == '-')
198 return -ERANGE;
6bedfcbb
LP
199
200 if (*e == '.') {
201 e++;
202
203 /* strtoull() itself would accept space/+/- */
204 if (*e >= '0' && *e <= '9') {
205 unsigned long long l2;
206 char *e2;
207
208 l2 = strtoull(e, &e2, 10);
b3267152 209 if (errno > 0)
6bedfcbb
LP
210 return -errno;
211
212 /* Ignore failure. E.g. 10.M is valid */
213 frac = l2;
214 for (; e < e2; e++)
215 frac /= 10;
216 }
217 }
218
219 e += strspn(e, WHITESPACE);
220
221 for (i = start_pos; i < n_entries; i++)
222 if (startswith(e, table[i].suffix))
223 break;
224
225 if (i >= n_entries)
226 return -EINVAL;
227
228 if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
229 return -ERANGE;
230
231 tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
232 if (tmp > ULLONG_MAX - r)
233 return -ERANGE;
234
235 r += tmp;
236 if ((unsigned long long) (uint64_t) r != r)
237 return -ERANGE;
238
239 p = e + strlen(table[i].suffix);
240
241 start_pos = i + 1;
242
243 } while (*p);
244
245 *size = r;
246
247 return 0;
248}
249
28cb17ef
FB
250int parse_range(const char *t, unsigned *lower, unsigned *upper) {
251 _cleanup_free_ char *word = NULL;
252 unsigned l, u;
253 int r;
254
255 assert(lower);
256 assert(upper);
257
258 /* Extract the lower bound. */
259 r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
260 if (r < 0)
261 return r;
262 if (r == 0)
263 return -EINVAL;
264
265 r = safe_atou(word, &l);
266 if (r < 0)
267 return r;
268
269 /* Check for the upper bound and extract it if needed */
270 if (!t)
271 /* Single number with no dashes. */
272 u = l;
273 else if (!*t)
274 /* Trailing dash is an error. */
275 return -EINVAL;
276 else {
277 r = safe_atou(t, &u);
278 if (r < 0)
279 return r;
280 }
281
282 *lower = l;
283 *upper = u;
284 return 0;
285}
286
cf26c4a7
YW
287int 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
33d12153
YW
300 /* 0 is also allowed here */
301 if (!errno_is_valid(e) && e != 0)
cf26c4a7
YW
302 return -ERANGE;
303
304 return e;
305}
306
307int 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;
ae2a15bc 340 *name = TAKE_PTR(n);
cf26c4a7
YW
341
342 return 0;
343}
344
6bedfcbb
LP
345char *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
380finish:
381 buf[l-1] = 0;
382 return buf;
383
384}
385
65baa289 386int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
6bedfcbb
LP
387 char *x = NULL;
388 unsigned long l;
389
390 assert(s);
391 assert(ret_u);
65baa289 392 assert(base <= 16);
6bedfcbb 393
2d49a208
LP
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. */
6bedfcbb 401
2d49a208 402 s += strspn(s, WHITESPACE);
6bedfcbb 403
2d49a208 404 errno = 0;
65baa289 405 l = strtoul(s, &x, base);
b3267152 406 if (errno > 0)
2d49a208 407 return -errno;
b5ffbc55 408 if (!x || x == s || *x != 0)
2d49a208
LP
409 return -EINVAL;
410 if (s[0] == '-')
411 return -ERANGE;
6bedfcbb
LP
412 if ((unsigned long) (unsigned) l != l)
413 return -ERANGE;
414
415 *ret_u = (unsigned) l;
416 return 0;
417}
418
419int 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);
b3267152 428 if (errno > 0)
2d49a208 429 return -errno;
b5ffbc55 430 if (!x || x == s || *x != 0)
2d49a208 431 return -EINVAL;
6bedfcbb
LP
432 if ((long) (int) l != l)
433 return -ERANGE;
434
435 *ret_i = (int) l;
436 return 0;
437}
438
439int 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
2d49a208
LP
446 s += strspn(s, WHITESPACE);
447
6bedfcbb
LP
448 errno = 0;
449 l = strtoull(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 == '-')
455 return -ERANGE;
6bedfcbb
LP
456
457 *ret_llu = l;
458 return 0;
459}
460
461int 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);
b3267152 470 if (errno > 0)
2d49a208 471 return -errno;
b5ffbc55 472 if (!x || x == s || *x != 0)
2d49a208 473 return -EINVAL;
6bedfcbb
LP
474
475 *ret_lli = l;
476 return 0;
477}
478
479int safe_atou8(const char *s, uint8_t *ret) {
480 char *x = NULL;
481 unsigned long l;
482
483 assert(s);
484 assert(ret);
485
2d49a208
LP
486 s += strspn(s, WHITESPACE);
487
6bedfcbb
LP
488 errno = 0;
489 l = strtoul(s, &x, 0);
b3267152 490 if (errno > 0)
2d49a208 491 return -errno;
b5ffbc55 492 if (!x || x == s || *x != 0)
2d49a208
LP
493 return -EINVAL;
494 if (s[0] == '-')
495 return -ERANGE;
6bedfcbb
LP
496 if ((unsigned long) (uint8_t) l != l)
497 return -ERANGE;
498
499 *ret = (uint8_t) l;
500 return 0;
501}
502
5ef56aa2 503int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
6bedfcbb
LP
504 char *x = NULL;
505 unsigned long l;
506
507 assert(s);
508 assert(ret);
5ef56aa2 509 assert(base <= 16);
6bedfcbb 510
2d49a208
LP
511 s += strspn(s, WHITESPACE);
512
6bedfcbb 513 errno = 0;
5ef56aa2 514 l = strtoul(s, &x, base);
b3267152 515 if (errno > 0)
2d49a208 516 return -errno;
b5ffbc55 517 if (!x || x == s || *x != 0)
2d49a208
LP
518 return -EINVAL;
519 if (s[0] == '-')
520 return -ERANGE;
6bedfcbb
LP
521 if ((unsigned long) (uint16_t) l != l)
522 return -ERANGE;
523
524 *ret = (uint16_t) l;
525 return 0;
526}
527
528int 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);
b3267152 537 if (errno > 0)
2d49a208 538 return -errno;
b5ffbc55 539 if (!x || x == s || *x != 0)
2d49a208 540 return -EINVAL;
6bedfcbb
LP
541 if ((long) (int16_t) l != l)
542 return -ERANGE;
543
544 *ret = (int16_t) l;
545 return 0;
546}
547
548int safe_atod(const char *s, double *ret_d) {
e520e0fc 549 _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
6bedfcbb
LP
550 char *x = NULL;
551 double d = 0;
6bedfcbb
LP
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);
e520e0fc 562 if (errno > 0)
2d49a208 563 return -errno;
e520e0fc 564 if (!x || x == s || *x != 0)
2d49a208 565 return -EINVAL;
6bedfcbb 566
6bedfcbb
LP
567 *ret_d = (double) d;
568 return 0;
569}
436dd70f
HV
570
571int 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 */
9ed794a3 579 for (i=0; i < digits; i++,s++) {
436dd70f
HV
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}
9184ca48 606
5124866d 607int parse_percent_unbounded(const char *p) {
9184ca48 608 const char *pc, *n;
bac794f6 609 int r, v;
9184ca48
LP
610
611 pc = endswith(p, "%");
612 if (!pc)
613 return -EINVAL;
614
615 n = strndupa(p, pc - p);
bac794f6 616 r = safe_atoi(n, &v);
9184ca48
LP
617 if (r < 0)
618 return r;
bac794f6
LP
619 if (v < 0)
620 return -ERANGE;
5124866d 621
bac794f6 622 return v;
5124866d
DM
623}
624
625int parse_percent(const char *p) {
41bf0590 626 int v;
5124866d 627
41bf0590 628 v = parse_percent_unbounded(p);
9184ca48
LP
629 if (v > 100)
630 return -ERANGE;
631
5124866d 632 return v;
9184ca48 633}
41bf0590
LP
634
635int parse_nice(const char *p, int *ret) {
636 int n, r;
637
638 r = safe_atoi(p, &n);
639 if (r < 0)
640 return r;
641
642 if (!nice_is_valid(n))
643 return -ERANGE;
644
645 *ret = n;
646 return 0;
647}
10452f7c
SS
648
649int parse_ip_port(const char *s, uint16_t *ret) {
650 uint16_t l;
651 int r;
652
653 r = safe_atou16(s, &l);
654 if (r < 0)
655 return r;
656
657 if (l == 0)
658 return -EINVAL;
659
660 *ret = (uint16_t) l;
661
662 return 0;
663}
fbcc7f41
FB
664
665int parse_dev(const char *s, dev_t *ret) {
666 unsigned x, y;
667 dev_t d;
668
669 if (sscanf(s, "%u:%u", &x, &y) != 2)
670 return -EINVAL;
671
672 d = makedev(x, y);
673 if ((unsigned) major(d) != x || (unsigned) minor(d) != y)
674 return -EINVAL;
675
676 *ret = d;
677 return 0;
678}
e9eb2c02
LP
679
680int parse_oom_score_adjust(const char *s, int *ret) {
681 int r, v;
682
683 assert(s);
684 assert(ret);
685
686 r = safe_atoi(s, &v);
687 if (r < 0)
688 return r;
689
690 if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
691 return -ERANGE;
692
693 *ret = v;
694 return 0;
695}