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