]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/parse-util.c
Merge pull request #17185 from yuwata/ethtool-update
[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"
005bfaf1
TM
19#if HAVE_SECCOMP
20#include "seccomp-util.h"
21#endif
de06c0cf 22#include "stat-util.h"
6bedfcbb 23#include "string-util.h"
ddd6a22a 24#include "strv.h"
6bedfcbb
LP
25
26int parse_boolean(const char *v) {
b06f0cc6
LP
27 if (!v)
28 return -EINVAL;
6bedfcbb 29
ddd6a22a
LP
30 if (STRCASE_IN_SET(v,
31 "1",
32 "yes",
33 "y",
34 "true",
35 "t",
36 "on"))
6bedfcbb 37 return 1;
ddd6a22a
LP
38
39 if (STRCASE_IN_SET(v,
40 "0",
41 "no",
42 "n",
43 "false",
44 "f",
45 "off"))
6bedfcbb
LP
46 return 0;
47
48 return -EINVAL;
49}
50
51int parse_pid(const char *s, pid_t* ret_pid) {
52 unsigned long ul = 0;
53 pid_t pid;
54 int r;
55
56 assert(s);
57 assert(ret_pid);
58
59 r = safe_atolu(s, &ul);
60 if (r < 0)
61 return r;
62
63 pid = (pid_t) ul;
64
65 if ((unsigned long) pid != ul)
66 return -ERANGE;
67
54191eb3 68 if (!pid_is_valid(pid))
6bedfcbb
LP
69 return -ERANGE;
70
71 *ret_pid = pid;
72 return 0;
73}
74
75int parse_mode(const char *s, mode_t *ret) {
c44702a8
LP
76 unsigned m;
77 int r;
6bedfcbb
LP
78
79 assert(s);
2d49a208 80
c44702a8
LP
81 r = safe_atou_full(s, 8 |
82 SAFE_ATO_REFUSE_PLUS_MINUS, /* Leading '+' or even '-' char? that's just weird,
83 * refuse. User might have wanted to add mode flags or
84 * so, but this parser doesn't allow that, so let's
85 * better be safe. */
86 &m);
87 if (r < 0)
88 return r;
89 if (m > 07777)
6bedfcbb
LP
90 return -ERANGE;
91
c44702a8
LP
92 if (ret)
93 *ret = m;
6bedfcbb
LP
94 return 0;
95}
96
597da51b 97int parse_ifindex(const char *s) {
6ad623a3
LP
98 int ifi, r;
99
f5072281 100 assert(s);
f5072281 101
6ad623a3
LP
102 r = safe_atoi(s, &ifi);
103 if (r < 0)
104 return r;
105 if (ifi <= 0)
106 return -EINVAL;
107
597da51b 108 return ifi;
88465a4e
YW
109}
110
f91c6093
LP
111int parse_mtu(int family, const char *s, uint32_t *ret) {
112 uint64_t u;
113 size_t m;
114 int r;
115
116 r = parse_size(s, 1024, &u);
117 if (r < 0)
118 return r;
119
120 if (u > UINT32_MAX)
121 return -ERANGE;
122
123 if (family == AF_INET6)
124 m = IPV6_MIN_MTU; /* This is 1280 */
125 else
126 m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */
127
128 if (u < m)
129 return -ERANGE;
130
131 *ret = (uint32_t) u;
132 return 0;
133}
134
6bedfcbb
LP
135int parse_size(const char *t, uint64_t base, uint64_t *size) {
136
137 /* Soo, sometimes we want to parse IEC binary suffixes, and
138 * sometimes SI decimal suffixes. This function can parse
139 * both. Which one is the right way depends on the
140 * context. Wikipedia suggests that SI is customary for
141 * hardware metrics and network speeds, while IEC is
142 * customary for most data sizes used by software and volatile
143 * (RAM) memory. Hence be careful which one you pick!
144 *
145 * In either case we use just K, M, G as suffix, and not Ki,
146 * Mi, Gi or so (as IEC would suggest). That's because that's
147 * frickin' ugly. But this means you really need to make sure
148 * to document which base you are parsing when you use this
149 * call. */
150
151 struct table {
152 const char *suffix;
153 unsigned long long factor;
154 };
155
156 static const struct table iec[] = {
157 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
158 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
159 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
160 { "G", 1024ULL*1024ULL*1024ULL },
161 { "M", 1024ULL*1024ULL },
162 { "K", 1024ULL },
163 { "B", 1ULL },
164 { "", 1ULL },
165 };
166
167 static const struct table si[] = {
168 { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
169 { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
170 { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
171 { "G", 1000ULL*1000ULL*1000ULL },
172 { "M", 1000ULL*1000ULL },
173 { "K", 1000ULL },
174 { "B", 1ULL },
175 { "", 1ULL },
176 };
177
178 const struct table *table;
179 const char *p;
180 unsigned long long r = 0;
181 unsigned n_entries, start_pos = 0;
182
183 assert(t);
4c701096 184 assert(IN_SET(base, 1000, 1024));
6bedfcbb
LP
185 assert(size);
186
187 if (base == 1000) {
188 table = si;
189 n_entries = ELEMENTSOF(si);
190 } else {
191 table = iec;
192 n_entries = ELEMENTSOF(iec);
193 }
194
195 p = t;
196 do {
197 unsigned long long l, tmp;
198 double frac = 0;
199 char *e;
200 unsigned i;
201
202 p += strspn(p, WHITESPACE);
6bedfcbb
LP
203
204 errno = 0;
205 l = strtoull(p, &e, 10);
b3267152 206 if (errno > 0)
6bedfcbb
LP
207 return -errno;
208 if (e == p)
209 return -EINVAL;
2d49a208
LP
210 if (*p == '-')
211 return -ERANGE;
6bedfcbb
LP
212
213 if (*e == '.') {
214 e++;
215
216 /* strtoull() itself would accept space/+/- */
217 if (*e >= '0' && *e <= '9') {
218 unsigned long long l2;
219 char *e2;
220
221 l2 = strtoull(e, &e2, 10);
b3267152 222 if (errno > 0)
6bedfcbb
LP
223 return -errno;
224
225 /* Ignore failure. E.g. 10.M is valid */
226 frac = l2;
227 for (; e < e2; e++)
228 frac /= 10;
229 }
230 }
231
232 e += strspn(e, WHITESPACE);
233
234 for (i = start_pos; i < n_entries; i++)
235 if (startswith(e, table[i].suffix))
236 break;
237
238 if (i >= n_entries)
239 return -EINVAL;
240
241 if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
242 return -ERANGE;
243
244 tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
245 if (tmp > ULLONG_MAX - r)
246 return -ERANGE;
247
248 r += tmp;
249 if ((unsigned long long) (uint64_t) r != r)
250 return -ERANGE;
251
252 p = e + strlen(table[i].suffix);
253
254 start_pos = i + 1;
255
256 } while (*p);
257
258 *size = r;
259
260 return 0;
261}
262
28cb17ef
FB
263int parse_range(const char *t, unsigned *lower, unsigned *upper) {
264 _cleanup_free_ char *word = NULL;
265 unsigned l, u;
266 int r;
267
268 assert(lower);
269 assert(upper);
270
271 /* Extract the lower bound. */
272 r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
273 if (r < 0)
274 return r;
275 if (r == 0)
276 return -EINVAL;
277
278 r = safe_atou(word, &l);
279 if (r < 0)
280 return r;
281
282 /* Check for the upper bound and extract it if needed */
283 if (!t)
284 /* Single number with no dashes. */
285 u = l;
286 else if (!*t)
287 /* Trailing dash is an error. */
288 return -EINVAL;
289 else {
290 r = safe_atou(t, &u);
291 if (r < 0)
292 return r;
293 }
294
295 *lower = l;
296 *upper = u;
297 return 0;
298}
299
cf26c4a7
YW
300int parse_errno(const char *t) {
301 int r, e;
302
303 assert(t);
304
305 r = errno_from_name(t);
306 if (r > 0)
307 return r;
308
309 r = safe_atoi(t, &e);
310 if (r < 0)
311 return r;
312
33d12153
YW
313 /* 0 is also allowed here */
314 if (!errno_is_valid(e) && e != 0)
cf26c4a7
YW
315 return -ERANGE;
316
317 return e;
318}
319
005bfaf1 320#if HAVE_SECCOMP
cf26c4a7
YW
321int parse_syscall_and_errno(const char *in, char **name, int *error) {
322 _cleanup_free_ char *n = NULL;
323 char *p;
324 int e = -1;
325
326 assert(in);
327 assert(name);
328 assert(error);
329
330 /*
331 * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255".
332 * If errno is omitted, then error is set to -1.
333 * Empty syscall name is not allowed.
334 * Here, we do not check that the syscall name is valid or not.
335 */
336
337 p = strchr(in, ':');
338 if (p) {
005bfaf1 339 e = seccomp_parse_errno_or_action(p + 1);
cf26c4a7
YW
340 if (e < 0)
341 return e;
342
343 n = strndup(in, p - in);
344 } else
345 n = strdup(in);
346
347 if (!n)
348 return -ENOMEM;
349
350 if (isempty(n))
351 return -EINVAL;
352
353 *error = e;
ae2a15bc 354 *name = TAKE_PTR(n);
cf26c4a7
YW
355
356 return 0;
357}
005bfaf1 358#endif
cf26c4a7 359
fc80cabc
LP
360static const char *mangle_base(const char *s, unsigned *base) {
361 const char *k;
362
363 assert(s);
364 assert(base);
365
366 /* Base already explicitly specified, then don't do anything. */
367 if (SAFE_ATO_MASK_FLAGS(*base) != 0)
368 return s;
369
370 /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
371 k = STARTSWITH_SET(s, "0b", "0B");
372 if (k) {
373 *base = 2 | (*base & SAFE_ATO_ALL_FLAGS);
374 return k;
375 }
376
377 k = STARTSWITH_SET(s, "0o", "0O");
378 if (k) {
379 *base = 8 | (*base & SAFE_ATO_ALL_FLAGS);
380 return k;
381 }
382
383 return s;
384}
385
65baa289 386int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
6bedfcbb
LP
387 char *x = NULL;
388 unsigned long l;
389
390 assert(s);
707e93af 391 assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
6bedfcbb 392
707e93af
LP
393 /* strtoul() is happy to parse negative values, and silently converts them to unsigned values without
394 * generating an error. We want a clean error, hence let's look for the "-" prefix on our own, and
395 * generate an error. But let's do so only after strtoul() validated that the string is clean
396 * otherwise, so that we return EINVAL preferably over ERANGE. */
397
398 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
399 strchr(WHITESPACE, s[0]))
400 return -EINVAL;
6bedfcbb 401
2d49a208 402 s += strspn(s, WHITESPACE);
6bedfcbb 403
707e93af
LP
404 if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
405 IN_SET(s[0], '+', '-'))
406 return -EINVAL; /* Note that we check the "-" prefix again a second time below, but return a
407 * different error. I.e. if the SAFE_ATO_REFUSE_PLUS_MINUS flag is set we
408 * blanket refuse +/- prefixed integers, while if it is missing we'll just
409 * return ERANGE, because the string actually parses correctly, but doesn't
410 * fit in the return type. */
411
412 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
413 s[0] == '0' && !streq(s, "0"))
414 return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
415 * notation and assumed-to-be-decimal integers with a leading zero. */
416
fc80cabc
LP
417 s = mangle_base(s, &base);
418
2d49a208 419 errno = 0;
707e93af
LP
420 l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
421 * base is left */);
b3267152 422 if (errno > 0)
2d49a208 423 return -errno;
b5ffbc55 424 if (!x || x == s || *x != 0)
2d49a208 425 return -EINVAL;
c78eefc1 426 if (l != 0 && s[0] == '-')
2d49a208 427 return -ERANGE;
6bedfcbb
LP
428 if ((unsigned long) (unsigned) l != l)
429 return -ERANGE;
430
22810041
LP
431 if (ret_u)
432 *ret_u = (unsigned) l;
433
6bedfcbb
LP
434 return 0;
435}
436
437int safe_atoi(const char *s, int *ret_i) {
fc80cabc 438 unsigned base = 0;
6bedfcbb
LP
439 char *x = NULL;
440 long l;
441
442 assert(s);
6bedfcbb 443
fc80cabc
LP
444 s += strspn(s, WHITESPACE);
445 s = mangle_base(s, &base);
446
6bedfcbb 447 errno = 0;
fc80cabc 448 l = strtol(s, &x, base);
b3267152 449 if (errno > 0)
2d49a208 450 return -errno;
b5ffbc55 451 if (!x || x == s || *x != 0)
2d49a208 452 return -EINVAL;
6bedfcbb
LP
453 if ((long) (int) l != l)
454 return -ERANGE;
455
22810041
LP
456 if (ret_i)
457 *ret_i = (int) l;
458
6bedfcbb
LP
459 return 0;
460}
461
ce51632a 462int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu) {
6bedfcbb
LP
463 char *x = NULL;
464 unsigned long long l;
465
466 assert(s);
707e93af
LP
467 assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
468
469 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
470 strchr(WHITESPACE, s[0]))
471 return -EINVAL;
6bedfcbb 472
2d49a208
LP
473 s += strspn(s, WHITESPACE);
474
707e93af
LP
475 if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
476 IN_SET(s[0], '+', '-'))
477 return -EINVAL;
478
479 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
480 s[0] == '0' && s[1] != 0)
481 return -EINVAL;
482
fc80cabc
LP
483 s = mangle_base(s, &base);
484
6bedfcbb 485 errno = 0;
707e93af 486 l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
b3267152 487 if (errno > 0)
2d49a208 488 return -errno;
b5ffbc55 489 if (!x || x == s || *x != 0)
2d49a208 490 return -EINVAL;
c78eefc1 491 if (l != 0 && s[0] == '-')
2d49a208 492 return -ERANGE;
6bedfcbb 493
22810041
LP
494 if (ret_llu)
495 *ret_llu = l;
496
6bedfcbb
LP
497 return 0;
498}
499
500int safe_atolli(const char *s, long long int *ret_lli) {
fc80cabc 501 unsigned base = 0;
6bedfcbb
LP
502 char *x = NULL;
503 long long l;
504
505 assert(s);
6bedfcbb 506
fc80cabc
LP
507 s += strspn(s, WHITESPACE);
508 s = mangle_base(s, &base);
509
6bedfcbb 510 errno = 0;
fc80cabc 511 l = strtoll(s, &x, base);
b3267152 512 if (errno > 0)
2d49a208 513 return -errno;
b5ffbc55 514 if (!x || x == s || *x != 0)
2d49a208 515 return -EINVAL;
6bedfcbb 516
22810041
LP
517 if (ret_lli)
518 *ret_lli = l;
519
6bedfcbb
LP
520 return 0;
521}
522
523int safe_atou8(const char *s, uint8_t *ret) {
fc80cabc 524 unsigned base = 0;
6bedfcbb 525 unsigned long l;
fc80cabc 526 char *x = NULL;
6bedfcbb
LP
527
528 assert(s);
6bedfcbb 529
2d49a208 530 s += strspn(s, WHITESPACE);
fc80cabc 531 s = mangle_base(s, &base);
2d49a208 532
6bedfcbb 533 errno = 0;
fc80cabc 534 l = strtoul(s, &x, base);
b3267152 535 if (errno > 0)
2d49a208 536 return -errno;
b5ffbc55 537 if (!x || x == s || *x != 0)
2d49a208 538 return -EINVAL;
c78eefc1 539 if (l != 0 && s[0] == '-')
2d49a208 540 return -ERANGE;
6bedfcbb
LP
541 if ((unsigned long) (uint8_t) l != l)
542 return -ERANGE;
543
22810041
LP
544 if (ret)
545 *ret = (uint8_t) l;
6bedfcbb
LP
546 return 0;
547}
548
5ef56aa2 549int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
6bedfcbb
LP
550 char *x = NULL;
551 unsigned long l;
552
553 assert(s);
707e93af
LP
554 assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
555
556 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
557 strchr(WHITESPACE, s[0]))
558 return -EINVAL;
6bedfcbb 559
2d49a208
LP
560 s += strspn(s, WHITESPACE);
561
707e93af
LP
562 if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
563 IN_SET(s[0], '+', '-'))
564 return -EINVAL;
565
566 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
567 s[0] == '0' && s[1] != 0)
568 return -EINVAL;
569
fc80cabc
LP
570 s = mangle_base(s, &base);
571
6bedfcbb 572 errno = 0;
707e93af 573 l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base));
b3267152 574 if (errno > 0)
2d49a208 575 return -errno;
b5ffbc55 576 if (!x || x == s || *x != 0)
2d49a208 577 return -EINVAL;
c78eefc1 578 if (l != 0 && s[0] == '-')
2d49a208 579 return -ERANGE;
6bedfcbb
LP
580 if ((unsigned long) (uint16_t) l != l)
581 return -ERANGE;
582
aa85e4d3
LP
583 if (ret)
584 *ret = (uint16_t) l;
585
6bedfcbb
LP
586 return 0;
587}
588
589int safe_atoi16(const char *s, int16_t *ret) {
fc80cabc 590 unsigned base = 0;
6bedfcbb
LP
591 char *x = NULL;
592 long l;
593
594 assert(s);
6bedfcbb 595
fc80cabc
LP
596 s += strspn(s, WHITESPACE);
597 s = mangle_base(s, &base);
598
6bedfcbb 599 errno = 0;
fc80cabc 600 l = strtol(s, &x, base);
b3267152 601 if (errno > 0)
2d49a208 602 return -errno;
b5ffbc55 603 if (!x || x == s || *x != 0)
2d49a208 604 return -EINVAL;
6bedfcbb
LP
605 if ((long) (int16_t) l != l)
606 return -ERANGE;
607
22810041
LP
608 if (ret)
609 *ret = (int16_t) l;
610
6bedfcbb
LP
611 return 0;
612}
613
614int safe_atod(const char *s, double *ret_d) {
e520e0fc 615 _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
6bedfcbb
LP
616 char *x = NULL;
617 double d = 0;
6bedfcbb
LP
618
619 assert(s);
6bedfcbb
LP
620
621 loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
622 if (loc == (locale_t) 0)
623 return -errno;
624
625 errno = 0;
626 d = strtod_l(s, &x, loc);
e520e0fc 627 if (errno > 0)
2d49a208 628 return -errno;
e520e0fc 629 if (!x || x == s || *x != 0)
2d49a208 630 return -EINVAL;
6bedfcbb 631
22810041
LP
632 if (ret_d)
633 *ret_d = (double) d;
634
6bedfcbb
LP
635 return 0;
636}
436dd70f
HV
637
638int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
639 size_t i;
640 unsigned val = 0;
641 const char *s;
642
643 s = *p;
644
f21f31b2 645 /* accept any number of digits, strtoull is limited to 19 */
9ed794a3 646 for (i=0; i < digits; i++,s++) {
436dd70f
HV
647 if (*s < '0' || *s > '9') {
648 if (i == 0)
649 return -EINVAL;
650
651 /* too few digits, pad with 0 */
652 for (; i < digits; i++)
653 val *= 10;
654
655 break;
656 }
657
658 val *= 10;
659 val += *s - '0';
660 }
661
662 /* maybe round up */
663 if (*s >= '5' && *s <= '9')
664 val++;
665
666 s += strspn(s, DIGITS);
667
668 *p = s;
669 *res = val;
670
671 return 0;
672}
9184ca48 673
5124866d 674int parse_percent_unbounded(const char *p) {
9184ca48 675 const char *pc, *n;
bac794f6 676 int r, v;
9184ca48
LP
677
678 pc = endswith(p, "%");
679 if (!pc)
680 return -EINVAL;
681
682 n = strndupa(p, pc - p);
bac794f6 683 r = safe_atoi(n, &v);
9184ca48
LP
684 if (r < 0)
685 return r;
bac794f6
LP
686 if (v < 0)
687 return -ERANGE;
5124866d 688
bac794f6 689 return v;
5124866d
DM
690}
691
692int parse_percent(const char *p) {
41bf0590 693 int v;
5124866d 694
41bf0590 695 v = parse_percent_unbounded(p);
9184ca48
LP
696 if (v > 100)
697 return -ERANGE;
698
5124866d 699 return v;
9184ca48 700}
41bf0590 701
958acea1
MKB
702int parse_permille_unbounded(const char *p) {
703 const char *pc, *pm, *dot, *n;
704 int r, q, v;
705
706 pm = endswith(p, "‰");
707 if (pm) {
708 n = strndupa(p, pm - p);
709 r = safe_atoi(n, &v);
710 if (r < 0)
711 return r;
8cbc92d5
LP
712 if (v < 0)
713 return -ERANGE;
958acea1
MKB
714 } else {
715 pc = endswith(p, "%");
716 if (!pc)
717 return -EINVAL;
718
719 dot = memchr(p, '.', pc - p);
720 if (dot) {
721 if (dot + 2 != pc)
722 return -EINVAL;
723 if (dot[1] < '0' || dot[1] > '9')
724 return -EINVAL;
725 q = dot[1] - '0';
726 n = strndupa(p, dot - p);
727 } else {
728 q = 0;
729 n = strndupa(p, pc - p);
730 }
731 r = safe_atoi(n, &v);
732 if (r < 0)
733 return r;
8cbc92d5
LP
734 if (v < 0)
735 return -ERANGE;
fbbe6d65 736 if (v > (INT_MAX - q) / 10)
958acea1
MKB
737 return -ERANGE;
738
739 v = v * 10 + q;
740 }
741
958acea1
MKB
742 return v;
743}
744
745int parse_permille(const char *p) {
746 int v;
747
748 v = parse_permille_unbounded(p);
749 if (v > 1000)
750 return -ERANGE;
751
752 return v;
753}
754
41bf0590
LP
755int parse_nice(const char *p, int *ret) {
756 int n, r;
757
758 r = safe_atoi(p, &n);
759 if (r < 0)
760 return r;
761
762 if (!nice_is_valid(n))
763 return -ERANGE;
764
765 *ret = n;
766 return 0;
767}
10452f7c
SS
768
769int parse_ip_port(const char *s, uint16_t *ret) {
770 uint16_t l;
771 int r;
772
773 r = safe_atou16(s, &l);
774 if (r < 0)
775 return r;
776
777 if (l == 0)
778 return -EINVAL;
779
780 *ret = (uint16_t) l;
781
782 return 0;
783}
fbcc7f41 784
926062f0
SS
785int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
786 unsigned l, h;
787 int r;
788
789 r = parse_range(s, &l, &h);
790 if (r < 0)
791 return r;
792
793 if (l <= 0 || l > 65535 || h <= 0 || h > 65535)
794 return -EINVAL;
795
796 if (h < l)
797 return -EINVAL;
798
799 *low = l;
800 *high = h;
801
802 return 0;
803}
804
53e1ba28
NF
805int parse_ip_prefix_length(const char *s, int *ret) {
806 unsigned l;
807 int r;
808
809 r = safe_atou(s, &l);
810 if (r < 0)
811 return r;
812
813 if (l > 128)
814 return -ERANGE;
815
816 *ret = (int) l;
817
818 return 0;
819}
820
fbcc7f41 821int parse_dev(const char *s, dev_t *ret) {
de06c0cf 822 const char *major;
fbcc7f41 823 unsigned x, y;
de06c0cf
LP
824 size_t n;
825 int r;
fbcc7f41 826
de06c0cf
LP
827 n = strspn(s, DIGITS);
828 if (n == 0)
fbcc7f41 829 return -EINVAL;
de06c0cf 830 if (s[n] != ':')
fbcc7f41
FB
831 return -EINVAL;
832
de06c0cf
LP
833 major = strndupa(s, n);
834 r = safe_atou(major, &x);
835 if (r < 0)
836 return r;
837
838 r = safe_atou(s + n + 1, &y);
839 if (r < 0)
840 return r;
841
842 if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
843 return -ERANGE;
844
845 *ret = makedev(x, y);
fbcc7f41
FB
846 return 0;
847}
e9eb2c02
LP
848
849int parse_oom_score_adjust(const char *s, int *ret) {
850 int r, v;
851
852 assert(s);
853 assert(ret);
854
855 r = safe_atoi(s, &v);
856 if (r < 0)
857 return r;
858
859 if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
860 return -ERANGE;
861
862 *ret = v;
863 return 0;
864}
510ca79c
AZ
865
866int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret) {
867 assert(ret);
868
869 if (i >= (~0UL << FSHIFT))
870 return -ERANGE;
871
872 i = i << FSHIFT;
873 f = DIV_ROUND_UP((f << FSHIFT), 100);
874
875 if (f >= FIXED_1)
876 return -ERANGE;
877
878 *ret = i | f;
879 return 0;
880}
881
882int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
883 const char *d, *f_str, *i_str;
884 unsigned long i, f;
885 int r;
886
887 assert(s);
888 assert(ret);
889
890 d = strchr(s, '.');
891 if (!d)
892 return -EINVAL;
893
894 i_str = strndupa(s, d - s);
895 f_str = d + 1;
896
897 r = safe_atolu_full(i_str, 10, &i);
898 if (r < 0)
899 return r;
900
901 r = safe_atolu_full(f_str, 10, &f);
902 if (r < 0)
903 return r;
904
905 return store_loadavg_fixed_point(i, f, ret);
906}