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