1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include <sys/socket.h>
10 #include "alloc-util.h"
11 #include "errno-list.h"
12 #include "extract-word.h"
13 #include "locale-util.h"
15 #include "missing_network.h"
16 #include "parse-util.h"
17 #include "process-util.h"
18 #include "stat-util.h"
19 #include "string-util.h"
22 int parse_boolean(const char *v
) {
47 int parse_tristate_full(const char *v
, const char *third
, int *ret
) {
50 if (isempty(v
) || streq_ptr(v
, third
)) { /* Empty string is always taken as the third/invalid/auto state */
65 int parse_pid(const char *s
, pid_t
* ret_pid
) {
72 r
= safe_atolu(s
, &ul
);
78 if ((unsigned long) pid
!= ul
)
81 if (!pid_is_valid(pid
))
89 int parse_mode(const char *s
, mode_t
*ret
) {
95 r
= safe_atou_full(s
, 8 |
96 SAFE_ATO_REFUSE_PLUS_MINUS
, /* Leading '+' or even '-' char? that's just weird,
97 * refuse. User might have wanted to add mode flags or
98 * so, but this parser doesn't allow that, so let's
111 int parse_ifindex(const char *s
) {
116 r
= safe_atoi(s
, &ifi
);
125 int parse_mtu(int family
, const char *s
, uint32_t *ret
) {
130 r
= parse_size(s
, 1024, &u
);
137 if (family
== AF_INET6
)
138 m
= IPV6_MIN_MTU
; /* This is 1280 */
140 m
= IPV4_MIN_MTU
; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */
149 int parse_size(const char *t
, uint64_t base
, uint64_t *size
) {
151 /* Soo, sometimes we want to parse IEC binary suffixes, and
152 * sometimes SI decimal suffixes. This function can parse
153 * both. Which one is the right way depends on the
154 * context. Wikipedia suggests that SI is customary for
155 * hardware metrics and network speeds, while IEC is
156 * customary for most data sizes used by software and volatile
157 * (RAM) memory. Hence be careful which one you pick!
159 * In either case we use just K, M, G as suffix, and not Ki,
160 * Mi, Gi or so (as IEC would suggest). That's because that's
161 * frickin' ugly. But this means you really need to make sure
162 * to document which base you are parsing when you use this
167 unsigned long long factor
;
170 static const struct table iec
[] = {
171 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
172 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
173 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
174 { "G", 1024ULL*1024ULL*1024ULL },
175 { "M", 1024ULL*1024ULL },
181 static const struct table si
[] = {
182 { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
183 { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
184 { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
185 { "G", 1000ULL*1000ULL*1000ULL },
186 { "M", 1000ULL*1000ULL },
192 const struct table
*table
;
194 unsigned long long r
= 0;
195 unsigned n_entries
, start_pos
= 0;
198 assert(IN_SET(base
, 1000, 1024));
203 n_entries
= ELEMENTSOF(si
);
206 n_entries
= ELEMENTSOF(iec
);
211 unsigned long long l
, tmp
;
216 p
+= strspn(p
, WHITESPACE
);
219 l
= strtoull(p
, &e
, 10);
230 /* strtoull() itself would accept space/+/- */
231 if (ascii_isdigit(*e
)) {
232 unsigned long long l2
;
235 l2
= strtoull(e
, &e2
, 10);
239 /* Ignore failure. E.g. 10.M is valid */
246 e
+= strspn(e
, WHITESPACE
);
248 for (i
= start_pos
; i
< n_entries
; i
++)
249 if (startswith(e
, table
[i
].suffix
))
255 if (l
+ (frac
> 0) > ULLONG_MAX
/ table
[i
].factor
)
258 tmp
= l
* table
[i
].factor
+ (unsigned long long) (frac
* table
[i
].factor
);
259 if (tmp
> ULLONG_MAX
- r
)
263 if ((unsigned long long) (uint64_t) r
!= r
)
266 p
= e
+ strlen(table
[i
].suffix
);
277 int parse_sector_size(const char *t
, uint64_t *ret
) {
285 r
= safe_atou64(t
, &ss
);
287 return log_error_errno(r
, "Failed to parse sector size parameter %s", t
);
288 if (ss
< 512 || ss
> 4096) /* Allow up to 4K due to dm-crypt support and 4K alignment by the homed LUKS backend */
289 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
), "Sector size not between 512 and 4096: %s", t
);
291 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Sector size not power of 2: %s", t
);
297 int parse_range(const char *t
, unsigned *lower
, unsigned *upper
) {
298 _cleanup_free_
char *word
= NULL
;
305 /* Extract the lower bound. */
306 r
= extract_first_word(&t
, &word
, "-", EXTRACT_DONT_COALESCE_SEPARATORS
);
312 r
= safe_atou(word
, &l
);
316 /* Check for the upper bound and extract it if needed */
318 /* Single number with no dashes. */
321 /* Trailing dash is an error. */
324 r
= safe_atou(t
, &u
);
334 int parse_errno(const char *t
) {
339 r
= errno_from_name(t
);
343 r
= safe_atoi(t
, &e
);
347 /* 0 is also allowed here */
348 if (!errno_is_valid(e
) && e
!= 0)
354 int parse_fd(const char *t
) {
359 r
= safe_atoi(t
, &fd
);
369 static const char *mangle_base(const char *s
, unsigned *base
) {
375 /* Base already explicitly specified, then don't do anything. */
376 if (SAFE_ATO_MASK_FLAGS(*base
) != 0)
379 /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
380 k
= STARTSWITH_SET(s
, "0b", "0B");
382 *base
= 2 | (*base
& SAFE_ATO_ALL_FLAGS
);
386 k
= STARTSWITH_SET(s
, "0o", "0O");
388 *base
= 8 | (*base
& SAFE_ATO_ALL_FLAGS
);
395 int safe_atou_full(const char *s
, unsigned base
, unsigned *ret_u
) {
400 assert(SAFE_ATO_MASK_FLAGS(base
) <= 16);
402 /* strtoul() is happy to parse negative values, and silently converts them to unsigned values without
403 * generating an error. We want a clean error, hence let's look for the "-" prefix on our own, and
404 * generate an error. But let's do so only after strtoul() validated that the string is clean
405 * otherwise, so that we return EINVAL preferably over ERANGE. */
407 if (FLAGS_SET(base
, SAFE_ATO_REFUSE_LEADING_WHITESPACE
) &&
408 strchr(WHITESPACE
, s
[0]))
411 s
+= strspn(s
, WHITESPACE
);
413 if (FLAGS_SET(base
, SAFE_ATO_REFUSE_PLUS_MINUS
) &&
414 IN_SET(s
[0], '+', '-'))
415 return -EINVAL
; /* Note that we check the "-" prefix again a second time below, but return a
416 * different error. I.e. if the SAFE_ATO_REFUSE_PLUS_MINUS flag is set we
417 * blanket refuse +/- prefixed integers, while if it is missing we'll just
418 * return ERANGE, because the string actually parses correctly, but doesn't
419 * fit in the return type. */
421 if (FLAGS_SET(base
, SAFE_ATO_REFUSE_LEADING_ZERO
) &&
422 s
[0] == '0' && !streq(s
, "0"))
423 return -EINVAL
; /* This is particularly useful to avoid ambiguities between C's octal
424 * notation and assumed-to-be-decimal integers with a leading zero. */
426 s
= mangle_base(s
, &base
);
429 l
= strtoul(s
, &x
, SAFE_ATO_MASK_FLAGS(base
) /* Let's mask off the flags bits so that only the actual
433 if (!x
|| x
== s
|| *x
!= 0)
435 if (l
!= 0 && s
[0] == '-')
437 if ((unsigned long) (unsigned) l
!= l
)
441 *ret_u
= (unsigned) l
;
446 int safe_atou_bounded(const char *s
, unsigned min
, unsigned max
, unsigned *ret
) {
450 r
= safe_atou(s
, &v
);
454 if (v
< min
|| v
> max
)
461 int safe_atoi(const char *s
, int *ret_i
) {
468 s
+= strspn(s
, WHITESPACE
);
469 s
= mangle_base(s
, &base
);
472 l
= strtol(s
, &x
, base
);
475 if (!x
|| x
== s
|| *x
!= 0)
477 if ((long) (int) l
!= l
)
486 int safe_atollu_full(const char *s
, unsigned base
, unsigned long long *ret_llu
) {
488 unsigned long long l
;
491 assert(SAFE_ATO_MASK_FLAGS(base
) <= 16);
493 if (FLAGS_SET(base
, SAFE_ATO_REFUSE_LEADING_WHITESPACE
) &&
494 strchr(WHITESPACE
, s
[0]))
497 s
+= strspn(s
, WHITESPACE
);
499 if (FLAGS_SET(base
, SAFE_ATO_REFUSE_PLUS_MINUS
) &&
500 IN_SET(s
[0], '+', '-'))
503 if (FLAGS_SET(base
, SAFE_ATO_REFUSE_LEADING_ZERO
) &&
504 s
[0] == '0' && s
[1] != 0)
507 s
= mangle_base(s
, &base
);
510 l
= strtoull(s
, &x
, SAFE_ATO_MASK_FLAGS(base
));
513 if (!x
|| x
== s
|| *x
!= 0)
515 if (l
!= 0 && s
[0] == '-')
524 int safe_atolli(const char *s
, long long int *ret_lli
) {
531 s
+= strspn(s
, WHITESPACE
);
532 s
= mangle_base(s
, &base
);
535 l
= strtoll(s
, &x
, base
);
538 if (!x
|| x
== s
|| *x
!= 0)
547 int safe_atou8_full(const char *s
, unsigned base
, uint8_t *ret
) {
551 r
= safe_atou_full(s
, base
, &u
);
561 int safe_atou16_full(const char *s
, unsigned base
, uint16_t *ret
) {
565 r
= safe_atou_full(s
, base
, &u
);
575 int safe_atoi16(const char *s
, int16_t *ret
) {
582 s
+= strspn(s
, WHITESPACE
);
583 s
= mangle_base(s
, &base
);
586 l
= strtol(s
, &x
, base
);
589 if (!x
|| x
== s
|| *x
!= 0)
591 if ((long) (int16_t) l
!= l
)
600 int safe_atod(const char *s
, double *ret_d
) {
601 _cleanup_(freelocalep
) locale_t loc
= (locale_t
) 0;
607 loc
= newlocale(LC_NUMERIC_MASK
, "C", (locale_t
) 0);
608 if (loc
== (locale_t
) 0)
612 d
= strtod_l(s
, &x
, loc
);
615 if (!x
|| x
== s
|| *x
!= 0)
624 int parse_fractional_part_u(const char **p
, size_t digits
, unsigned *res
) {
630 /* accept any number of digits, strtoull is limited to 19 */
631 for (size_t i
= 0; i
< digits
; i
++,s
++) {
632 if (!ascii_isdigit(*s
)) {
636 /* too few digits, pad with 0 */
637 for (; i
< digits
; i
++)
648 if (*s
>= '5' && *s
<= '9')
651 s
+= strspn(s
, DIGITS
);
659 int parse_nice(const char *p
, int *ret
) {
662 r
= safe_atoi(p
, &n
);
666 if (!nice_is_valid(n
))
673 int parse_ip_port(const char *s
, uint16_t *ret
) {
677 r
= safe_atou16_full(s
, SAFE_ATO_REFUSE_LEADING_WHITESPACE
, &l
);
689 int parse_ip_port_range(const char *s
, uint16_t *low
, uint16_t *high
) {
693 r
= parse_range(s
, &l
, &h
);
697 if (l
<= 0 || l
> 65535 || h
<= 0 || h
> 65535)
709 int parse_ip_prefix_length(const char *s
, int *ret
) {
713 r
= safe_atou(s
, &l
);
725 int parse_oom_score_adjust(const char *s
, int *ret
) {
731 r
= safe_atoi(s
, &v
);
735 if (!oom_score_adjust_is_valid(v
))
742 int store_loadavg_fixed_point(unsigned long i
, unsigned long f
, loadavg_t
*ret
) {
745 if (i
>= (~0UL << LOADAVG_PRECISION_BITS
))
748 i
= i
<< LOADAVG_PRECISION_BITS
;
749 f
= DIV_ROUND_UP((f
<< LOADAVG_PRECISION_BITS
), 100);
751 if (f
>= LOADAVG_FIXED_POINT_1_0
)
758 int parse_loadavg_fixed_point(const char *s
, loadavg_t
*ret
) {
759 const char *d
, *f_str
, *i_str
;
770 i_str
= strndupa_safe(s
, d
- s
);
773 r
= safe_atolu_full(i_str
, 10, &i
);
777 r
= safe_atolu_full(f_str
, 10, &f
);
781 return store_loadavg_fixed_point(i
, f
, ret
);
784 /* Limitations are described in https://www.netfilter.org/projects/nftables/manpage.html and
785 * https://bugzilla.netfilter.org/show_bug.cgi?id=1175 */
786 bool nft_identifier_valid(const char *id
) {
790 size_t len
= strlen(id
);
791 if (len
== 0 || len
> 31)
794 if (!ascii_isalpha(id
[0]))
797 for (size_t i
= 1; i
< len
; i
++)
798 if (!ascii_isalpha(id
[i
]) && !ascii_isdigit(id
[i
]) && !IN_SET(id
[i
], '/', '\\', '_', '.'))