Bug Summary

File:build-scan/../src/basic/parse-util.c
Warning:line 331, column 25
Potential leak of memory pointed to by 'n'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name parse-util.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/basic/libbasic.a.p -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -I /usr/include/blkid -I /usr/include/libmount -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/basic/parse-util.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).h>
4#include <inttypes.h>
5#include <locale.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/socket.h>
10
11#include "alloc-util.h"
12#include "errno-list.h"
13#include "extract-word.h"
14#include "locale-util.h"
15#include "macro.h"
16#include "missing.h"
17#include "parse-util.h"
18#include "process-util.h"
19#include "string-util.h"
20#include "strv.h"
21
22int parse_boolean(const char *v) {
23 assert(v)do { if ((__builtin_expect(!!(!(v)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("v"), "../src/basic/parse-util.c", 23, __PRETTY_FUNCTION__
); } while (0)
;
24
25 if (streq(v, "1")(strcmp((v),("1")) == 0) || strcaseeq(v, "yes")(strcasecmp((v),("yes")) == 0) || strcaseeq(v, "y")(strcasecmp((v),("y")) == 0) || strcaseeq(v, "true")(strcasecmp((v),("true")) == 0) || strcaseeq(v, "t")(strcasecmp((v),("t")) == 0) || strcaseeq(v, "on")(strcasecmp((v),("on")) == 0))
26 return 1;
27 else if (streq(v, "0")(strcmp((v),("0")) == 0) || strcaseeq(v, "no")(strcasecmp((v),("no")) == 0) || strcaseeq(v, "n")(strcasecmp((v),("n")) == 0) || strcaseeq(v, "false")(strcasecmp((v),("false")) == 0) || strcaseeq(v, "f")(strcasecmp((v),("f")) == 0) || strcaseeq(v, "off")(strcasecmp((v),("off")) == 0))
28 return 0;
29
30 return -EINVAL22;
31}
32
33int parse_pid(const char *s, pid_t* ret_pid) {
34 unsigned long ul = 0;
35 pid_t pid;
36 int r;
37
38 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 38, __PRETTY_FUNCTION__
); } while (0)
;
39 assert(ret_pid)do { if ((__builtin_expect(!!(!(ret_pid)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_pid"), "../src/basic/parse-util.c",
39, __PRETTY_FUNCTION__); } while (0)
;
40
41 r = safe_atolu(s, &ul);
42 if (r < 0)
43 return r;
44
45 pid = (pid_t) ul;
46
47 if ((unsigned long) pid != ul)
48 return -ERANGE34;
49
50 if (!pid_is_valid(pid))
51 return -ERANGE34;
52
53 *ret_pid = pid;
54 return 0;
55}
56
57int parse_mode(const char *s, mode_t *ret) {
58 unsigned m;
59 int r;
60
61 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 61, __PRETTY_FUNCTION__
); } while (0)
;
62
63 r = safe_atou_full(s, 8 |
64 SAFE_ATO_REFUSE_PLUS_MINUS(1U << 30), /* Leading '+' or even '-' char? that's just weird,
65 * refuse. User might have wanted to add mode flags or
66 * so, but this parser doesn't allow that, so let's
67 * better be safe. */
68 &m);
69 if (r < 0)
70 return r;
71 if (m > 07777)
72 return -ERANGE34;
73
74 if (ret)
75 *ret = m;
76 return 0;
77}
78
79int parse_ifindex(const char *s, int *ret) {
80 int ifi, r;
81
82 r = safe_atoi(s, &ifi);
83 if (r < 0)
84 return r;
85 if (ifi <= 0)
86 return -EINVAL22;
87
88 *ret = ifi;
89 return 0;
90}
91
92int parse_mtu(int family, const char *s, uint32_t *ret) {
93 uint64_t u;
94 size_t m;
95 int r;
96
97 r = parse_size(s, 1024, &u);
98 if (r < 0)
99 return r;
100
101 if (u > UINT32_MAX(4294967295U))
102 return -ERANGE34;
103
104 if (family == AF_INET610)
105 m = IPV6_MIN_MTU1280; /* This is 1280 */
106 else
107 m = IPV4_MIN_MTU68; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */
108
109 if (u < m)
110 return -ERANGE34;
111
112 *ret = (uint32_t) u;
113 return 0;
114}
115
116int parse_size(const char *t, uint64_t base, uint64_t *size) {
117
118 /* Soo, sometimes we want to parse IEC binary suffixes, and
119 * sometimes SI decimal suffixes. This function can parse
120 * both. Which one is the right way depends on the
121 * context. Wikipedia suggests that SI is customary for
122 * hardware metrics and network speeds, while IEC is
123 * customary for most data sizes used by software and volatile
124 * (RAM) memory. Hence be careful which one you pick!
125 *
126 * In either case we use just K, M, G as suffix, and not Ki,
127 * Mi, Gi or so (as IEC would suggest). That's because that's
128 * frickin' ugly. But this means you really need to make sure
129 * to document which base you are parsing when you use this
130 * call. */
131
132 struct table {
133 const char *suffix;
134 unsigned long long factor;
135 };
136
137 static const struct table iec[] = {
138 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
139 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
140 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
141 { "G", 1024ULL*1024ULL*1024ULL },
142 { "M", 1024ULL*1024ULL },
143 { "K", 1024ULL },
144 { "B", 1ULL },
145 { "", 1ULL },
146 };
147
148 static const struct table si[] = {
149 { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
150 { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
151 { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
152 { "G", 1000ULL*1000ULL*1000ULL },
153 { "M", 1000ULL*1000ULL },
154 { "K", 1000ULL },
155 { "B", 1ULL },
156 { "", 1ULL },
157 };
158
159 const struct table *table;
160 const char *p;
161 unsigned long long r = 0;
162 unsigned n_entries, start_pos = 0;
163
164 assert(t)do { if ((__builtin_expect(!!(!(t)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("t"), "../src/basic/parse-util.c", 164, __PRETTY_FUNCTION__
); } while (0)
;
165 assert(IN_SET(base, 1000, 1024))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){1000, 1024})/sizeof(int)]; switch(base) { case
1000: case 1024: _found = 1; break; default: break; } _found
; }))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("IN_SET(base, 1000, 1024)"
), "../src/basic/parse-util.c", 165, __PRETTY_FUNCTION__); } while
(0)
;
166 assert(size)do { if ((__builtin_expect(!!(!(size)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("size"), "../src/basic/parse-util.c", 166
, __PRETTY_FUNCTION__); } while (0)
;
167
168 if (base == 1000) {
169 table = si;
170 n_entries = ELEMENTSOF(si)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(si), typeof(&*(si))), sizeof(si)/sizeof((si)[0]),
((void)0)))
;
171 } else {
172 table = iec;
173 n_entries = ELEMENTSOF(iec)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(iec), typeof(&*(iec))), sizeof(iec)/sizeof((iec)[
0]), ((void)0)))
;
174 }
175
176 p = t;
177 do {
178 unsigned long long l, tmp;
179 double frac = 0;
180 char *e;
181 unsigned i;
182
183 p += strspn(p, WHITESPACE" \t\n\r");
184
185 errno(*__errno_location ()) = 0;
186 l = strtoull(p, &e, 10);
187 if (errno(*__errno_location ()) > 0)
188 return -errno(*__errno_location ());
189 if (e == p)
190 return -EINVAL22;
191 if (*p == '-')
192 return -ERANGE34;
193
194 if (*e == '.') {
195 e++;
196
197 /* strtoull() itself would accept space/+/- */
198 if (*e >= '0' && *e <= '9') {
199 unsigned long long l2;
200 char *e2;
201
202 l2 = strtoull(e, &e2, 10);
203 if (errno(*__errno_location ()) > 0)
204 return -errno(*__errno_location ());
205
206 /* Ignore failure. E.g. 10.M is valid */
207 frac = l2;
208 for (; e < e2; e++)
209 frac /= 10;
210 }
211 }
212
213 e += strspn(e, WHITESPACE" \t\n\r");
214
215 for (i = start_pos; i < n_entries; i++)
216 if (startswith(e, table[i].suffix))
217 break;
218
219 if (i >= n_entries)
220 return -EINVAL22;
221
222 if (l + (frac > 0) > ULLONG_MAX(9223372036854775807LL*2ULL+1ULL) / table[i].factor)
223 return -ERANGE34;
224
225 tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
226 if (tmp > ULLONG_MAX(9223372036854775807LL*2ULL+1ULL) - r)
227 return -ERANGE34;
228
229 r += tmp;
230 if ((unsigned long long) (uint64_t) r != r)
231 return -ERANGE34;
232
233 p = e + strlen(table[i].suffix);
234
235 start_pos = i + 1;
236
237 } while (*p);
238
239 *size = r;
240
241 return 0;
242}
243
244int parse_range(const char *t, unsigned *lower, unsigned *upper) {
245 _cleanup_free___attribute__((cleanup(freep))) char *word = NULL((void*)0);
246 unsigned l, u;
247 int r;
248
249 assert(lower)do { if ((__builtin_expect(!!(!(lower)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("lower"), "../src/basic/parse-util.c", 249
, __PRETTY_FUNCTION__); } while (0)
;
250 assert(upper)do { if ((__builtin_expect(!!(!(upper)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("upper"), "../src/basic/parse-util.c", 250
, __PRETTY_FUNCTION__); } while (0)
;
251
252 /* Extract the lower bound. */
253 r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
254 if (r < 0)
255 return r;
256 if (r == 0)
257 return -EINVAL22;
258
259 r = safe_atou(word, &l);
260 if (r < 0)
261 return r;
262
263 /* Check for the upper bound and extract it if needed */
264 if (!t)
265 /* Single number with no dashes. */
266 u = l;
267 else if (!*t)
268 /* Trailing dash is an error. */
269 return -EINVAL22;
270 else {
271 r = safe_atou(t, &u);
272 if (r < 0)
273 return r;
274 }
275
276 *lower = l;
277 *upper = u;
278 return 0;
279}
280
281int parse_errno(const char *t) {
282 int r, e;
283
284 assert(t)do { if ((__builtin_expect(!!(!(t)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("t"), "../src/basic/parse-util.c", 284, __PRETTY_FUNCTION__
); } while (0)
;
285
286 r = errno_from_name(t);
287 if (r > 0)
288 return r;
289
290 r = safe_atoi(t, &e);
291 if (r < 0)
292 return r;
293
294 /* 0 is also allowed here */
295 if (!errno_is_valid(e) && e != 0)
296 return -ERANGE34;
297
298 return e;
299}
300
301int parse_syscall_and_errno(const char *in, char **name, int *error) {
302 _cleanup_free___attribute__((cleanup(freep))) char *n = NULL((void*)0);
303 char *p;
304 int e = -1;
305
306 assert(in)do { if ((__builtin_expect(!!(!(in)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("in"), "../src/basic/parse-util.c", 306,
__PRETTY_FUNCTION__); } while (0)
;
1
Assuming 'in' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
307 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/basic/parse-util.c", 307
, __PRETTY_FUNCTION__); } while (0)
;
4
Assuming 'name' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
308 assert(error)do { if ((__builtin_expect(!!(!(error)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("error"), "../src/basic/parse-util.c", 308
, __PRETTY_FUNCTION__); } while (0)
;
7
Assuming 'error' is non-null
8
Taking false branch
9
Loop condition is false. Exiting loop
309
310 /*
311 * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255".
312 * If errno is omitted, then error is set to -1.
313 * Empty syscall name is not allowed.
314 * Here, we do not check that the syscall name is valid or not.
315 */
316
317 p = strchr(in, ':');
318 if (p) {
10
Assuming 'p' is non-null
11
Taking true branch
319 e = parse_errno(p + 1);
320 if (e
11.1
'e' is >= 0
< 0)
12
Taking false branch
321 return e;
322
323 n = strndup(in, p - in);
13
Memory is allocated
324 } else
325 n = strdup(in);
326
327 if (!n)
14
Assuming 'n' is non-null
15
Taking false branch
328 return -ENOMEM12;
329
330 if (isempty(n))
16
Taking true branch
331 return -EINVAL22;
17
Potential leak of memory pointed to by 'n'
332
333 *error = e;
334 *name = TAKE_PTR(n)({ typeof(n) _ptr_ = (n); (n) = ((void*)0); _ptr_; });
335
336 return 0;
337}
338
339char *format_bytes(char *buf, size_t l, uint64_t t) {
340 unsigned i;
341
342 /* This only does IEC units so far */
343
344 static const struct {
345 const char *suffix;
346 uint64_t factor;
347 } table[] = {
348 { "E", UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL },
349 { "P", UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL },
350 { "T", UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL },
351 { "G", UINT64_C(1024)1024UL*UINT64_C(1024)1024UL*UINT64_C(1024)1024UL },
352 { "M", UINT64_C(1024)1024UL*UINT64_C(1024)1024UL },
353 { "K", UINT64_C(1024)1024UL },
354 };
355
356 if (t == (uint64_t) -1)
357 return NULL((void*)0);
358
359 for (i = 0; i < ELEMENTSOF(table)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(table), typeof(&*(table))), sizeof(table)/sizeof(
(table)[0]), ((void)0)))
; i++) {
360
361 if (t >= table[i].factor) {
362 snprintf(buf, l,
363 "%" PRIu64"l" "u" ".%" PRIu64"l" "u" "%s",
364 t / table[i].factor,
365 ((t*UINT64_C(10)10UL) / table[i].factor) % UINT64_C(10)10UL,
366 table[i].suffix);
367
368 goto finish;
369 }
370 }
371
372 snprintf(buf, l, "%" PRIu64"l" "u" "B", t);
373
374finish:
375 buf[l-1] = 0;
376 return buf;
377}
378
379static const char *mangle_base(const char *s, unsigned *base) {
380 const char *k;
381
382 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 382, __PRETTY_FUNCTION__
); } while (0)
;
383 assert(base)do { if ((__builtin_expect(!!(!(base)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("base"), "../src/basic/parse-util.c", 383
, __PRETTY_FUNCTION__); } while (0)
;
384
385 /* Base already explicitly specified, then don't do anything. */
386 if (SAFE_ATO_MASK_FLAGS(*base)((*base) & ~((1U << 30)|(1U << 29)|(1U <<
28)))
!= 0)
387 return s;
388
389 /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
390 k = STARTSWITH_SET(s, "0b", "0B")({ const char *_p = (s); char *_found = ((void*)0), **_i; for
((_i) = (((char**) ((const char*[]) { "0b", "0B", ((void*)0)
}))); (_i) && *(_i); (_i)++) { _found = startswith(_p
, *_i); if (_found) break; } _found; })
;
391 if (k) {
392 *base = 2 | (*base & SAFE_ATO_ALL_FLAGS((1U << 30)|(1U << 29)|(1U << 28)));
393 return k;
394 }
395
396 k = STARTSWITH_SET(s, "0o", "0O")({ const char *_p = (s); char *_found = ((void*)0), **_i; for
((_i) = (((char**) ((const char*[]) { "0o", "0O", ((void*)0)
}))); (_i) && *(_i); (_i)++) { _found = startswith(_p
, *_i); if (_found) break; } _found; })
;
397 if (k) {
398 *base = 8 | (*base & SAFE_ATO_ALL_FLAGS((1U << 30)|(1U << 29)|(1U << 28)));
399 return k;
400 }
401
402 return s;
403}
404
405int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
406 char *x = NULL((void*)0);
407 unsigned long l;
408
409 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 409, __PRETTY_FUNCTION__
); } while (0)
;
410 assert(SAFE_ATO_MASK_FLAGS(base) <= 16)do { if ((__builtin_expect(!!(!(((base) & ~((1U << 30
)|(1U << 29)|(1U << 28))) <= 16)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("SAFE_ATO_MASK_FLAGS(base) <= 16"), "../src/basic/parse-util.c"
, 410, __PRETTY_FUNCTION__); } while (0)
;
411
412 /* strtoul() is happy to parse negative values, and silently converts them to unsigned values without
413 * generating an error. We want a clean error, hence let's look for the "-" prefix on our own, and
414 * generate an error. But let's do so only after strtoul() validated that the string is clean
415 * otherwise, so that we return EINVAL preferably over ERANGE. */
416
417 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE)(((base) & ((1U << 28))) == ((1U << 28))) &&
418 strchr(WHITESPACE" \t\n\r", s[0]))
419 return -EINVAL22;
420
421 s += strspn(s, WHITESPACE" \t\n\r");
422
423 if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS)(((base) & ((1U << 30))) == ((1U << 30))) &&
424 IN_SET(s[0], '+', '-')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'+', '-'})/sizeof(int)]; switch(s[0]) { case
'+': case '-': _found = 1; break; default: break; } _found; }
)
)
425 return -EINVAL22; /* Note that we check the "-" prefix again a second time below, but return a
426 * different error. I.e. if the SAFE_ATO_REFUSE_PLUS_MINUS flag is set we
427 * blanket refuse +/- prefixed integers, while if it is missing we'll just
428 * return ERANGE, because the string actually parses correctly, but doesn't
429 * fit in the return type. */
430
431 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO)(((base) & ((1U << 29))) == ((1U << 29))) &&
432 s[0] == '0' && !streq(s, "0")(strcmp((s),("0")) == 0))
433 return -EINVAL22; /* This is particularly useful to avoid ambiguities between C's octal
434 * notation and assumed-to-be-decimal integers with a leading zero. */
435
436 s = mangle_base(s, &base);
437
438 errno(*__errno_location ()) = 0;
439 l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base)((base) & ~((1U << 30)|(1U << 29)|(1U <<
28)))
/* Let's mask off the flags bits so that only the actual
440 * base is left */);
441 if (errno(*__errno_location ()) > 0)
442 return -errno(*__errno_location ());
443 if (!x || x == s || *x != 0)
444 return -EINVAL22;
445 if (l != 0 && s[0] == '-')
446 return -ERANGE34;
447 if ((unsigned long) (unsigned) l != l)
448 return -ERANGE34;
449
450 if (ret_u)
451 *ret_u = (unsigned) l;
452
453 return 0;
454}
455
456int safe_atoi(const char *s, int *ret_i) {
457 unsigned base = 0;
458 char *x = NULL((void*)0);
459 long l;
460
461 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 461, __PRETTY_FUNCTION__
); } while (0)
;
462
463 s += strspn(s, WHITESPACE" \t\n\r");
464 s = mangle_base(s, &base);
465
466 errno(*__errno_location ()) = 0;
467 l = strtol(s, &x, base);
468 if (errno(*__errno_location ()) > 0)
469 return -errno(*__errno_location ());
470 if (!x || x == s || *x != 0)
471 return -EINVAL22;
472 if ((long) (int) l != l)
473 return -ERANGE34;
474
475 if (ret_i)
476 *ret_i = (int) l;
477
478 return 0;
479}
480
481int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu) {
482 char *x = NULL((void*)0);
483 unsigned long long l;
484
485 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 485, __PRETTY_FUNCTION__
); } while (0)
;
486 assert(SAFE_ATO_MASK_FLAGS(base) <= 16)do { if ((__builtin_expect(!!(!(((base) & ~((1U << 30
)|(1U << 29)|(1U << 28))) <= 16)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("SAFE_ATO_MASK_FLAGS(base) <= 16"), "../src/basic/parse-util.c"
, 486, __PRETTY_FUNCTION__); } while (0)
;
487
488 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE)(((base) & ((1U << 28))) == ((1U << 28))) &&
489 strchr(WHITESPACE" \t\n\r", s[0]))
490 return -EINVAL22;
491
492 s += strspn(s, WHITESPACE" \t\n\r");
493
494 if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS)(((base) & ((1U << 30))) == ((1U << 30))) &&
495 IN_SET(s[0], '+', '-')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'+', '-'})/sizeof(int)]; switch(s[0]) { case
'+': case '-': _found = 1; break; default: break; } _found; }
)
)
496 return -EINVAL22;
497
498 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO)(((base) & ((1U << 29))) == ((1U << 29))) &&
499 s[0] == '0' && s[1] != 0)
500 return -EINVAL22;
501
502 s = mangle_base(s, &base);
503
504 errno(*__errno_location ()) = 0;
505 l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base)((base) & ~((1U << 30)|(1U << 29)|(1U <<
28)))
);
506 if (errno(*__errno_location ()) > 0)
507 return -errno(*__errno_location ());
508 if (!x || x == s || *x != 0)
509 return -EINVAL22;
510 if (l != 0 && s[0] == '-')
511 return -ERANGE34;
512
513 if (ret_llu)
514 *ret_llu = l;
515
516 return 0;
517}
518
519int safe_atolli(const char *s, long long int *ret_lli) {
520 unsigned base = 0;
521 char *x = NULL((void*)0);
522 long long l;
523
524 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 524, __PRETTY_FUNCTION__
); } while (0)
;
525
526 s += strspn(s, WHITESPACE" \t\n\r");
527 s = mangle_base(s, &base);
528
529 errno(*__errno_location ()) = 0;
530 l = strtoll(s, &x, base);
531 if (errno(*__errno_location ()) > 0)
532 return -errno(*__errno_location ());
533 if (!x || x == s || *x != 0)
534 return -EINVAL22;
535
536 if (ret_lli)
537 *ret_lli = l;
538
539 return 0;
540}
541
542int safe_atou8(const char *s, uint8_t *ret) {
543 unsigned base = 0;
544 unsigned long l;
545 char *x = NULL((void*)0);
546
547 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 547, __PRETTY_FUNCTION__
); } while (0)
;
548
549 s += strspn(s, WHITESPACE" \t\n\r");
550 s = mangle_base(s, &base);
551
552 errno(*__errno_location ()) = 0;
553 l = strtoul(s, &x, base);
554 if (errno(*__errno_location ()) > 0)
555 return -errno(*__errno_location ());
556 if (!x || x == s || *x != 0)
557 return -EINVAL22;
558 if (l != 0 && s[0] == '-')
559 return -ERANGE34;
560 if ((unsigned long) (uint8_t) l != l)
561 return -ERANGE34;
562
563 if (ret)
564 *ret = (uint8_t) l;
565 return 0;
566}
567
568int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
569 char *x = NULL((void*)0);
570 unsigned long l;
571
572 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 572, __PRETTY_FUNCTION__
); } while (0)
;
573 assert(SAFE_ATO_MASK_FLAGS(base) <= 16)do { if ((__builtin_expect(!!(!(((base) & ~((1U << 30
)|(1U << 29)|(1U << 28))) <= 16)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("SAFE_ATO_MASK_FLAGS(base) <= 16"), "../src/basic/parse-util.c"
, 573, __PRETTY_FUNCTION__); } while (0)
;
574
575 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE)(((base) & ((1U << 28))) == ((1U << 28))) &&
576 strchr(WHITESPACE" \t\n\r", s[0]))
577 return -EINVAL22;
578
579 s += strspn(s, WHITESPACE" \t\n\r");
580
581 if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS)(((base) & ((1U << 30))) == ((1U << 30))) &&
582 IN_SET(s[0], '+', '-')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'+', '-'})/sizeof(int)]; switch(s[0]) { case
'+': case '-': _found = 1; break; default: break; } _found; }
)
)
583 return -EINVAL22;
584
585 if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO)(((base) & ((1U << 29))) == ((1U << 29))) &&
586 s[0] == '0' && s[1] != 0)
587 return -EINVAL22;
588
589 s = mangle_base(s, &base);
590
591 errno(*__errno_location ()) = 0;
592 l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base)((base) & ~((1U << 30)|(1U << 29)|(1U <<
28)))
);
593 if (errno(*__errno_location ()) > 0)
594 return -errno(*__errno_location ());
595 if (!x || x == s || *x != 0)
596 return -EINVAL22;
597 if (l != 0 && s[0] == '-')
598 return -ERANGE34;
599 if ((unsigned long) (uint16_t) l != l)
600 return -ERANGE34;
601
602 if (ret)
603 *ret = (uint16_t) l;
604
605 return 0;
606}
607
608int safe_atoi16(const char *s, int16_t *ret) {
609 unsigned base = 0;
610 char *x = NULL((void*)0);
611 long l;
612
613 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 613, __PRETTY_FUNCTION__
); } while (0)
;
614
615 s += strspn(s, WHITESPACE" \t\n\r");
616 s = mangle_base(s, &base);
617
618 errno(*__errno_location ()) = 0;
619 l = strtol(s, &x, base);
620 if (errno(*__errno_location ()) > 0)
621 return -errno(*__errno_location ());
622 if (!x || x == s || *x != 0)
623 return -EINVAL22;
624 if ((long) (int16_t) l != l)
625 return -ERANGE34;
626
627 if (ret)
628 *ret = (int16_t) l;
629
630 return 0;
631}
632
633int safe_atod(const char *s, double *ret_d) {
634 _cleanup_(freelocalep)__attribute__((cleanup(freelocalep))) locale_t loc = (locale_t) 0;
635 char *x = NULL((void*)0);
636 double d = 0;
637
638 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 638, __PRETTY_FUNCTION__
); } while (0)
;
639
640 loc = newlocale(LC_NUMERIC_MASK(1 << 1), "C", (locale_t) 0);
641 if (loc == (locale_t) 0)
642 return -errno(*__errno_location ());
643
644 errno(*__errno_location ()) = 0;
645 d = strtod_l(s, &x, loc);
646 if (errno(*__errno_location ()) > 0)
647 return -errno(*__errno_location ());
648 if (!x || x == s || *x != 0)
649 return -EINVAL22;
650
651 if (ret_d)
652 *ret_d = (double) d;
653
654 return 0;
655}
656
657int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
658 size_t i;
659 unsigned val = 0;
660 const char *s;
661
662 s = *p;
663
664 /* accept any number of digits, strtoull is limted to 19 */
665 for (i=0; i < digits; i++,s++) {
666 if (*s < '0' || *s > '9') {
667 if (i == 0)
668 return -EINVAL22;
669
670 /* too few digits, pad with 0 */
671 for (; i < digits; i++)
672 val *= 10;
673
674 break;
675 }
676
677 val *= 10;
678 val += *s - '0';
679 }
680
681 /* maybe round up */
682 if (*s >= '5' && *s <= '9')
683 val++;
684
685 s += strspn(s, DIGITS"0123456789");
686
687 *p = s;
688 *res = val;
689
690 return 0;
691}
692
693int parse_percent_unbounded(const char *p) {
694 const char *pc, *n;
695 int r, v;
696
697 pc = endswith(p, "%");
698 if (!pc)
699 return -EINVAL22;
700
701 n = strndupa(p, pc - p)(__extension__ ({ const char *__old = (p); size_t __len = strnlen
(__old, (pc - p)); char *__new = (char *) __builtin_alloca (
__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old
, __len); }))
;
702 r = safe_atoi(n, &v);
703 if (r < 0)
704 return r;
705 if (v < 0)
706 return -ERANGE34;
707
708 return v;
709}
710
711int parse_percent(const char *p) {
712 int v;
713
714 v = parse_percent_unbounded(p);
715 if (v > 100)
716 return -ERANGE34;
717
718 return v;
719}
720
721int parse_permille_unbounded(const char *p) {
722 const char *pc, *pm, *dot, *n;
723 int r, q, v;
724
725 pm = endswith(p, "‰");
726 if (pm) {
727 n = strndupa(p, pm - p)(__extension__ ({ const char *__old = (p); size_t __len = strnlen
(__old, (pm - p)); char *__new = (char *) __builtin_alloca (
__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old
, __len); }))
;
728 r = safe_atoi(n, &v);
729 if (r < 0)
730 return r;
731 } else {
732 pc = endswith(p, "%");
733 if (!pc)
734 return -EINVAL22;
735
736 dot = memchr(p, '.', pc - p);
737 if (dot) {
738 if (dot + 2 != pc)
739 return -EINVAL22;
740 if (dot[1] < '0' || dot[1] > '9')
741 return -EINVAL22;
742 q = dot[1] - '0';
743 n = strndupa(p, dot - p)(__extension__ ({ const char *__old = (p); size_t __len = strnlen
(__old, (dot - p)); char *__new = (char *) __builtin_alloca (
__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old
, __len); }))
;
744 } else {
745 q = 0;
746 n = strndupa(p, pc - p)(__extension__ ({ const char *__old = (p); size_t __len = strnlen
(__old, (pc - p)); char *__new = (char *) __builtin_alloca (
__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old
, __len); }))
;
747 }
748 r = safe_atoi(n, &v);
749 if (r < 0)
750 return r;
751 if (v > (INT_MAX2147483647 - q) / 10)
752 return -ERANGE34;
753
754 v = v * 10 + q;
755 }
756
757 if (v < 0)
758 return -ERANGE34;
759
760 return v;
761}
762
763int parse_permille(const char *p) {
764 int v;
765
766 v = parse_permille_unbounded(p);
767 if (v > 1000)
768 return -ERANGE34;
769
770 return v;
771}
772
773int parse_nice(const char *p, int *ret) {
774 int n, r;
775
776 r = safe_atoi(p, &n);
777 if (r < 0)
778 return r;
779
780 if (!nice_is_valid(n))
781 return -ERANGE34;
782
783 *ret = n;
784 return 0;
785}
786
787int parse_ip_port(const char *s, uint16_t *ret) {
788 uint16_t l;
789 int r;
790
791 r = safe_atou16(s, &l);
792 if (r < 0)
793 return r;
794
795 if (l == 0)
796 return -EINVAL22;
797
798 *ret = (uint16_t) l;
799
800 return 0;
801}
802
803int parse_dev(const char *s, dev_t *ret) {
804 unsigned x, y;
805 dev_t d;
806
807 if (sscanf(s, "%u:%u", &x, &y) != 2)
808 return -EINVAL22;
809
810 d = makedev(x, y)gnu_dev_makedev (x, y);
811 if ((unsigned) major(d)gnu_dev_major (d) != x || (unsigned) minor(d)gnu_dev_minor (d) != y)
812 return -EINVAL22;
813
814 *ret = d;
815 return 0;
816}
817
818int parse_oom_score_adjust(const char *s, int *ret) {
819 int r, v;
820
821 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/parse-util.c", 821, __PRETTY_FUNCTION__
); } while (0)
;
822 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/basic/parse-util.c", 822
, __PRETTY_FUNCTION__); } while (0)
;
823
824 r = safe_atoi(s, &v);
825 if (r < 0)
826 return r;
827
828 if (v < OOM_SCORE_ADJ_MIN(-1000) || v > OOM_SCORE_ADJ_MAX1000)
829 return -ERANGE34;
830
831 *ret = v;
832 return 0;
833}