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