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