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