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