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