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