• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 19020191358

02 Nov 2025 05:04PM UTC coverage: 72.222% (-0.02%) from 72.241%
19020191358

push

github

web-flow
Enhance docs for ukify and direct kernel boots (#39516)

305246 of 422650 relevant lines covered (72.22%)

1085243.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.18
/src/basic/parse-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <linux/ipv6.h>
4
#include <linux/netfilter/nf_tables.h>
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <sys/socket.h>
8

9
#include "alloc-util.h"
10
#include "capability-list.h"
11
#include "capability-util.h"
12
#include "errno-list.h"
13
#include "extract-word.h"
14
#include "locale-util.h"
15
#include "log.h"
16
#include "missing-network.h"
17
#include "parse-util.h"
18
#include "path-util.h"
19
#include "process-util.h"
20
#include "string-util.h"
21
#include "strv.h"
22

23
int parse_boolean(const char *v) {
660,886✔
24
        if (!v)
660,886✔
25
                return -EINVAL;
26

27
        if (STRCASE_IN_SET(v,
660,886✔
28
                           "1",
29
                           "yes",
30
                           "y",
31
                           "true",
32
                           "t",
33
                           "on"))
34
                return 1;
198,525✔
35

36
        if (STRCASE_IN_SET(v,
462,361✔
37
                           "0",
38
                           "no",
39
                           "n",
40
                           "false",
41
                           "f",
42
                           "off"))
43
                return 0;
425,130✔
44

45
        return -EINVAL;
37,231✔
46
}
47

48
int parse_tristate_full(const char *v, const char *third, int *ret) {
5,595✔
49
        int r;
5,595✔
50

51
        if (isempty(v) || streq_ptr(v, third)) { /* Empty string is always taken as the third/invalid/auto state */
11,190✔
52
                if (ret)
×
53
                        *ret = -1;
×
54
        } else {
55
                r = parse_boolean(v);
5,595✔
56
                if (r < 0)
5,595✔
57
                        return r;
58

59
                if (ret)
5,595✔
60
                        *ret = r;
5,595✔
61
        }
62

63
        return 0;
64
}
65

66
int parse_pid(const char *s, pid_t* ret_pid) {
78,198✔
67
        unsigned long ul = 0;
78,198✔
68
        pid_t pid;
78,198✔
69
        int r;
78,198✔
70

71
        assert(s);
78,198✔
72

73
        r = safe_atolu(s, &ul);
78,198✔
74
        if (r < 0)
78,198✔
75
                return r;
78,198✔
76

77
        pid = (pid_t) ul;
78,034✔
78

79
        if ((unsigned long) pid != ul)
78,034✔
80
                return -ERANGE;
81

82
        if (!pid_is_valid(pid))
78,034✔
83
                return -ERANGE;
84

85
        if (ret_pid)
78,032✔
86
                *ret_pid = pid;
78,030✔
87
        return 0;
88
}
89

90
int parse_mode(const char *s, mode_t *ret) {
118,193✔
91
        unsigned m;
118,193✔
92
        int r;
118,193✔
93

94
        assert(s);
118,193✔
95

96
        r = safe_atou_full(s, 8 |
118,193✔
97
                           SAFE_ATO_REFUSE_PLUS_MINUS, /* Leading '+' or even '-' char? that's just weird,
98
                                                        * refuse. User might have wanted to add mode flags or
99
                                                        * so, but this parser doesn't allow that, so let's
100
                                                        * better be safe. */
101
                           &m);
102
        if (r < 0)
118,193✔
103
                return r;
118,193✔
104
        if (m > 07777)
118,178✔
105
                return -ERANGE;
106

107
        if (ret)
118,177✔
108
                *ret = m;
118,177✔
109
        return 0;
110
}
111

112
int parse_ifindex(const char *s) {
170,139✔
113
        int ifi, r;
170,139✔
114

115
        assert(s);
170,139✔
116

117
        r = safe_atoi(s, &ifi);
170,139✔
118
        if (r < 0)
170,139✔
119
                return r;
170,139✔
120
        if (ifi <= 0)
38,058✔
121
                return -EINVAL;
2✔
122

123
        return ifi;
124
}
125

126
int parse_mtu(int family, const char *s, uint32_t *ret) {
240✔
127
        uint64_t u, m;
240✔
128
        int r;
240✔
129

130
        r = parse_size(s, 1024, &u);
240✔
131
        if (r < 0)
240✔
132
                return r;
240✔
133

134
        if (u > UINT32_MAX)
217✔
135
                return -ERANGE;
136

137
        switch (family) {
213✔
138
        case AF_INET:
139
                m = IPV4_MIN_MTU; /* This is 68 */
140
                break;
141
        case AF_INET6:
27✔
142
                m = IPV6_MIN_MTU; /* This is 1280 */
27✔
143
                break;
27✔
144
        default:
145
                m = 0;
146
        }
147

148
        if (u < m)
37✔
149
                return -ERANGE;
150

151
        *ret = (uint32_t) u;
209✔
152
        return 0;
209✔
153
}
154

155
int parse_size(const char *t, uint64_t base, uint64_t *size) {
13,540✔
156

157
        /* Soo, sometimes we want to parse IEC binary suffixes, and
158
         * sometimes SI decimal suffixes. This function can parse
159
         * both. Which one is the right way depends on the
160
         * context. Wikipedia suggests that SI is customary for
161
         * hardware metrics and network speeds, while IEC is
162
         * customary for most data sizes used by software and volatile
163
         * (RAM) memory. Hence be careful which one you pick!
164
         *
165
         * In either case we use just K, M, G as suffix, and not Ki,
166
         * Mi, Gi or so (as IEC would suggest). That's because that's
167
         * frickin' ugly. But this means you really need to make sure
168
         * to document which base you are parsing when you use this
169
         * call. */
170

171
        struct table {
13,540✔
172
                const char *suffix;
173
                unsigned long long factor;
174
        };
175

176
        static const struct table iec[] = {
13,540✔
177
                { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
178
                { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
179
                { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
180
                { "G", 1024ULL*1024ULL*1024ULL },
181
                { "M", 1024ULL*1024ULL },
182
                { "K", 1024ULL },
183
                { "B", 1ULL },
184
                { "",  1ULL },
185
        };
186

187
        static const struct table si[] = {
13,540✔
188
                { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
189
                { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
190
                { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
191
                { "G", 1000ULL*1000ULL*1000ULL },
192
                { "M", 1000ULL*1000ULL },
193
                { "K", 1000ULL },
194
                { "B", 1ULL },
195
                { "",  1ULL },
196
        };
197

198
        const struct table *table;
13,540✔
199
        const char *p;
13,540✔
200
        unsigned long long r = 0;
13,540✔
201
        unsigned n_entries, start_pos = 0;
13,540✔
202

203
        assert(t);
13,540✔
204
        assert(IN_SET(base, 1000, 1024));
13,540✔
205
        assert(size);
13,540✔
206

207
        if (base == 1000) {
13,540✔
208
                table = si;
209
                n_entries = ELEMENTSOF(si);
210
        } else {
211
                table = iec;
13,472✔
212
                n_entries = ELEMENTSOF(iec);
13,472✔
213
        }
214

215
        p = t;
13,540✔
216
        do {
13,597✔
217
                unsigned long long l, tmp;
13,597✔
218
                double frac = 0;
13,597✔
219
                char *e;
13,597✔
220
                unsigned i;
13,597✔
221

222
                p += strspn(p, WHITESPACE);
13,597✔
223

224
                errno = 0;
13,597✔
225
                l = strtoull(p, &e, 10);
13,597✔
226
                if (errno > 0)
13,597✔
227
                        return -errno;
57✔
228
                if (e == p)
13,595✔
229
                        return -EINVAL;
230
                if (*p == '-')
13,556✔
231
                        return -ERANGE;
232

233
                if (*e == '.') {
13,544✔
234
                        e++;
45✔
235

236
                        /* strtoull() itself would accept space/+/- */
237
                        if (ascii_isdigit(*e)) {
45✔
238
                                unsigned long long l2;
40✔
239
                                char *e2;
40✔
240

241
                                l2 = strtoull(e, &e2, 10);
40✔
242
                                if (errno > 0)
40✔
243
                                        return -errno;
×
244

245
                                /* Ignore failure. E.g. 10.M is valid */
246
                                frac = l2;
40✔
247
                                for (; e < e2; e++)
90✔
248
                                        frac /= 10;
50✔
249
                        }
250
                }
251

252
                e += strspn(e, WHITESPACE);
13,544✔
253

254
                for (i = start_pos; i < n_entries; i++)
104,594✔
255
                        if (startswith(e, table[i].suffix))
104,592✔
256
                                break;
257

258
                if (i >= n_entries)
13,542✔
259
                        return -EINVAL;
260

261
                if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
13,542✔
262
                        return -ERANGE;
263

264
                tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
13,540✔
265
                if (tmp > ULLONG_MAX - r)
13,540✔
266
                        return -ERANGE;
267

268
                r += tmp;
13,540✔
269
                if ((unsigned long long) (uint64_t) r != r)
13,540✔
270
                        return -ERANGE;
271

272
                p = e + strlen(table[i].suffix);
13,540✔
273

274
                start_pos = i + 1;
13,540✔
275

276
        } while (*p);
13,540✔
277

278
        *size = r;
13,483✔
279

280
        return 0;
13,483✔
281
}
282

283
int parse_sector_size(const char *t, uint64_t *ret) {
4✔
284
        int r;
4✔
285

286
        assert(t);
4✔
287
        assert(ret);
4✔
288

289
        uint64_t ss;
4✔
290

291
        r = safe_atou64(t, &ss);
4✔
292
        if (r < 0)
4✔
293
                return log_error_errno(r, "Failed to parse sector size parameter %s", t);
×
294
        if (ss < 512 || ss > 4096) /* Allow up to 4K due to dm-crypt support and 4K alignment by the homed LUKS backend */
4✔
295
                return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Sector size not between 512 and 4096: %s", t);
×
296
        if (!ISPOWEROF2(ss))
4✔
297
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Sector size not power of 2: %s", t);
×
298

299
        *ret = ss;
4✔
300
        return 0;
4✔
301
}
302

303
int parse_range(const char *t, unsigned *lower, unsigned *upper) {
366✔
304
        _cleanup_free_ char *word = NULL;
366✔
305
        unsigned l, u;
366✔
306
        int r;
366✔
307

308
        assert(lower);
366✔
309
        assert(upper);
366✔
310

311
        /* Extract the lower bound. */
312
        r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
366✔
313
        if (r < 0)
366✔
314
                return r;
315
        if (r == 0)
366✔
316
                return -EINVAL;
317

318
        r = safe_atou(word, &l);
366✔
319
        if (r < 0)
366✔
320
                return r;
321

322
        /* Check for the upper bound and extract it if needed */
323
        if (!t)
337✔
324
                /* Single number with no dashes. */
325
                u = l;
131✔
326
        else if (!*t)
206✔
327
                /* Trailing dash is an error. */
328
                return -EINVAL;
329
        else {
330
                r = safe_atou(t, &u);
205✔
331
                if (r < 0)
205✔
332
                        return r;
333
        }
334

335
        *lower = l;
324✔
336
        *upper = u;
324✔
337
        return 0;
324✔
338
}
339

340
int parse_errno(const char *t) {
1,671✔
341
        int r, e;
1,671✔
342

343
        assert(t);
1,671✔
344

345
        r = errno_from_name(t);
1,671✔
346
        if (r > 0)
1,671✔
347
                return r;
1,671✔
348

349
        r = safe_atoi(t, &e);
30✔
350
        if (r < 0)
30✔
351
                return r;
352

353
        /* 0 is also allowed here */
354
        if (!errno_is_valid(e) && e != 0)
15✔
355
                return -ERANGE;
5✔
356

357
        return e;
358
}
359

360
int parse_fd(const char *t) {
182,177✔
361
        int r, fd;
182,177✔
362

363
        assert(t);
182,177✔
364

365
        r = safe_atoi(t, &fd);
182,177✔
366
        if (r < 0)
182,177✔
367
                return r;
182,177✔
368

369
        if (fd < 0)
182,173✔
370
                return -EBADF;
2✔
371

372
        return fd;
373
}
374

375
int parse_user_shell(const char *s, char **ret_sh, bool *ret_copy) {
26✔
376
        char *sh;
26✔
377
        int r;
26✔
378

379
        if (path_is_absolute(s) && path_is_normalized(s)) {
26✔
380
                sh = strdup(s);
9✔
381
                if (!sh)
9✔
382
                        return -ENOMEM;
383

384
                *ret_sh = sh;
9✔
385
                *ret_copy = false;
9✔
386
        } else {
387
                r = parse_boolean(s);
17✔
388
                if (r < 0)
17✔
389
                        return r;
390

391
                *ret_sh = NULL;
16✔
392
                *ret_copy = r;
16✔
393
        }
394

395
        return 0;
396
}
397

398
static const char *mangle_base(const char *s, unsigned *base) {
5,797,366✔
399
        const char *k;
5,797,366✔
400

401
        assert(s);
5,797,366✔
402
        assert(base);
5,797,366✔
403

404
        /* Base already explicitly specified, then don't do anything. */
405
        if (SAFE_ATO_MASK_FLAGS(*base) != 0)
5,797,366✔
406
                return s;
5,797,366✔
407

408
        /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
409
        k = STARTSWITH_SET(s, "0b", "0B");
5,402,358✔
410
        if (k) {
5,402,358✔
411
                *base = 2 | (*base & SAFE_ATO_ALL_FLAGS);
4✔
412
                return k;
4✔
413
        }
414

415
        k = STARTSWITH_SET(s, "0o", "0O");
5,402,354✔
416
        if (k) {
5,402,354✔
417
                *base = 8 | (*base & SAFE_ATO_ALL_FLAGS);
4✔
418
                return k;
4✔
419
        }
420

421
        return s;
422
}
423

424
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
1,787,974✔
425
        char *x = NULL;
1,787,974✔
426
        unsigned long l;
1,787,974✔
427

428
        assert(s);
1,787,974✔
429
        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
1,787,974✔
430

431
        /* strtoul() is happy to parse negative values, and silently converts them to unsigned values without
432
         * generating an error. We want a clean error, hence let's look for the "-" prefix on our own, and
433
         * generate an error. But let's do so only after strtoul() validated that the string is clean
434
         * otherwise, so that we return EINVAL preferably over ERANGE. */
435

436
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
1,787,974✔
437
            strchr(WHITESPACE, s[0]))
207,578✔
438
                return -EINVAL;
1,787,974✔
439

440
        s += strspn(s, WHITESPACE);
1,787,957✔
441

442
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
1,787,957✔
443
            IN_SET(s[0], '+', '-'))
325,462✔
444
                return -EINVAL; /* Note that we check the "-" prefix again a second time below, but return a
445
                                 * different error. I.e. if the SAFE_ATO_REFUSE_PLUS_MINUS flag is set we
446
                                 * blanket refuse +/- prefixed integers, while if it is missing we'll just
447
                                 * return ERANGE, because the string actually parses correctly, but doesn't
448
                                 * fit in the return type. */
449

450
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
1,787,940✔
451
            s[0] == '0' && !streq(s, "0"))
206,108✔
452
                return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
453
                                 * notation and assumed-to-be-decimal integers with a leading zero. */
454

455
        s = mangle_base(s, &base);
1,787,920✔
456

457
        errno = 0;
1,787,920✔
458
        l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
1,787,920✔
459
                                                      * base is left */);
460
        if (errno > 0)
1,787,920✔
461
                return -errno;
2✔
462
        if (!x || x == s || *x != 0)
1,787,918✔
463
                return -EINVAL;
464
        if (l != 0 && s[0] == '-')
1,589,460✔
465
                return -ERANGE;
466
        if ((unsigned long) (unsigned) l != l)
1,487,430✔
467
                return -ERANGE;
468

469
        if (ret_u)
1,589,432✔
470
                *ret_u = (unsigned) l;
1,589,355✔
471

472
        return 0;
473
}
474

475
int safe_atou_bounded(const char *s, unsigned min, unsigned max, unsigned *ret) {
99✔
476
        unsigned v;
99✔
477
        int r;
99✔
478

479
        r = safe_atou(s, &v);
99✔
480
        if (r < 0)
99✔
481
                return r;
99✔
482

483
        if (v < min || v > max)
98✔
484
                return -ERANGE;
485

486
        *ret = v;
96✔
487
        return 0;
96✔
488
}
489

490
int safe_atoi(const char *s, int *ret_i) {
2,557,497✔
491
        unsigned base = 0;
2,557,497✔
492
        char *x = NULL;
2,557,497✔
493
        long l;
2,557,497✔
494

495
        assert(s);
2,557,497✔
496

497
        s += strspn(s, WHITESPACE);
2,557,497✔
498
        s = mangle_base(s, &base);
2,557,497✔
499

500
        errno = 0;
2,557,497✔
501
        l = strtol(s, &x, base);
2,557,497✔
502
        if (errno > 0)
2,557,497✔
503
                return -errno;
8✔
504
        if (!x || x == s || *x != 0)
2,557,489✔
505
                return -EINVAL;
506
        if ((long) (int) l != l)
2,413,480✔
507
                return -ERANGE;
508

509
        if (ret_i)
2,413,473✔
510
                *ret_i = (int) l;
2,413,102✔
511

512
        return 0;
513
}
514

515
int safe_atollu_full(const char *s, unsigned base, unsigned long long *ret_llu) {
1,451,895✔
516
        char *x = NULL;
1,451,895✔
517
        unsigned long long l;
1,451,895✔
518

519
        assert(s);
1,451,895✔
520
        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
1,451,895✔
521

522
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
1,451,895✔
523
            strchr(WHITESPACE, s[0]))
×
524
                return -EINVAL;
1,451,895✔
525

526
        s += strspn(s, WHITESPACE);
1,451,895✔
527

528
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
1,451,895✔
529
            IN_SET(s[0], '+', '-'))
×
530
                return -EINVAL;
531

532
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
1,451,895✔
533
            s[0] == '0' && s[1] != 0)
