Line data Source code
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 226 : int parse_boolean(const char *v) {
25 226 : if (!v)
26 0 : return -EINVAL;
27 :
28 226 : if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
29 66 : return 1;
30 160 : else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
31 78 : return 0;
32 :
33 82 : return -EINVAL;
34 : }
35 :
36 287 : int parse_pid(const char *s, pid_t* ret_pid) {
37 287 : unsigned long ul = 0;
38 : pid_t pid;
39 : int r;
40 :
41 287 : assert(s);
42 287 : assert(ret_pid);
43 :
44 287 : r = safe_atolu(s, &ul);
45 287 : if (r < 0)
46 15 : return r;
47 :
48 272 : pid = (pid_t) ul;
49 :
50 272 : if ((unsigned long) pid != ul)
51 0 : return -ERANGE;
52 :
53 272 : if (!pid_is_valid(pid))
54 1 : return -ERANGE;
55 :
56 271 : *ret_pid = pid;
57 271 : return 0;
58 : }
59 :
60 16 : int parse_mode(const char *s, mode_t *ret) {
61 : char *x;
62 : long l;
63 :
64 16 : assert(s);
65 16 : assert(ret);
66 :
67 16 : s += strspn(s, WHITESPACE);
68 16 : if (s[0] == '-')
69 2 : return -ERANGE;
70 :
71 14 : errno = 0;
72 14 : l = strtol(s, &x, 8);
73 14 : if (errno > 0)
74 0 : return -errno;
75 14 : if (!x || x == s || *x != 0)
76 6 : return -EINVAL;
77 8 : if (l < 0 || l > 07777)
78 1 : return -ERANGE;
79 :
80 7 : *ret = (mode_t) l;
81 7 : return 0;
82 : }
83 :
84 180 : int parse_ifindex(const char *s, int *ret) {
85 : int ifi, r;
86 :
87 180 : assert(s);
88 180 : assert(ret);
89 :
90 180 : r = safe_atoi(s, &ifi);
91 180 : if (r < 0)
92 2 : return r;
93 178 : if (ifi <= 0)
94 0 : return -EINVAL;
95 :
96 178 : *ret = ifi;
97 178 : return 0;
98 : }
99 :
100 0 : int parse_ifindex_or_ifname(const char *s, int *ret) {
101 : int r;
102 :
103 0 : assert(s);
104 0 : assert(ret);
105 :
106 0 : r = parse_ifindex(s, ret);
107 0 : if (r >= 0)
108 0 : return r;
109 :
110 0 : r = (int) if_nametoindex(s);
111 0 : if (r <= 0)
112 0 : return -errno;
113 :
114 0 : *ret = r;
115 0 : return 0;
116 : }
117 :
118 28 : int parse_mtu(int family, const char *s, uint32_t *ret) {
119 : uint64_t u;
120 : size_t m;
121 : int r;
122 :
123 28 : r = parse_size(s, 1024, &u);
124 28 : if (r < 0)
125 7 : return r;
126 :
127 21 : if (u > UINT32_MAX)
128 2 : return -ERANGE;
129 :
130 19 : if (family == AF_INET6)
131 3 : m = IPV6_MIN_MTU; /* This is 1280 */
132 : else
133 16 : m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */
134 :
135 19 : if (u < m)
136 4 : return -ERANGE;
137 :
138 15 : *ret = (uint32_t) u;
139 15 : return 0;
140 : }
141 :
142 88 : 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 88 : unsigned long long r = 0;
188 88 : unsigned n_entries, start_pos = 0;
189 :
190 88 : assert(t);
191 88 : assert(IN_SET(base, 1000, 1024));
192 88 : assert(size);
193 :
194 88 : if (base == 1000) {
195 9 : table = si;
196 9 : n_entries = ELEMENTSOF(si);
197 : } else {
198 79 : table = iec;
199 79 : n_entries = ELEMENTSOF(iec);
200 : }
201 :
202 88 : p = t;
203 : do {
204 : unsigned long long l, tmp;
205 112 : double frac = 0;
206 : char *e;
207 : unsigned i;
208 :
209 112 : p += strspn(p, WHITESPACE);
210 :
211 112 : errno = 0;
212 112 : l = strtoull(p, &e, 10);
213 112 : if (errno > 0)
214 28 : return -errno;
215 110 : if (e == p)
216 17 : return -EINVAL;
217 93 : if (*p == '-')
218 7 : return -ERANGE;
219 :
220 86 : if (*e == '.') {
221 19 : e++;
222 :
223 : /* strtoull() itself would accept space/+/- */
224 19 : if (*e >= '0' && *e <= '9') {
225 : unsigned long long l2;
226 : char *e2;
227 :
228 17 : l2 = strtoull(e, &e2, 10);
229 17 : if (errno > 0)
230 0 : return -errno;
231 :
232 : /* Ignore failure. E.g. 10.M is valid */
233 17 : frac = l2;
234 40 : for (; e < e2; e++)
235 23 : frac /= 10;
236 : }
237 : }
238 :
239 86 : e += strspn(e, WHITESPACE);
240 :
241 514 : for (i = start_pos; i < n_entries; i++)
242 513 : if (startswith(e, table[i].suffix))
243 85 : break;
244 :
245 86 : if (i >= n_entries)
246 1 : return -EINVAL;
247 :
248 85 : if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
249 1 : return -ERANGE;
250 :
251 84 : tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
252 84 : if (tmp > ULLONG_MAX - r)
253 0 : return -ERANGE;
254 :
255 84 : r += tmp;
256 : if ((unsigned long long) (uint64_t) r != r)
257 : return -ERANGE;
258 :
259 84 : p = e + strlen(table[i].suffix);
260 :
261 84 : start_pos = i + 1;
262 :
263 84 : } while (*p);
264 :
265 60 : *size = r;
266 :
267 60 : return 0;
268 : }
269 :
270 104 : int parse_range(const char *t, unsigned *lower, unsigned *upper) {
271 104 : _cleanup_free_ char *word = NULL;
272 : unsigned l, u;
273 : int r;
274 :
275 104 : assert(lower);
276 104 : assert(upper);
277 :
278 : /* Extract the lower bound. */
279 104 : r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
280 104 : if (r < 0)
281 0 : return r;
282 104 : if (r == 0)
283 0 : return -EINVAL;
284 :
285 104 : r = safe_atou(word, &l);
286 104 : if (r < 0)
287 18 : return r;
288 :
289 : /* Check for the upper bound and extract it if needed */
290 86 : if (!t)
291 : /* Single number with no dashes. */
292 52 : u = l;
293 34 : else if (!*t)
294 : /* Trailing dash is an error. */
295 1 : return -EINVAL;
296 : else {
297 33 : r = safe_atou(t, &u);
298 33 : if (r < 0)
299 11 : return r;
300 : }
301 :
302 74 : *lower = l;
303 74 : *upper = u;
304 74 : return 0;
305 : }
306 :
307 30 : int parse_errno(const char *t) {
308 : int r, e;
309 :
310 30 : assert(t);
311 :
312 30 : r = errno_from_name(t);
313 30 : if (r > 0)
314 4 : return r;
315 :
316 26 : r = safe_atoi(t, &e);
317 26 : if (r < 0)
318 15 : return r;
319 :
320 : /* 0 is also allowed here */
321 11 : if (!errno_is_valid(e) && e != 0)
322 5 : return -ERANGE;
323 :
324 6 : return e;
325 : }
326 :
327 16 : int parse_syscall_and_errno(const char *in, char **name, int *error) {
328 16 : _cleanup_free_ char *n = NULL;
329 : char *p;
330 16 : int e = -1;
331 :
332 16 : assert(in);
333 16 : assert(name);
334 16 : 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 16 : p = strchr(in, ':');
344 16 : if (p) {
345 14 : e = parse_errno(p + 1);
346 14 : if (e < 0)
347 9 : return e;
348 :
349 5 : n = strndup(in, p - in);
350 : } else
351 2 : n = strdup(in);
352 :
353 7 : if (!n)
354 0 : return -ENOMEM;
355 :
356 7 : if (isempty(n))
357 2 : return -EINVAL;
358 :
359 5 : *error = e;
360 5 : *name = TAKE_PTR(n);
361 :
362 5 : return 0;
363 : }
364 :
365 104890 : int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
366 104890 : char *x = NULL;
367 : unsigned long l;
368 :
369 104890 : assert(s);
370 104890 : assert(ret_u);
371 104890 : 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 104890 : s += strspn(s, WHITESPACE);
382 :
383 104890 : errno = 0;
384 104890 : l = strtoul(s, &x, base);
385 104890 : if (errno > 0)
386 2 : return -errno;
387 104888 : if (!x || x == s || *x != 0)
388 113 : return -EINVAL;
389 104775 : if (s[0] == '-')
390 4 : return -ERANGE;
391 104771 : if ((unsigned long) (unsigned) l != l)
392 0 : return -ERANGE;
393 :
394 104771 : *ret_u = (unsigned) l;
395 104771 : return 0;
396 : }
397 :
398 837 : int safe_atoi(const char *s, int *ret_i) {
399 837 : char *x = NULL;
400 : long l;
401 :
402 837 : assert(s);
403 837 : assert(ret_i);
404 :
405 837 : errno = 0;
406 837 : l = strtol(s, &x, 0);
407 837 : if (errno > 0)
408 2 : return -errno;
409 835 : if (!x || x == s || *x != 0)
410 231 : return -EINVAL;
411 604 : if ((long) (int) l != l)
412 3 : return -ERANGE;
413 :
414 601 : *ret_i = (int) l;
415 601 : return 0;
416 : }
417 :
418 3170 : int safe_atollu(const char *s, long long unsigned *ret_llu) {
419 3170 : char *x = NULL;
420 : unsigned long long l;
421 :
422 3170 : assert(s);
423 3170 : assert(ret_llu);
424 :
425 3170 : s += strspn(s, WHITESPACE);
426 :
427 3170 : errno = 0;
428 3170 : l = strtoull(s, &x, 0);
429 3170 : if (errno > 0)
430 2 : return -errno;
431 3168 : if (!x || x == s || *x != 0)
432 20 : return -EINVAL;
433 3148 : if (*s == '-')
434 3 : return -ERANGE;
435 :
436 3145 : *ret_llu = l;
437 3145 : return 0;
438 : }
439 :
440 20 : int safe_atolli(const char *s, long long int *ret_lli) {
441 20 : char *x = NULL;
442 : long long l;
443 :
444 20 : assert(s);
445 20 : assert(ret_lli);
446 :
447 20 : errno = 0;
448 20 : l = strtoll(s, &x, 0);
449 20 : if (errno > 0)
450 4 : return -errno;
451 16 : if (!x || x == s || *x != 0)
452 8 : return -EINVAL;
453 :
454 8 : *ret_lli = l;
455 8 : return 0;
456 : }
457 :
458 115 : int safe_atou8(const char *s, uint8_t *ret) {
459 115 : char *x = NULL;
460 : unsigned long l;
461 :
462 115 : assert(s);
463 115 : assert(ret);
464 :
465 115 : s += strspn(s, WHITESPACE);
466 :
467 115 : errno = 0;
468 115 : l = strtoul(s, &x, 0);
469 115 : if (errno > 0)
470 0 : return -errno;
471 115 : if (!x || x == s || *x != 0)
472 1 : return -EINVAL;
473 114 : if (s[0] == '-')
474 5 : return -ERANGE;
475 109 : if ((unsigned long) (uint8_t) l != l)
476 1 : return -ERANGE;
477 :
478 108 : *ret = (uint8_t) l;
479 108 : return 0;
480 : }
481 :
482 52 : int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
483 52 : char *x = NULL;
484 : unsigned long l;
485 :
486 52 : assert(s);
487 52 : assert(ret);
488 52 : assert(base <= 16);
489 :
490 52 : s += strspn(s, WHITESPACE);
491 :
492 52 : errno = 0;
493 52 : l = strtoul(s, &x, base);
494 52 : if (errno > 0)
495 0 : return -errno;
496 52 : if (!x || x == s || *x != 0)
497 14 : return -EINVAL;
498 38 : if (s[0] == '-')
499 4 : return -ERANGE;
500 34 : if ((unsigned long) (uint16_t) l != l)
501 5 : return -ERANGE;
502 :
503 29 : *ret = (uint16_t) l;
504 29 : return 0;
505 : }
506 :
507 10 : int safe_atoi16(const char *s, int16_t *ret) {
508 10 : char *x = NULL;
509 : long l;
510 :
511 10 : assert(s);
512 10 : assert(ret);
513 :
514 10 : errno = 0;
515 10 : l = strtol(s, &x, 0);
516 10 : if (errno > 0)
517 0 : return -errno;
518 10 : if (!x || x == s || *x != 0)
519 4 : return -EINVAL;
520 6 : if ((long) (int16_t) l != l)
521 2 : return -ERANGE;
522 :
523 4 : *ret = (int16_t) l;
524 4 : return 0;
525 : }
526 :
527 10 : int safe_atod(const char *s, double *ret_d) {
528 10 : _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
529 10 : char *x = NULL;
530 10 : double d = 0;
531 :
532 10 : assert(s);
533 10 : assert(ret_d);
534 :
535 10 : loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
536 10 : if (loc == (locale_t) 0)
537 0 : return -errno;
538 :
539 10 : errno = 0;
540 10 : d = strtod_l(s, &x, loc);
541 10 : if (errno > 0)
542 0 : return -errno;
543 10 : if (!x || x == s || *x != 0)
544 7 : return -EINVAL;
545 :
546 3 : *ret_d = (double) d;
547 3 : return 0;
548 : }
549 :
550 222 : int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
551 : size_t i;
552 222 : unsigned val = 0;
553 : const char *s;
554 :
555 222 : s = *p;
556 :
557 : /* accept any number of digits, strtoull is limited to 19 */
558 1494 : for (i=0; i < digits; i++,s++) {
559 1286 : if (*s < '0' || *s > '9') {
560 14 : if (i == 0)
561 0 : return -EINVAL;
562 :
563 : /* too few digits, pad with 0 */
564 74 : for (; i < digits; i++)
565 60 : val *= 10;
566 :
567 14 : break;
568 : }
569 :
570 1272 : val *= 10;
571 1272 : val += *s - '0';
572 : }
573 :
574 : /* maybe round up */
575 222 : if (*s >= '5' && *s <= '9')
576 4 : val++;
577 :
578 222 : s += strspn(s, DIGITS);
579 :
580 222 : *p = s;
581 222 : *res = val;
582 :
583 222 : return 0;
584 : }
585 :
586 18 : int parse_percent_unbounded(const char *p) {
587 : const char *pc, *n;
588 : int r, v;
589 :
590 18 : pc = endswith(p, "%");
591 18 : if (!pc)
592 7 : return -EINVAL;
593 :
594 11 : n = strndupa(p, pc - p);
595 11 : r = safe_atoi(n, &v);
596 11 : if (r < 0)
597 4 : return r;
598 7 : if (v < 0)
599 1 : return -ERANGE;
600 :
601 6 : return v;
602 : }
603 :
604 16 : int parse_percent(const char *p) {
605 : int v;
606 :
607 16 : v = parse_percent_unbounded(p);
608 16 : if (v > 100)
609 1 : return -ERANGE;
610 :
611 15 : return v;
612 : }
613 :
614 46 : int parse_permille_unbounded(const char *p) {
615 : const char *pc, *pm, *dot, *n;
616 : int r, q, v;
617 :
618 46 : pm = endswith(p, "‰");
619 46 : if (pm) {
620 15 : n = strndupa(p, pm - p);
621 15 : r = safe_atoi(n, &v);
622 15 : if (r < 0)
623 7 : return r;
624 8 : if (v < 0)
625 1 : return -ERANGE;
626 : } else {
627 31 : pc = endswith(p, "%");
628 31 : if (!pc)
629 15 : return -EINVAL;
630 :
631 16 : dot = memchr(p, '.', pc - p);
632 16 : if (dot) {
633 6 : if (dot + 2 != pc)
634 1 : return -EINVAL;
635 5 : if (dot[1] < '0' || dot[1] > '9')
636 0 : return -EINVAL;
637 5 : q = dot[1] - '0';
638 5 : n = strndupa(p, dot - p);
639 : } else {
640 10 : q = 0;
641 10 : n = strndupa(p, pc - p);
642 : }
643 15 : r = safe_atoi(n, &v);
644 15 : if (r < 0)
645 3 : return r;
646 12 : if (v < 0)
647 1 : return -ERANGE;
648 11 : if (v > (INT_MAX - q) / 10)
649 3 : return -ERANGE;
650 :
651 8 : v = v * 10 + q;
652 : }
653 :
654 15 : return v;
655 : }
656 :
657 34 : int parse_permille(const char *p) {
658 : int v;
659 :
660 34 : v = parse_permille_unbounded(p);
661 34 : if (v > 1000)
662 2 : return -ERANGE;
663 :
664 32 : return v;
665 : }
666 :
667 21 : int parse_nice(const char *p, int *ret) {
668 : int n, r;
669 :
670 21 : r = safe_atoi(p, &n);
671 21 : if (r < 0)
672 4 : return r;
673 :
674 17 : if (!nice_is_valid(n))
675 6 : return -ERANGE;
676 :
677 11 : *ret = n;
678 11 : return 0;
679 : }
680 :
681 33 : int parse_ip_port(const char *s, uint16_t *ret) {
682 : uint16_t l;
683 : int r;
684 :
685 33 : r = safe_atou16(s, &l);
686 33 : if (r < 0)
687 9 : return r;
688 :
689 24 : if (l == 0)
690 3 : return -EINVAL;
691 :
692 21 : *ret = (uint16_t) l;
693 :
694 21 : return 0;
695 : }
696 :
697 0 : int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
698 : unsigned l, h;
699 : int r;
700 :
701 0 : r = parse_range(s, &l, &h);
702 0 : if (r < 0)
703 0 : return r;
704 :
705 0 : if (l <= 0 || l > 65535 || h <= 0 || h > 65535)
706 0 : return -EINVAL;
707 :
708 0 : if (h < l)
709 0 : return -EINVAL;
710 :
711 0 : *low = l;
712 0 : *high = h;
713 :
714 0 : return 0;
715 : }
716 :
717 488 : 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 488 : n = strspn(s, DIGITS);
724 488 : if (n == 0)
725 4 : return -EINVAL;
726 484 : if (s[n] != ':')
727 2 : return -EINVAL;
728 :
729 482 : major = strndupa(s, n);
730 482 : r = safe_atou(major, &x);
731 482 : if (r < 0)
732 0 : return r;
733 :
734 482 : r = safe_atou(s + n + 1, &y);
735 482 : if (r < 0)
736 1 : return r;
737 :
738 481 : if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
739 0 : return -ERANGE;
740 :
741 481 : *ret = makedev(x, y);
742 481 : return 0;
743 : }
744 :
745 0 : int parse_oom_score_adjust(const char *s, int *ret) {
746 : int r, v;
747 :
748 0 : assert(s);
749 0 : assert(ret);
750 :
751 0 : r = safe_atoi(s, &v);
752 0 : if (r < 0)
753 0 : return r;
754 :
755 0 : if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
756 0 : return -ERANGE;
757 :
758 0 : *ret = v;
759 0 : return 0;
760 : }
|