chiark / gitweb /
Prep v228: With most functions split out, clean up the enormous includes list in...
[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 #if 0 /// UNNEEDED by elogind
229 int parse_range(const char *t, unsigned *lower, unsigned *upper) {
230         _cleanup_free_ char *word = NULL;
231         unsigned l, u;
232         int r;
233
234         assert(lower);
235         assert(upper);
236
237         /* Extract the lower bound. */
238         r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
239         if (r < 0)
240                 return r;
241         if (r == 0)
242                 return -EINVAL;
243
244         r = safe_atou(word, &l);
245         if (r < 0)
246                 return r;
247
248         /* Check for the upper bound and extract it if needed */
249         if (!t)
250                 /* Single number with no dashes. */
251                 u = l;
252         else if (!*t)
253                 /* Trailing dash is an error. */
254                 return -EINVAL;
255         else {
256                 r = safe_atou(t, &u);
257                 if (r < 0)
258                         return r;
259         }
260
261         *lower = l;
262         *upper = u;
263         return 0;
264 }
265
266 char *format_bytes(char *buf, size_t l, uint64_t t) {
267         unsigned i;
268
269         /* This only does IEC units so far */
270
271         static const struct {
272                 const char *suffix;
273                 uint64_t factor;
274         } table[] = {
275                 { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
276                 { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
277                 { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
278                 { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
279                 { "M", UINT64_C(1024)*UINT64_C(1024) },
280                 { "K", UINT64_C(1024) },
281         };
282
283         if (t == (uint64_t) -1)
284                 return NULL;
285
286         for (i = 0; i < ELEMENTSOF(table); i++) {
287
288                 if (t >= table[i].factor) {
289                         snprintf(buf, l,
290                                  "%" PRIu64 ".%" PRIu64 "%s",
291                                  t / table[i].factor,
292                                  ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
293                                  table[i].suffix);
294
295                         goto finish;
296                 }
297         }
298
299         snprintf(buf, l, "%" PRIu64 "B", t);
300
301 finish:
302         buf[l-1] = 0;
303         return buf;
304
305 }
306 #endif // 0
307
308 int safe_atou(const char *s, unsigned *ret_u) {
309         char *x = NULL;
310         unsigned long l;
311
312         assert(s);
313         assert(ret_u);
314
315         /* strtoul() is happy to parse negative values, and silently
316          * converts them to unsigned values without generating an
317          * error. We want a clean error, hence let's look for the "-"
318          * prefix on our own, and generate an error. But let's do so
319          * only after strtoul() validated that the string is clean
320          * otherwise, so that we return EINVAL preferably over
321          * ERANGE. */
322
323         s += strspn(s, WHITESPACE);
324
325         errno = 0;
326         l = strtoul(s, &x, 0);
327         if (errno != 0)
328                 return -errno;
329         if (!x || x == s || *x)
330                 return -EINVAL;
331         if (s[0] == '-')
332                 return -ERANGE;
333         if ((unsigned long) (unsigned) l != l)
334                 return -ERANGE;
335
336         *ret_u = (unsigned) l;
337         return 0;
338 }
339
340 int safe_atoi(const char *s, int *ret_i) {
341         char *x = NULL;
342         long l;
343
344         assert(s);
345         assert(ret_i);
346
347         errno = 0;
348         l = strtol(s, &x, 0);
349         if (errno != 0)
350                 return -errno;
351         if (!x || x == s || *x)
352                 return -EINVAL;
353         if ((long) (int) l != l)
354                 return -ERANGE;
355
356         *ret_i = (int) l;
357         return 0;
358 }
359
360 int safe_atollu(const char *s, long long unsigned *ret_llu) {
361         char *x = NULL;
362         unsigned long long l;
363
364         assert(s);
365         assert(ret_llu);
366
367         s += strspn(s, WHITESPACE);
368
369         errno = 0;
370         l = strtoull(s, &x, 0);
371         if (errno != 0)
372                 return -errno;
373         if (!x || x == s || *x)
374                 return -EINVAL;
375         if (*s == '-')
376                 return -ERANGE;
377
378         *ret_llu = l;
379         return 0;
380 }
381
382 int safe_atolli(const char *s, long long int *ret_lli) {
383         char *x = NULL;
384         long long l;
385
386         assert(s);
387         assert(ret_lli);
388
389         errno = 0;
390         l = strtoll(s, &x, 0);
391         if (errno != 0)
392                 return -errno;
393         if (!x || x == s || *x)
394                 return -EINVAL;
395
396         *ret_lli = l;
397         return 0;
398 }
399
400 int safe_atou8(const char *s, uint8_t *ret) {
401         char *x = NULL;
402         unsigned long l;
403
404         assert(s);
405         assert(ret);
406
407         s += strspn(s, WHITESPACE);
408
409         errno = 0;
410         l = strtoul(s, &x, 0);
411         if (errno != 0)
412                 return -errno;
413         if (!x || x == s || *x)
414                 return -EINVAL;
415         if (s[0] == '-')
416                 return -ERANGE;
417         if ((unsigned long) (uint8_t) l != l)
418                 return -ERANGE;
419
420         *ret = (uint8_t) l;
421         return 0;
422 }
423
424 int safe_atou16(const char *s, uint16_t *ret) {
425         char *x = NULL;
426         unsigned long l;
427
428         assert(s);
429         assert(ret);
430
431         s += strspn(s, WHITESPACE);
432
433         errno = 0;
434         l = strtoul(s, &x, 0);
435         if (errno != 0)
436                 return -errno;
437         if (!x || x == s || *x)
438                 return -EINVAL;
439         if (s[0] == '-')
440                 return -ERANGE;
441         if ((unsigned long) (uint16_t) l != l)
442                 return -ERANGE;
443
444         *ret = (uint16_t) l;
445         return 0;
446 }
447
448 int safe_atoi16(const char *s, int16_t *ret) {
449         char *x = NULL;
450         long l;
451
452         assert(s);
453         assert(ret);
454
455         errno = 0;
456         l = strtol(s, &x, 0);
457         if (errno != 0)
458                 return -errno;
459         if (!x || x == s || *x)
460                 return -EINVAL;
461         if ((long) (int16_t) l != l)
462                 return -ERANGE;
463
464         *ret = (int16_t) l;
465         return 0;
466 }
467
468 int safe_atod(const char *s, double *ret_d) {
469         char *x = NULL;
470         double d = 0;
471         locale_t loc;
472
473         assert(s);
474         assert(ret_d);
475
476         loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
477         if (loc == (locale_t) 0)
478                 return -errno;
479
480         errno = 0;
481         d = strtod_l(s, &x, loc);
482         if (errno != 0) {
483                 freelocale(loc);
484                 return -errno;
485         }
486         if (!x || x == s || *x) {
487                 freelocale(loc);
488                 return -EINVAL;
489         }
490
491         freelocale(loc);
492         *ret_d = (double) d;
493         return 0;
494 }