×
534
                return -EINVAL;
535

536
        s = mangle_base(s, &base);
1,451,895✔
537

538
        errno = 0;
1,451,895✔
539
        l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
1,451,895✔
540
        if (errno > 0)
1,451,895✔
541
                return -errno;
3✔
542
        if (!x || x == s || *x != 0)
1,451,892✔
543
                return -EINVAL;
544
        if (l != 0 && s[0] == '-')
1,451,712✔
545
                return -ERANGE;
546

547
        if (ret_llu)
1,451,705✔
548
                *ret_llu = l;
1,451,705✔
549

550
        return 0;
551
}
552

553
int safe_atolli(const char *s, long long *ret_lli) {
40✔
554
        unsigned base = 0;
40✔
555
        char *x = NULL;
40✔
556
        long long l;
40✔
557

558
        assert(s);
40✔
559

560
        s += strspn(s, WHITESPACE);
40✔
561
        s = mangle_base(s, &base);
40✔
562

563
        errno = 0;
40✔
564
        l = strtoll(s, &x, base);
40✔
565
        if (errno > 0)
40✔
566
                return -errno;
4✔
567
        if (!x || x == s || *x != 0)
36✔
568
                return -EINVAL;
569

570
        if (ret_lli)
28✔
571
                *ret_lli = l;
28✔
572

573
        return 0;
574
}
575

