]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/parse-util.c
util-lib: split string parsing related calls from util.[ch] into parse-util.[ch]
[thirdparty/systemd.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 "parse-util.h"
23 #include "string-util.h"
24 #include "util.h"
25
26 int parse_boolean(const char *v) {
27 assert(v);
28
29 if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
30 return 1;
31 else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
32 return 0;
33
34 return -EINVAL;
35 }
36
37 int parse_pid(const char *s, pid_t* ret_pid) {
38 unsigned long ul = 0;
39 pid_t pid;
40 int r;
41
42 assert(s);
43 assert(ret_pid);
44
45 r = safe_atolu(s, &ul);
46 if (r < 0)
47 return r;
48
49 pid = (pid_t) ul;
50
51 if ((unsigned long) pid != ul)
52 return -ERANGE;
53
54 if (pid <= 0)
55 return -ERANGE;
56
57 *ret_pid = pid;
58 return 0;
59 }
60
61 int parse_mode(const char *s, mode_t *ret) {
62 char *x;
63 long l;
64
65 assert(s);
66 assert(ret);
67
68 errno = 0;
69 l = strtol(s, &x, 8);
70 if (errno != 0)
71 return -errno;
72
73 if (!x || x == s || *x)
74 return -EINVAL;
75 if (l < 0 || l > 07777)
76 return -ERANGE;
77
78 *ret = (mode_t) l;
79 return 0;
80 }
81
82 int parse_size(const char *t, uint64_t base, uint64_t *size) {
83
84 /* Soo, sometimes we want to parse IEC binary suffixes, and
85 * sometimes SI decimal suffixes. This function can parse
86 * both. Which one is the right way depends on the
87 * context. Wikipedia suggests that SI is customary for
88 * hardware metrics and network speeds, while IEC is
89 * customary for most data sizes used by software and volatile
90 * (RAM) memory. Hence be careful which one you pick!
91 *
92 * In either case we use just K, M, G as suffix, and not Ki,
93 * Mi, Gi or so (as IEC would suggest). That's because that's
94 * frickin' ugly. But this means you really need to make sure
95 * to document which base you are parsing when you use this
96 * call. */
97
98 struct table {
99 const char *suffix;
100 unsigned long long factor;
101 };
102
103 static const struct table iec[] = {
104 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
105 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
106 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
107 { "G", 1024ULL*1024ULL*1024ULL },
108 { "M", 1024ULL*1024ULL },
109 { "K", 1024ULL },
110 { "B", 1ULL },
111 { "", 1ULL },
112 };
113
114 static const struct table si[] = {
115 { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
116 { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
117 { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
118 { "G", 1000ULL*1000ULL*1000ULL },
119 { "M", 1000ULL*1000ULL },
120 { "K", 1000ULL },
121 { "B", 1ULL },
122 { "", 1ULL },
123 };
124
125 const struct table *table;
126 const char *p;
127 unsigned long long r = 0;
128 unsigned n_entries, start_pos = 0;
129
130 assert(t);
131 assert(base == 1000 || base == 1024);
132 assert(size);
133
134 if (base == 1000) {
135 table = si;
136 n_entries = ELEMENTSOF(si);
137 } else {
138 table = iec;
139 n_entries = ELEMENTSOF(iec);
140 }
141
142 p = t;
143 do {
144 unsigned long long l, tmp;
145 double frac = 0;
146 char *e;
147 unsigned i;
148
149 p += strspn(p, WHITESPACE);
150 if (*p == '-')
151 return -ERANGE;
152
153 errno = 0;
154 l = strtoull(p, &e, 10);
155 if (errno > 0)
156 return -errno;
157 if (e == p)
158 return -EINVAL;
159
160 if (*e == '.') {
161 e++;
162
163 /* strtoull() itself would accept space/+/- */
164 if (*e >= '0' && *e <= '9') {
165 unsigned long long l2;
166 char *e2;
167
168 l2 = strtoull(e, &e2, 10);
169 if (errno > 0)
170 return -errno;
171
172 /* Ignore failure. E.g. 10.M is valid */
173 frac = l2;
174 for (; e < e2; e++)
175 frac /= 10;
176 }
177 }
178
179 e += strspn(e, WHITESPACE);
180
181 for (i = start_pos; i < n_entries; i++)
182 if (startswith(e, table[i].suffix))
183 break;
184
185 if (i >= n_entries)
186 return -EINVAL;
187
188 if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
189 return -ERANGE;
190
191 tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
192 if (tmp > ULLONG_MAX - r)
193 return -ERANGE;
194
195 r += tmp;
196 if ((unsigned long long) (uint64_t) r != r)
197 return -ERANGE;
198
199 p = e + strlen(table[i].suffix);
200
201 start_pos = i + 1;
202
203 } while (*p);
204
205 *size = r;
206
207 return 0;
208 }
209
210 char *format_bytes(char *buf, size_t l, uint64_t t) {
211 unsigned i;
212
213 /* This only does IEC units so far */
214
215 static const struct {
216 const char *suffix;
217 uint64_t factor;
218 } table[] = {
219 { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
220 { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
221 { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
222 { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
223 { "M", UINT64_C(1024)*UINT64_C(1024) },
224 { "K", UINT64_C(1024) },
225 };
226
227 if (t == (uint64_t) -1)
228 return NULL;
229
230 for (i = 0; i < ELEMENTSOF(table); i++) {
231
232 if (t >= table[i].factor) {
233 snprintf(buf, l,
234 "%" PRIu64 ".%" PRIu64 "%s",
235 t / table[i].factor,
236 ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
237 table[i].suffix);
238
239 goto finish;
240 }
241 }
242
243 snprintf(buf, l, "%" PRIu64 "B", t);
244
245 finish:
246 buf[l-1] = 0;
247 return buf;
248
249 }
250
251 int safe_atou(const char *s, unsigned *ret_u) {
252 char *x = NULL;
253 unsigned long l;
254
255 assert(s);
256 assert(ret_u);
257
258 errno = 0;
259 l = strtoul(s, &x, 0);
260
261 if (!x || x == s || *x || errno)
262 return errno > 0 ? -errno : -EINVAL;
263
264 if ((unsigned long) (unsigned) l != l)
265 return -ERANGE;
266
267 *ret_u = (unsigned) l;
268 return 0;
269 }
270
271 int safe_atoi(const char *s, int *ret_i) {
272 char *x = NULL;
273 long l;
274
275 assert(s);
276 assert(ret_i);
277
278 errno = 0;
279 l = strtol(s, &x, 0);
280
281 if (!x || x == s || *x || errno)
282 return errno > 0 ? -errno : -EINVAL;
283
284 if ((long) (int) l != l)
285 return -ERANGE;
286
287 *ret_i = (int) l;
288 return 0;
289 }
290
291 int safe_atollu(const char *s, long long unsigned *ret_llu) {
292 char *x = NULL;
293 unsigned long long l;
294
295 assert(s);
296 assert(ret_llu);
297
298 errno = 0;
299 l = strtoull(s, &x, 0);
300
301 if (!x || x == s || *x || errno)
302 return errno ? -errno : -EINVAL;
303
304 *ret_llu = l;
305 return 0;
306 }
307
308 int safe_atolli(const char *s, long long int *ret_lli) {
309 char *x = NULL;
310 long long l;
311
312 assert(s);
313 assert(ret_lli);
314
315 errno = 0;
316 l = strtoll(s, &x, 0);
317
318 if (!x || x == s || *x || errno)
319 return errno ? -errno : -EINVAL;
320
321 *ret_lli = l;
322 return 0;
323 }
324
325 int safe_atou8(const char *s, uint8_t *ret) {
326 char *x = NULL;
327 unsigned long l;
328
329 assert(s);
330 assert(ret);
331
332 errno = 0;
333 l = strtoul(s, &x, 0);
334
335 if (!x || x == s || *x || errno)
336 return errno > 0 ? -errno : -EINVAL;
337
338 if ((unsigned long) (uint8_t) l != l)
339 return -ERANGE;
340
341 *ret = (uint8_t) l;
342 return 0;
343 }
344
345 int safe_atou16(const char *s, uint16_t *ret) {
346 char *x = NULL;
347 unsigned long l;
348
349 assert(s);
350 assert(ret);
351
352 errno = 0;
353 l = strtoul(s, &x, 0);
354
355 if (!x || x == s || *x || errno)
356 return errno > 0 ? -errno : -EINVAL;
357
358 if ((unsigned long) (uint16_t) l != l)
359 return -ERANGE;
360
361 *ret = (uint16_t) l;
362 return 0;
363 }
364
365 int safe_atoi16(const char *s, int16_t *ret) {
366 char *x = NULL;
367 long l;
368
369 assert(s);
370 assert(ret);
371
372 errno = 0;
373 l = strtol(s, &x, 0);
374
375 if (!x || x == s || *x || errno)
376 return errno > 0 ? -errno : -EINVAL;
377
378 if ((long) (int16_t) l != l)
379 return -ERANGE;
380
381 *ret = (int16_t) l;
382 return 0;
383 }
384
385 int safe_atod(const char *s, double *ret_d) {
386 char *x = NULL;
387 double d = 0;
388 locale_t loc;
389
390 assert(s);
391 assert(ret_d);
392
393 loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
394 if (loc == (locale_t) 0)
395 return -errno;
396
397 errno = 0;
398 d = strtod_l(s, &x, loc);
399
400 if (!x || x == s || *x || errno) {
401 freelocale(loc);
402 return errno ? -errno : -EINVAL;
403 }
404
405 freelocale(loc);
406 *ret_d = (double) d;
407 return 0;
408 }