chiark / gitweb /
Prep v229: Add missing fixes from upstream [1/6] 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 #include <xlocale.h>
27
28 #include "alloc-util.h"
29 //#include "extract-word.h"
30 #include "macro.h"
31 #include "parse-util.h"
32 #include "string-util.h"
33
34 int 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
45 int 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
62         if (pid <= 0)
63                 return -ERANGE;
64
65         *ret_pid = pid;
66         return 0;
67 }
68
69 int parse_mode(const char *s, mode_t *ret) {
70         char *x;
71         long l;
72
73         assert(s);
74         assert(ret);
75
76         s += strspn(s, WHITESPACE);
77         if (s[0] == '-')
78                 return -ERANGE;
79
80         errno = 0;
81         l = strtol(s, &x, 8);
82         if (errno > 0)
83                 return -errno;
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
93 int 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
106 int 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);
155         assert(base == 1000 || base == 1024);
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);
174
175                 errno = 0;
176                 l = strtoull(p, &e, 10);
177                 if (errno > 0)
178                         return -errno;
179                 if (e == p)
180                         return -EINVAL;
181                 if (*p == '-')
182                         return -ERANGE;
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);
193                                 if (errno > 0)
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
234 #if 0 /// UNNEEDED by elogind
235 int parse_range(const char *t, unsigned *lower, unsigned *upper) {
236         _cleanup_free_ char *word = NULL;
237         unsigned l, u;
238         int r;
239
240         assert(lower);
241         assert(upper);
242
243         /* Extract the lower bound. */
244         r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
245         if (r < 0)
246                 return r;
247         if (r == 0)
248                 return -EINVAL;
249
250         r = safe_atou(word, &l);
251         if (r < 0)
252                 return r;
253
254         /* Check for the upper bound and extract it if needed */
255         if (!t)
256                 /* Single number with no dashes. */
257                 u = l;
258         else if (!*t)
259                 /* Trailing dash is an error. */
260                 return -EINVAL;
261         else {
262                 r = safe_atou(t, &u);
263                 if (r < 0)
264                         return r;
265         }
266
267         *lower = l;
268         *upper = u;
269         return 0;
270 }
271
272 char *format_bytes(char *buf, size_t l, uint64_t t) {
273         unsigned i;
274
275         /* This only does IEC units so far */
276
277         static const struct {
278                 const char *suffix;
279                 uint64_t factor;
280         } table[] = {
281                 { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
282                 { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
283                 { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
284                 { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
285                 { "M", UINT64_C(1024)*UINT64_C(1024) },
286                 { "K", UINT64_C(1024) },
287         };
288
289         if (t == (uint64_t) -1)
290                 return NULL;
291
292         for (i = 0; i < ELEMENTSOF(table); i++) {
293
294                 if (t >= table[i].factor) {
295                         snprintf(buf, l,
296                                  "%" PRIu64 ".%" PRIu64 "%s",
297                                  t / table[i].factor,
298                                  ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
299                                  table[i].suffix);
300
301                         goto finish;
302                 }
303         }
304
305         snprintf(buf, l, "%" PRIu64 "B", t);
306
307 finish:
308         buf[l-1] = 0;
309         return buf;
310
311 }
312 #endif // 0
313
314 int safe_atou(const char *s, unsigned *ret_u) {
315         char *x = NULL;
316         unsigned long l;
317
318         assert(s);
319         assert(ret_u);
320
321         /* strtoul() is happy to parse negative values, and silently
322          * converts them to unsigned values without generating an
323          * error. We want a clean error, hence let's look for the "-"
324          * prefix on our own, and generate an error. But let's do so
325          * only after strtoul() validated that the string is clean
326          * otherwise, so that we return EINVAL preferably over
327          * ERANGE. */
328
329         s += strspn(s, WHITESPACE);
330
331         errno = 0;
332         l = strtoul(s, &x, 0);
333         if (errno > 0)
334                 return -errno;
335         if (!x || x == s || *x)
336                 return -EINVAL;
337         if (s[0] == '-')
338                 return -ERANGE;
339         if ((unsigned long) (unsigned) l != l)
340                 return -ERANGE;
341
342         *ret_u = (unsigned) l;
343         return 0;
344 }
345
346 int safe_atoi(const char *s, int *ret_i) {
347         char *x = NULL;
348         long l;
349
350         assert(s);
351         assert(ret_i);
352
353         errno = 0;
354         l = strtol(s, &x, 0);
355         if (errno > 0)
356                 return -errno;
357         if (!x || x == s || *x)
358                 return -EINVAL;
359         if ((long) (int) l != l)
360                 return -ERANGE;
361
362         *ret_i = (int) l;
363         return 0;
364 }
365
366 int safe_atollu(const char *s, long long unsigned *ret_llu) {
367         char *x = NULL;
368         unsigned long long l;
369
370         assert(s);
371         assert(ret_llu);
372
373         s += strspn(s, WHITESPACE);
374
375         errno = 0;
376         l = strtoull(s, &x, 0);
377         if (errno > 0)
378                 return -errno;
379         if (!x || x == s || *x)
380                 return -EINVAL;
381         if (*s == '-')
382                 return -ERANGE;
383
384         *ret_llu = l;
385         return 0;
386 }
387
388 int safe_atolli(const char *s, long long int *ret_lli) {
389         char *x = NULL;
390         long long l;
391
392         assert(s);
393         assert(ret_lli);
394
395         errno = 0;
396         l = strtoll(s, &x, 0);
397         if (errno > 0)
398                 return -errno;
399         if (!x || x == s || *x)
400                 return -EINVAL;
401
402         *ret_lli = l;
403         return 0;
404 }
405
406 int safe_atou8(const char *s, uint8_t *ret) {
407         char *x = NULL;
408         unsigned long l;
409
410         assert(s);
411         assert(ret);
412
413         s += strspn(s, WHITESPACE);
414
415         errno = 0;
416         l = strtoul(s, &x, 0);
417         if (errno > 0)
418                 return -errno;
419         if (!x || x == s || *x)
420                 return -EINVAL;
421         if (s[0] == '-')
422                 return -ERANGE;
423         if ((unsigned long) (uint8_t) l != l)
424                 return -ERANGE;
425
426         *ret = (uint8_t) l;
427         return 0;
428 }
429
430 int safe_atou16(const char *s, uint16_t *ret) {
431         char *x = NULL;
432         unsigned long l;
433
434         assert(s);
435         assert(ret);
436
437         s += strspn(s, WHITESPACE);
438
439         errno = 0;
440         l = strtoul(s, &x, 0);
441         if (errno > 0)
442                 return -errno;
443         if (!x || x == s || *x)
444                 return -EINVAL;
445         if (s[0] == '-')
446                 return -ERANGE;
447         if ((unsigned long) (uint16_t) l != l)
448                 return -ERANGE;
449
450         *ret = (uint16_t) l;
451         return 0;
452 }
453
454 int safe_atoi16(const char *s, int16_t *ret) {
455         char *x = NULL;
456         long l;
457
458         assert(s);
459         assert(ret);
460
461         errno = 0;
462         l = strtol(s, &x, 0);
463         if (errno > 0)
464                 return -errno;
465         if (!x || x == s || *x)
466                 return -EINVAL;
467         if ((long) (int16_t) l != l)
468                 return -ERANGE;
469
470         *ret = (int16_t) l;
471         return 0;
472 }
473
474 int safe_atod(const char *s, double *ret_d) {
475         char *x = NULL;
476         double d = 0;
477         locale_t loc;
478
479         assert(s);
480         assert(ret_d);
481
482         loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
483         if (loc == (locale_t) 0)
484                 return -errno;
485
486         errno = 0;
487         d = strtod_l(s, &x, loc);
488         if (errno > 0) {
489                 freelocale(loc);
490                 return -errno;
491         }
492         if (!x || x == s || *x) {
493                 freelocale(loc);
494                 return -EINVAL;
495         }
496
497         freelocale(loc);
498         *ret_d = (double) d;
499         return 0;
500 }
501
502 int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
503         size_t i;
504         unsigned val = 0;
505         const char *s;
506
507         s = *p;
508
509         /* accept any number of digits, strtoull is limted to 19 */
510         for(i=0; i < digits; i++,s++) {
511                 if (*s < '0' || *s > '9') {
512                         if (i == 0)
513                                 return -EINVAL;
514
515                         /* too few digits, pad with 0 */
516                         for (; i < digits; i++)
517                                 val *= 10;
518
519                         break;
520                 }
521
522                 val *= 10;
523                 val += *s - '0';
524         }
525
526         /* maybe round up */
527         if (*s >= '5' && *s <= '9')
528                 val++;
529
530         s += strspn(s, DIGITS);
531
532         *p = s;
533         *res = val;
534
535         return 0;
536 }