576
int safe_atou8_full(const char *s, unsigned base, uint8_t *ret) {
144,508✔
577
        unsigned u;
144,508✔
578
        int r;
144,508✔
579

580
        r = safe_atou_full(s, base, &u);
144,508✔
581
        if (r < 0)
144,508✔
582
                return r;
144,508✔
583
        if (u > UINT8_MAX)
144,389✔
584
                return -ERANGE;
585

586
        *ret = (uint8_t) u;
144,388✔
587
        return 0;
144,388✔
588
}
589

590
int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
4,175✔
591
        unsigned u;
4,175✔
592
        int r;
4,175✔
593

594
        r = safe_atou_full(s, base, &u);
4,175✔
595
        if (r < 0)
4,175✔
596
                return r;
4,175✔
597
        if (u > UINT16_MAX)
4,092✔
598
                return -ERANGE;
599

600
        *ret = (uint16_t) u;
4,085✔
601
        return 0;
4,085✔
602
}
603

604
int safe_atoi16(const char *s, int16_t *ret) {
14✔
605
        unsigned base = 0;
14✔
606
        char *x = NULL;
14✔
607
        long l;
14✔
608

609
        assert(s);
14✔
610

611
        s += strspn(s, WHITESPACE);
14✔
612
        s = mangle_base(s, &base);
14✔
613

614
        errno = 0;
14✔
615
        l = strtol(s, &x, base);
14✔
616
        if (errno > 0)
14✔
617
                return -errno;
×
618
        if (!x || x == s || *x != 0)
14✔
619
                return -EINVAL;
620
        if ((long) (int16_t) l != l)
10✔
621
                return -ERANGE;
622

623
        if (ret)
8✔
624
                *ret = (int16_t) l;
8✔
625

626
        return 0;
627
}
628

