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