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