629
int safe_atod(const char *s, double *ret_d) {
9✔
630
        _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
18✔
631
        char *x = NULL;
9✔
632
        double d = 0;
9✔
633

634
        assert(s);
9✔
635

636
        loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
9✔
637
        if (loc == (locale_t) 0)
9✔
638
                return -errno;
×
639

640
        errno = 0;
9✔
641
        d = strtod_l(s, &x, loc);
9✔
642
        if (errno > 0)
9✔
643
                return -errno;
×
644
        if (!x || x == s || *x != 0)
9✔
645
                return -EINVAL;
646

647
        if (ret_d)
6✔
648
                *ret_d = (double) d;
6✔
649

650
        return 0;
651
}
652

653
int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
458✔
654
        unsigned val = 0;
458✔
655
        const char *s;
458✔
656

657
        s = *p;
458✔
658

659
        /* accept any number of digits, strtoull is limited to 19 */
660
        for (size_t i = 0; i < digits; i++, s++) {
2,704✔
661
                if (!ascii_isdigit(*s)) {
2,422✔
662
                        if (i == 0)
176✔
663
                                return -EINVAL;
664

665
                        /* too few digits, pad with 0 */
666
                        for (; i < digits; i++)
678✔
667
                                val *= 10;
502✔
668

669
                        break;
670
                }
671

672
                val *= 10;
2,246✔
673
                val += *s - '0';
2,246✔
674
        }
