chiark / gitweb /
macro: introduce TAKE_PTR() macro
[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 = TAKE_PTR(n);
333
334         return 0;
335 }
336
337 char *format_bytes(char *buf, size_t l, uint64_t t) {
338         unsigned i;
339
340         /* This only does IEC units so far */
341
342         static const struct {
343                 const char *suffix;
344                 uint64_t factor;
345         } table[] = {
346                 { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
347                 { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
348                 { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
349                 { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
350                 { "M", UINT64_C(1024)*UINT64_C(1024) },
351                 { "K", UINT64_C(1024) },
352         };
353
354         if (t == (uint64_t) -1)
355                 return NULL;
356
357         for (i = 0; i < ELEMENTSOF(table); i++) {
358
359                 if (t >= table[i].factor) {
360                         snprintf(buf, l,
361                                  "%" PRIu64 ".%" PRIu64 "%s",
362                                  t / table[i].factor,
363                                  ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
364                                  table[i].suffix);
365
366                         goto finish;
367                 }
368         }
369
370         snprintf(buf, l, "%" PRIu64 "B", t);
371
372 finish:
373         buf[l-1] = 0;
374         return buf;
375
376 }
377
378 int safe_atou(const char *s, unsigned *ret_u) {
379         char *x = NULL;
380         unsigned long l;
381
382         assert(s);
383         assert(ret_u);
384
385         /* strtoul() is happy to parse negative values, and silently
386          * converts them to unsigned values without generating an
387          * error. We want a clean error, hence let's look for the "-"
388          * prefix on our own, and generate an error. But let's do so
389          * only after strtoul() validated that the string is clean
390          * otherwise, so that we return EINVAL preferably over
391          * ERANGE. */
392
393         s += strspn(s, WHITESPACE);
394
395         errno = 0;
396         l = strtoul(s, &x, 0);
397         if (errno > 0)
398                 return -errno;
399         if (!x || x == s || *x != 0)
400                 return -EINVAL;
401         if (s[0] == '-')
402                 return -ERANGE;
403         if ((unsigned long) (unsigned) l != l)
404                 return -ERANGE;
405
406         *ret_u = (unsigned) l;
407         return 0;
408 }
409
410 int safe_atoi(const char *s, int *ret_i) {
411         char *x = NULL;
412         long l;
413
414         assert(s);
415         assert(ret_i);
416
417         errno = 0;
418         l = strtol(s, &x, 0);
419         if (errno > 0)
420                 return -errno;
421         if (!x || x == s || *x != 0)
422                 return -EINVAL;
423         if ((long) (int) l != l)
424                 return -ERANGE;
425
426         *ret_i = (int) l;
427         return 0;
428 }
429
430 int safe_atollu(const char *s, long long unsigned *ret_llu) {
431         char *x = NULL;
432         unsigned long long l;
433
434         assert(s);
435         assert(ret_llu);
436
437         s += strspn(s, WHITESPACE);
438
439         errno = 0;
440         l = strtoull(s, &x, 0);
441         if (errno > 0)
442                 return -errno;
443         if (!x || x == s || *x != 0)
444                 return -EINVAL;
445         if (*s == '-')
446                 return -ERANGE;
447
448         *ret_llu = l;
449         return 0;
450 }
451
452 int safe_atolli(const char *s, long long int *ret_lli) {
453         char *x = NULL;
454         long long l;
455
456         assert(s);
457         assert(ret_lli);
458
459         errno = 0;
460         l = strtoll(s, &x, 0);
461         if (errno > 0)
462                 return -errno;
463         if (!x || x == s || *x != 0)
464                 return -EINVAL;
465
466         *ret_lli = l;
467         return 0;
468 }
469
470 int safe_atou8(const char *s, uint8_t *ret) {
471         char *x = NULL;
472         unsigned long l;
473
474         assert(s);
475         assert(ret);
476
477         s += strspn(s, WHITESPACE);
478
479         errno = 0;
480         l = strtoul(s, &x, 0);
481         if (errno > 0)
482                 return -errno;
483         if (!x || x == s || *x != 0)
484                 return -EINVAL;
485         if (s[0] == '-')
486                 return -ERANGE;
487         if ((unsigned long) (uint8_t) l != l)
488                 return -ERANGE;
489
490         *ret = (uint8_t) l;
491         return 0;
492 }
493
494 int safe_atou16(const char *s, uint16_t *ret) {
495         char *x = NULL;
496         unsigned long l;
497
498         assert(s);
499         assert(ret);
500
501         s += strspn(s, WHITESPACE);
502
503         errno = 0;
504         l = strtoul(s, &x, 0);
505         if (errno > 0)
506                 return -errno;
507         if (!x || x == s || *x != 0)
508                 return -EINVAL;
509         if (s[0] == '-')
510                 return -ERANGE;
511         if ((unsigned long) (uint16_t) l != l)
512                 return -ERANGE;
513
514         *ret = (uint16_t) l;
515         return 0;
516 }
517
518 int safe_atoi16(const char *s, int16_t *ret) {
519         char *x = NULL;
520         long l;
521
522         assert(s);
523         assert(ret);
524
525         errno = 0;
526         l = strtol(s, &x, 0);
527         if (errno > 0)
528                 return -errno;
529         if (!x || x == s || *x != 0)
530                 return -EINVAL;
531         if ((long) (int16_t) l != l)
532                 return -ERANGE;
533
534         *ret = (int16_t) l;
535         return 0;
536 }
537
538 int safe_atoux16(const char *s, uint16_t *ret) {
539         char *x = NULL;
540         unsigned long l;
541
542         assert(s);
543         assert(ret);
544
545         s += strspn(s, WHITESPACE);
546
547         errno = 0;
548         l = strtoul(s, &x, 16);
549         if (errno > 0)
550                 return -errno;
551         if (!x || x == s || *x != 0)
552                 return -EINVAL;
553         if (s[0] == '-')
554                 return -ERANGE;
555         if ((unsigned long) (uint16_t) l != l)
556                 return -ERANGE;
557
558         *ret = (uint16_t) l;
559         return 0;
560 }
561
562 int safe_atod(const char *s, double *ret_d) {
563         _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
564         char *x = NULL;
565         double d = 0;
566
567         assert(s);
568         assert(ret_d);
569
570         loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
571         if (loc == (locale_t) 0)
572                 return -errno;
573
574         errno = 0;
575         d = strtod_l(s, &x, loc);
576         if (errno > 0)
577                 return -errno;
578         if (!x || x == s || *x != 0)
579                 return -EINVAL;
580
581         *ret_d = (double) d;
582         return 0;
583 }
584
585 int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
586         size_t i;
587         unsigned val = 0;
588         const char *s;
589
590         s = *p;
591
592         /* accept any number of digits, strtoull is limted to 19 */
593         for (i=0; i < digits; i++,s++) {
594                 if (*s < '0' || *s > '9') {
595                         if (i == 0)
596                                 return -EINVAL;
597
598                         /* too few digits, pad with 0 */
599                         for (; i < digits; i++)
600                                 val *= 10;
601
602                         break;
603                 }
604
605                 val *= 10;
606                 val += *s - '0';
607         }
608
609         /* maybe round up */
610         if (*s >= '5' && *s <= '9')
611                 val++;
612
613         s += strspn(s, DIGITS);
614
615         *p = s;
616         *res = val;
617
618         return 0;
619 }
620
621 int parse_percent_unbounded(const char *p) {
622         const char *pc, *n;
623         int r, v;
624
625         pc = endswith(p, "%");
626         if (!pc)
627                 return -EINVAL;
628
629         n = strndupa(p, pc - p);
630         r = safe_atoi(n, &v);
631         if (r < 0)
632                 return r;
633         if (v < 0)
634                 return -ERANGE;
635
636         return v;
637 }
638
639 int parse_percent(const char *p) {
640         int v;
641
642         v = parse_percent_unbounded(p);
643         if (v > 100)
644                 return -ERANGE;
645
646         return v;
647 }
648
649 #if 0 /// UNNEEDED by elogind
650 int parse_nice(const char *p, int *ret) {
651         int n, r;
652
653         r = safe_atoi(p, &n);
654         if (r < 0)
655                 return r;
656
657         if (!nice_is_valid(n))
658                 return -ERANGE;
659
660         *ret = n;
661         return 0;
662 }
663
664 int parse_ip_port(const char *s, uint16_t *ret) {
665         uint16_t l;
666         int r;
667
668         r = safe_atou16(s, &l);
669         if (r < 0)
670                 return r;
671
672         if (l == 0)
673                 return -EINVAL;
674
675         *ret = (uint16_t) l;
676
677         return 0;
678 }
679 #endif // 0
680
681 int parse_dev(const char *s, dev_t *ret) {
682         unsigned x, y;
683         dev_t d;
684
685         if (sscanf(s, "%u:%u", &x, &y) != 2)
686                 return -EINVAL;
687
688         d = makedev(x, y);
689         if ((unsigned) major(d) != x || (unsigned) minor(d) != y)
690                 return -EINVAL;
691
692         *ret = d;
693         return 0;
694 }