chiark / gitweb /
Prep v228: Add remaining updates from upstream (1/3)
[elogind.git] / src / basic / parse-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "alloc-util.h"
23 //#include "extract-word.h"
24 #include "parse-util.h"
25 #include "string-util.h"
26 #include "util.h"
27
28 int parse_boolean(const char *v) {
29         assert(v);
30
31         if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
32                 return 1;
33         else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
34                 return 0;
35
36         return -EINVAL;
37 }
38
39 int parse_pid(const char *s, pid_t* ret_pid) {
40         unsigned long ul = 0;
41         pid_t pid;
42         int r;
43
44         assert(s);
45         assert(ret_pid);
46
47         r = safe_atolu(s, &ul);
48         if (r < 0)
49                 return r;
50
51         pid = (pid_t) ul;
52
53         if ((unsigned long) pid != ul)
54                 return -ERANGE;
55
56         if (pid <= 0)
57                 return -ERANGE;
58
59         *ret_pid = pid;
60         return 0;
61 }
62
63 int parse_mode(const char *s, mode_t *ret) {
64         char *x;
65         long l;
66
67         assert(s);
68         assert(ret);
69
70         s += strspn(s, WHITESPACE);
71         if (s[0] == '-')
72                 return -ERANGE;
73
74         errno = 0;
75         l = strtol(s, &x, 8);
76         if (errno != 0)
77                 return -errno;
78         if (!x || x == s || *x)
79                 return -EINVAL;
80         if (l < 0 || l  > 07777)
81                 return -ERANGE;
82
83         *ret = (mode_t) l;
84         return 0;
85 }
86
87 int parse_ifindex(const char *s, int *ret) {
88         int ifi, r;
89
90         r = safe_atoi(s, &ifi);
91         if (r < 0)
92                 return r;
93         if (ifi <= 0)
94                 return -EINVAL;
95
96         *ret = ifi;
97         return 0;
98 }
99
100 int parse_size(const char *t, uint64_t base, uint64_t *size) {
101
102         /* Soo, sometimes we want to parse IEC binary suffixes, and
103          * sometimes SI decimal suffixes. This function can parse
104          * both. Which one is the right way depends on the
105          * context. Wikipedia suggests that SI is customary for
106          * hardware metrics and network speeds, while IEC is
107          * customary for most data sizes used by software and volatile
108          * (RAM) memory. Hence be careful which one you pick!
109          *
110          * In either case we use just K, M, G as suffix, and not Ki,
111          * Mi, Gi or so (as IEC would suggest). That's because that's
112          * frickin' ugly. But this means you really need to make sure
113          * to document which base you are parsing when you use this
114          * call. */
115
116         struct table {
117                 const char *suffix;
118                 unsigned long long factor;
119         };
120
121         static const struct table iec[] = {
122                 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
123                 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
124                 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
125                 { "G", 1024ULL*1024ULL*1024ULL },
126                 { "M", 1024ULL*1024ULL },
127                 { "K", 1024ULL },
128                 { "B", 1ULL },
129                 { "",  1ULL },
130         };
131
132         static const struct table si[] = {
133                 { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
134                 { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
135                 { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
136                 { "G", 1000ULL*1000ULL*1000ULL },
137                 { "M", 1000ULL*1000ULL },
138                 { "K", 1000ULL },
139                 { "B", 1ULL },
140                 { "",  1ULL },
141         };
142
143         const struct table *table;
144         const char *p;
145         unsigned long long r = 0;
146         unsigned n_entries, start_pos = 0;
147
148         assert(t);
149         assert(base == 1000 || base == 1024);
150         assert(size);
151
152         if (base == 1000) {
153                 table = si;
154                 n_entries = ELEMENTSOF(si);
155         } else {
156                 table = iec;
157                 n_entries = ELEMENTSOF(iec);
158         }
159
160         p = t;
161         do {
162                 unsigned long long l, tmp;
163                 double frac = 0;
164                 char *e;
165                 unsigned i;
166
167                 p += strspn(p, WHITESPACE);
168
169                 errno = 0;
170                 l = strtoull(p, &e, 10);
171                 if (errno != 0)
172                         return -errno;
173                 if (e == p)
174                         return -EINVAL;
175                 if (*p == '-')
176                         return -ERANGE;
177
178                 if (*e == '.') {
179                         e++;
180
181                         /* strtoull() itself would accept space/+/- */
182                         if (*e >= '0' && *e <= '9') {
183                                 unsigned long long l2;
184                                 char *e2;
185
186                                 l2 = strtoull(e, &e2, 10);
187                                 if (errno != 0)
188                                         return -errno;
189
190                                 /* Ignore failure. E.g. 10.M is valid */
191                                 frac = l2;
192                                 for (; e < e2; e++)
193                                         frac /= 10;
194                         }
195                 }
196
197                 e += strspn(e, WHITESPACE);
198
199                 for (i = start_pos; i < n_entries; i++)
200                         if (startswith(e, table[i].suffix))
201                                 break;
202
203                 if (i >= n_entries)
204                         return -EINVAL;
205
206                 if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
207                         return -ERANGE;
208
209                 tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
210                 if (tmp > ULLONG_MAX - r)
211                         return -ERANGE;
212
213                 r += tmp;
214                 if ((unsigned long long) (uint64_t) r != r)
215                         return -ERANGE;
216
217                 p = e + strlen(table[i].suffix);
218
219                 start_pos = i + 1;
220
221         } while (*p);
222
223         *size = r;
224
225         return 0;
226 }
227
228 /// UNNEEDED by elogind
229 #if 0
230 int parse_range(const char *t, unsigned *lower, unsigned *upper) {
231         _cleanup_free_ char *word = NULL;
232         unsigned l, u;
233         int r;
234
235         assert(lower);
236         assert(upper);
237
238         /* Extract the lower bound. */
239         r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
240         if (r < 0)
241                 return r;
242         if (r == 0)
243                 return -EINVAL;
244
245         r = safe_atou(word, &l);
246         if (r < 0)
247                 return r;
248
249         /* Check for the upper bound and extract it if needed */
250         if (!t)
251                 /* Single number with no dashes. */
252                 u = l;
253         else if (!*t)
254                 /* Trailing dash is an error. */
255                 return -EINVAL;
256         else {
257                 r = safe_atou(t, &u);
258                 if (r < 0)
259                         return r;
260         }
261
262         *lower = l;
263         *upper = u;
264         return 0;
265 }
266
267 char *format_bytes(char *buf, size_t l, uint64_t t) {
268         unsigned i;
269
270         /* This only does IEC units so far */
271
272         static const struct {
273                 const char *suffix;
274                 uint64_t factor;
275         } table[] = {
276                 { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
277                 { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
278                 { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
279                 { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
280                 { "M", UINT64_C(1024)*UINT64_C(1024) },
281                 { "K", UINT64_C(1024) },
282         };
283
284         if (t == (uint64_t) -1)
285                 return NULL;
286
287         for (i = 0; i < ELEMENTSOF(table); i++) {
288
289                 if (t >= table[i].factor) {
290                         snprintf(buf, l,
291                                  "%" PRIu64 ".%" PRIu64 "%s",
292                                  t / table[i].factor,
293                                  ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
294                                  table[i].suffix);
295
296                         goto finish;
297                 }
298         }
299
300         snprintf(buf, l, "%" PRIu64 "B", t);
301
302 finish:
303         buf[l-1] = 0;
304         return buf;
305
306 }
307 #endif // 0
308
309 int safe_atou(const char *s, unsigned *ret_u) {
310         char *x = NULL;
311         unsigned long l;
312
313         assert(s);
314         assert(ret_u);
315
316         /* strtoul() is happy to parse negative values, and silently
317          * converts them to unsigned values without generating an
318          * error. We want a clean error, hence let's look for the "-"
319          * prefix on our own, and generate an error. But let's do so
320          * only after strtoul() validated that the string is clean
321          * otherwise, so that we return EINVAL preferably over
322          * ERANGE. */
323
324         s += strspn(s, WHITESPACE);
325
326         errno = 0;
327         l = strtoul(s, &x, 0);
328         if (errno != 0)
329                 return -errno;
330         if (!x || x == s || *x)
331                 return -EINVAL;
332         if (s[0] == '-')
333                 return -ERANGE;
334         if ((unsigned long) (unsigned) l != l)
335                 return -ERANGE;
336
337         *ret_u = (unsigned) l;
338         return 0;
339 }
340
341 int safe_atoi(const char *s, int *ret_i) {
342         char *x = NULL;
343         long l;
344
345         assert(s);
346         assert(ret_i);
347
348         errno = 0;
349         l = strtol(s, &x, 0);
350         if (errno != 0)
351                 return -errno;
352         if (!x || x == s || *x)
353                 return -EINVAL;
354         if ((long) (int) l != l)
355                 return -ERANGE;
356
357         *ret_i = (int) l;
358         return 0;
359 }
360
361 int safe_atollu(const char *s, long long unsigned *ret_llu) {
362         char *x = NULL;
363         unsigned long long l;
364
365         assert(s);
366         assert(ret_llu);
367
368         s += strspn(s, WHITESPACE);
369
370         errno = 0;
371         l = strtoull(s, &x, 0);
372         if (errno != 0)
373                 return -errno;
374         if (!x || x == s || *x)
375                 return -EINVAL;
376         if (*s == '-')
377                 return -ERANGE;
378
379         *ret_llu = l;
380         return 0;
381 }
382
383 int safe_atolli(const char *s, long long int *ret_lli) {
384         char *x = NULL;
385         long long l;
386
387         assert(s);
388         assert(ret_lli);
389
390         errno = 0;
391         l = strtoll(s, &x, 0);
392         if (errno != 0)
393                 return -errno;
394         if (!x || x == s || *x)
395                 return -EINVAL;
396
397         *ret_lli = l;
398         return 0;
399 }
400
401 int safe_atou8(const char *s, uint8_t *ret) {
402         char *x = NULL;
403         unsigned long l;
404
405         assert(s);
406         assert(ret);
407
408         s += strspn(s, WHITESPACE);
409
410         errno = 0;
411         l = strtoul(s, &x, 0);
412         if (errno != 0)
413                 return -errno;
414         if (!x || x == s || *x)
415                 return -EINVAL;
416         if (s[0] == '-')
417                 return -ERANGE;
418         if ((unsigned long) (uint8_t) l != l)
419                 return -ERANGE;
420
421         *ret = (uint8_t) l;
422         return 0;
423 }
424
425 int safe_atou16(const char *s, uint16_t *ret) {
426         char *x = NULL;
427         unsigned long l;
428
429         assert(s);
430         assert(ret);
431
432         s += strspn(s, WHITESPACE);
433
434         errno = 0;
435         l = strtoul(s, &x, 0);
436         if (errno != 0)
437                 return -errno;
438         if (!x || x == s || *x)
439                 return -EINVAL;
440         if (s[0] == '-')
441                 return -ERANGE;
442         if ((unsigned long) (uint16_t) l != l)
443                 return -ERANGE;
444
445         *ret = (uint16_t) l;
446         return 0;
447 }
448
449 int safe_atoi16(const char *s, int16_t *ret) {
450         char *x = NULL;
451         long l;
452
453         assert(s);
454         assert(ret);
455
456         errno = 0;
457         l = strtol(s, &x, 0);
458         if (errno != 0)
459                 return -errno;
460         if (!x || x == s || *x)
461                 return -EINVAL;
462         if ((long) (int16_t) l != l)
463                 return -ERANGE;
464
465         *ret = (int16_t) l;
466         return 0;
467 }
468
469 int safe_atod(const char *s, double *ret_d) {
470         char *x = NULL;
471         double d = 0;
472         locale_t loc;
473
474         assert(s);
475         assert(ret_d);
476
477         loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
478         if (loc == (locale_t) 0)
479                 return -errno;
480
481         errno = 0;
482         d = strtod_l(s, &x, loc);
483         if (errno != 0) {
484                 freelocale(loc);
485                 return -errno;
486         }
487         if (!x || x == s || *x) {
488                 freelocale(loc);
489                 return -EINVAL;
490         }
491
492         freelocale(loc);
493         *ret_d = (double) d;
494         return 0;
495 }