675

676
        /* maybe round up */
677
        if (*s >= '5' && *s <= '9')
458✔
678
                val++;
4✔
679

680
        s += strspn(s, DIGITS);
458✔
681

682
        *p = s;
458✔
683
        *res = val;
458✔
684

685
        return 0;
458✔
686
}
687

688
int parse_nice(const char *p, int *ret) {
263✔
689
        int n, r;
263✔
690

691
        r = safe_atoi(p, &n);
263✔
692
        if (r < 0)
263✔
693
                return r;
263✔
694

695
        if (!nice_is_valid(n))
257✔
696
                return -ERANGE;
697

698
        *ret = n;
251✔
699
        return 0;
251✔
700
}
701

702
int parse_ip_port(const char *s, uint16_t *ret) {
296✔
703
        uint16_t l;
296✔
704
        int r;
296✔
705

706
        r = safe_atou16_full(s, SAFE_ATO_REFUSE_LEADING_WHITESPACE, &l);
296✔
707
        if (r < 0)
296✔
708
                return r;
296✔
709

710
        if (l == 0)
223✔
711
                return -EINVAL;
712

713
        *ret = (uint16_t) l;
218✔
714

715
        return 0;
218✔
716
}
717

718
int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high, bool allow_zero) {
36✔
719
        unsigned l, h;
36✔
720
        int r;
36✔
721

722
        r = parse_range(s, &l, &h);
36✔
723
        if (r < 0)
36✔
724
                return r;
36✔
725

726
        if (l > 65535 || h > 65535)
26✔
727
                return -EINVAL;
728

729
        if (!allow_zero && (l == 0 || h == 0))
24✔
730
                return -EINVAL;
731

732
        if (h < l)
24✔
733
                return -EINVAL;
734

735
        *low = l;
23✔
736
        *high = h;
23✔
737

738
        return 0;
23✔
739
}
740

