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