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