741
int parse_oom_score_adjust(const char *s, int *ret) {
642✔
742
        int r, v;
642✔
743

744
        assert(s);
642✔
745
        assert(ret);
642✔
746

747
        r = safe_atoi(s, &v);
642✔
748
        if (r < 0)
642✔
749
                return r;
642✔
750

751
        if (!oom_score_adjust_is_valid(v))
640✔
752
                return -ERANGE;
753

754
        *ret = v;
640✔
755
        return 0;
640✔
756
}
757

758
int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret) {
571✔
759
        assert(ret);
571✔
760

761
        if (i >= (~0UL << LOADAVG_PRECISION_BITS))
571✔
762
                return -ERANGE;
763

764
        i = i << LOADAVG_PRECISION_BITS;
570✔
765
        f = DIV_ROUND_UP((f << LOADAVG_PRECISION_BITS), 100);
570✔
766

767
        if (f >= LOADAVG_FIXED_POINT_1_0)
570✔
768
                return -ERANGE;
769

770
        *ret = i | f;
568✔
771
        return 0;
568✔
772
}
773

774
int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
548✔
775
        const char *d, *f_str, *i_str;
548✔
776
        unsigned long i, f;
548✔
777
        int r;
548✔
778

779
        assert(s);
548✔
780
        assert(ret);
