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