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