548✔
781

782
        d = strchr(s, '.');
548✔
783
        if (!d)
548✔
784
                return -EINVAL;
548✔
785

786
        i_str = strndupa_safe(s, d - s);
545✔
787
        f_str = d + 1;
545✔
788

789
        r = safe_atolu_full(i_str, 10, &i);
545✔
790
        if (r < 0)
545✔
791
                return r;
792

793
        r = safe_atolu_full(f_str, 10, &f);
543✔
794
        if (r < 0)
543✔
795
                return r;
796

797
        return store_loadavg_fixed_point(i, f, ret);
541✔
798
}
799

800
/* Limitations are described in https://www.netfilter.org/projects/nftables/manpage.html and
801
 * https://bugzilla.netfilter.org/show_bug.cgi?id=1175 */
802
bool nft_identifier_valid(const char *id) {
106✔
803
        if (isempty(id))
106✔
804
                return false;
805

806
        if (strlen(id) >= NFT_NAME_MAXLEN)
104✔
807
                return false;
808

809
        if (!ascii_isalpha(id[0]))
103✔
810
                return false;
811

812
        return in_charset(id + 1, ALPHANUMERICAL "/\\_.");
101✔
813
}
814

815
int parse_capability_set(const char *s, uint64_t initial, uint64_t *current) {
1,715✔
816
        int r;
1,715✔
817

818
        assert(s);
1,715✔
819
        assert(current);
1,715✔
820

821
        if (isempty(s)) {
1,715✔
822
                *current = CAP_MASK_UNSET;
5✔
823
                return 1;
5✔
824
        }
825

826
        bool invert = false;
1,710✔
827
        if (s[0] == '~') {
1,710✔
828
                invert = true;
120✔
829
                s++;
120✔
830
        }
831

832
        uint64_t parsed;
1,710✔
833
        r = capability_set_from_string(s, &parsed);
1,710✔
834
        if (r < 0)
1,710✔
835
                return r;
836

837
        if (parsed == 0 || *current == initial)
1,710✔
838
                /* "~" or uninitialized data -> replace */
839
                *current = invert ? all_capabilities() & ~parsed : parsed;
1,810✔
840
        else {
841
                /* previous data -> merge */
842
                if (invert)
14✔
843
                        *current &= ~parsed;
6✔
844
                else
845
                        *current |= parsed;
8✔
846
        }
847

848
        return r;
849
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc