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

systemd / systemd / 15263807472

26 May 2025 08:53PM UTC coverage: 72.046% (-0.002%) from 72.048%
15263807472

push

github

yuwata
src/core/manager.c: log preset activity on first boot

This gives us a little more information about what units were enabled
or disabled on that first boot and will be useful for OS developers
tracking down the source of unit state.

An example with this enabled looks like:

```
NET: Registered PF_VSOCK protocol family
systemd[1]: Applying preset policy.
systemd[1]: Unit /etc/systemd/system/dnsmasq.service is masked, ignoring.
systemd[1]: Unit /etc/systemd/system/systemd-repart.service is masked, ignoring.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket'.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir.mount' → '/etc/systemd/system/var-mnt-workdir.mount'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir\x2dtmp.mount' → '/etc/systemd/system/var-mnt-workdir\x2dtmp.mount'.
systemd[1]: Created symlink '/etc/systemd/system/afterburn-sshkeys.target.requires/afterburn-sshkeys@core.service' → '/usr/lib/systemd/system/afterburn-sshkeys@.service'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket' → '/usr/lib/systemd/system/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket' → '/usr/lib/systemd/system/systemd-resolved-monitor.socket'.
systemd[1]: Populated /etc with preset unit settings.
```

Considering it only happens on first boot and not on every boot I think
the extra information is worth the extra verbosity in the logs just for
that boot.

5 of 6 new or added lines in 1 file covered. (83.33%)

5463 existing lines in 165 files now uncovered.

299151 of 415222 relevant lines covered (72.05%)

702386.45 hits per line

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

96.95
/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 "errno-list.h"
11
#include "extract-word.h"
12
#include "locale-util.h"
13
#include "log.h"
14
#include "missing_network.h"
15
#include "parse-util.h"
16
#include "process-util.h"
17
#include "string-util.h"
18
#include "strv.h"
19

20
int parse_boolean(const char *v) {
648,911✔
21
        if (!v)
648,911✔
22
                return -EINVAL;
23

24
        if (STRCASE_IN_SET(v,
648,911✔
25
                           "1",
26
                           "yes",
27
                           "y",
28
                           "true",
29
                           "t",
30
                           "on"))
31
                return 1;
187,271✔
32

33
        if (STRCASE_IN_SET(v,
461,640✔
34
                           "0",
35
                           "no",
36
                           "n",
37
                           "false",
38
                           "f",
39
                           "off"))
40
                return 0;
429,172✔
41

42
        return -EINVAL;
32,468✔
43
}
44

45
int parse_tristate_full(const char *v, const char *third, int *ret) {
6,881✔
46
        int r;
6,881✔
47

48
        if (isempty(v) || streq_ptr(v, third)) { /* Empty string is always taken as the third/invalid/auto state */
13,762✔
UNCOV
49
                if (ret)
×
UNCOV
50
                        *ret = -1;
×
51
        } else {
52
                r = parse_boolean(v);
6,881✔
53
                if (r < 0)
6,881✔
54
                        return r;
55

56
                if (ret)
6,881✔
57
                        *ret = r;
6,881✔
58
        }
59

60
        return 0;
61
}
62

63
int parse_pid(const char *s, pid_t* ret_pid) {
98,732✔
64
        unsigned long ul = 0;
98,732✔
65
        pid_t pid;
98,732✔
66
        int r;
98,732✔
67

68
        assert(s);
98,732✔
69

70
        r = safe_atolu(s, &ul);
98,732✔
71
        if (r < 0)
98,732✔
72
                return r;
98,732✔
73

74
        pid = (pid_t) ul;
98,590✔
75

76
        if ((unsigned long) pid != ul)
98,590✔
77
                return -ERANGE;
78

79
        if (!pid_is_valid(pid))
98,590✔
80
                return -ERANGE;
81

82
        if (ret_pid)
98,588✔
83
                *ret_pid = pid;
98,586✔
84
        return 0;
85
}
86

87
int parse_mode(const char *s, mode_t *ret) {
112,270✔
88
        unsigned m;
112,270✔
89
        int r;
112,270✔
90

91
        assert(s);
112,270✔
92

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

104
        if (ret)
112,254✔
105
                *ret = m;
112,254✔
106
        return 0;
107
}
108

109
int parse_ifindex(const char *s) {
162,832✔
110
        int ifi, r;
162,832✔
111

112
        assert(s);
162,832✔
113

114
        r = safe_atoi(s, &ifi);
162,832✔
115
        if (r < 0)
162,832✔
116
                return r;
162,832✔
117
        if (ifi <= 0)
38,219✔
118
                return -EINVAL;
2✔
119

120
        return ifi;
121
}
122

123
int parse_mtu(int family, const char *s, uint32_t *ret) {
206✔
124
        uint64_t u, m;
206✔
125
        int r;
206✔
126

127
        r = parse_size(s, 1024, &u);
206✔
128
        if (r < 0)
206✔
129
                return r;
206✔
130

131
        if (u > UINT32_MAX)
185✔
132
                return -ERANGE;
133

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

145
        if (u < m)
37✔
146
                return -ERANGE;
147

148
        *ret = (uint32_t) u;
177✔
149
        return 0;
177✔
150
}
151

152
int parse_size(const char *t, uint64_t base, uint64_t *size) {
13,094✔
153

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

168
        struct table {
13,094✔
169
                const char *suffix;
170
                unsigned long long factor;
171
        };
172

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

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

195
        const struct table *table;
13,094✔
196
        const char *p;
13,094✔
197
        unsigned long long r = 0;
13,094✔
198
        unsigned n_entries, start_pos = 0;
13,094✔
199

200
        assert(t);
13,094✔
201
        assert(IN_SET(base, 1000, 1024));
13,094✔
202
        assert(size);
13,094✔
203

204
        if (base == 1000) {
13,094✔
205
                table = si;
206
                n_entries = ELEMENTSOF(si);
207
        } else {
208
                table = iec;
13,037✔
209
                n_entries = ELEMENTSOF(iec);
13,037✔
210
        }
211

212
        p = t;
13,094✔
213
        do {
13,149✔
214
                unsigned long long l, tmp;
13,149✔
215
                double frac = 0;
13,149✔
216
                char *e;
13,149✔
217
                unsigned i;
13,149✔
218

219
                p += strspn(p, WHITESPACE);
13,149✔
220

221
                errno = 0;
13,149✔
222
                l = strtoull(p, &e, 10);
13,149✔
223
                if (errno > 0)
13,149✔
224
                        return -errno;
55✔
225
                if (e == p)
13,147✔
226
                        return -EINVAL;
227
                if (*p == '-')
13,110✔
228
                        return -ERANGE;
229

230
                if (*e == '.') {
13,098✔
231
                        e++;
42✔
232

233
                        /* strtoull() itself would accept space/+/- */
234
                        if (ascii_isdigit(*e)) {
42✔
235
                                unsigned long long l2;
38✔
236
                                char *e2;
38✔
237

238
                                l2 = strtoull(e, &e2, 10);
38✔
239
                                if (errno > 0)
38✔
UNCOV
240
                                        return -errno;
×
241

242
                                /* Ignore failure. E.g. 10.M is valid */
243
                                frac = l2;
38✔
244
                                for (; e < e2; e++)
84✔
245
                                        frac /= 10;
46✔
246
                        }
247
                }
248

249
                e += strspn(e, WHITESPACE);
13,098✔
250

251
                for (i = start_pos; i < n_entries; i++)
100,984✔
252
                        if (startswith(e, table[i].suffix))
100,982✔
253
                                break;
254

255
                if (i >= n_entries)
13,096✔
256
                        return -EINVAL;
257

258
                if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
13,096✔
259
                        return -ERANGE;
260

261
                tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
13,094✔
262
                if (tmp > ULLONG_MAX - r)
13,094✔
263
                        return -ERANGE;
264

265
                r += tmp;
13,094✔
266
                if ((unsigned long long) (uint64_t) r != r)
13,094✔
267
                        return -ERANGE;
268

269
                p = e + strlen(table[i].suffix);
13,094✔
270

271
                start_pos = i + 1;
13,094✔
272

273
        } while (*p);
13,094✔
274

275
        *size = r;
13,039✔
276

277
        return 0;
13,039✔
278
}
279

280
int parse_sector_size(const char *t, uint64_t *ret) {
4✔
281
        int r;
4✔
282

283
        assert(t);
4✔
284
        assert(ret);
4✔
285

286
        uint64_t ss;
4✔
287

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

296
        *ret = ss;
4✔
297
        return 0;
4✔
298
}
299

300
int parse_range(const char *t, unsigned *lower, unsigned *upper) {
331✔
301
        _cleanup_free_ char *word = NULL;
331✔
302
        unsigned l, u;
331✔
303
        int r;
331✔
304

305
        assert(lower);
331✔
306
        assert(upper);
331✔
307

308
        /* Extract the lower bound. */
309
        r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
331✔
310
        if (r < 0)
331✔
311
                return r;
312
        if (r == 0)
331✔
313
                return -EINVAL;
314

315
        r = safe_atou(word, &l);
331✔
316
        if (r < 0)
331✔
317
                return r;
318

319
        /* Check for the upper bound and extract it if needed */
320
        if (!t)
302✔
321
                /* Single number with no dashes. */
322
                u = l;
105✔
323
        else if (!*t)
197✔
324
                /* Trailing dash is an error. */
325
                return -EINVAL;
326
        else {
327
                r = safe_atou(t, &u);
196✔
328
                if (r < 0)
196✔
329
                        return r;
330
        }
331

332
        *lower = l;
289✔
333
        *upper = u;
289✔
334
        return 0;
289✔
335
}
336

337
int parse_errno(const char *t) {
1,600✔
338
        int r, e;
1,600✔
339

340
        assert(t);
1,600✔
341

342
        r = errno_from_name(t);
1,600✔
343
        if (r > 0)
1,600✔
344
                return r;
1,600✔
345

346
        r = safe_atoi(t, &e);
29✔
347
        if (r < 0)
29✔
348
                return r;
349

350
        /* 0 is also allowed here */
351
        if (!errno_is_valid(e) && e != 0)
14✔
352
                return -ERANGE;
5✔
353

354
        return e;
355
}
356

357
int parse_fd(const char *t) {
174,928✔
358
        int r, fd;
174,928✔
359

360
        assert(t);
174,928✔
361

362
        r = safe_atoi(t, &fd);
174,928✔
363
        if (r < 0)
174,928✔
364
                return r;
174,928✔
365

366
        if (fd < 0)
174,924✔
367
                return -EBADF;
2✔
368

369
        return fd;
370
}
371

372
static const char *mangle_base(const char *s, unsigned *base) {
5,859,481✔
373
        const char *k;
5,859,481✔
374

375
        assert(s);
5,859,481✔
376
        assert(base);
5,859,481✔
377

378
        /* Base already explicitly specified, then don't do anything. */
379
        if (SAFE_ATO_MASK_FLAGS(*base) != 0)
5,859,481✔
380
                return s;
5,859,481✔
381

382
        /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
383
        k = STARTSWITH_SET(s, "0b", "0B");
5,474,181✔
384
        if (k) {
5,474,181✔
385
                *base = 2 | (*base & SAFE_ATO_ALL_FLAGS);
4✔
386
                return k;
4✔
387
        }
388

389
        k = STARTSWITH_SET(s, "0o", "0O");
5,474,177✔
390
        if (k) {
5,474,177✔
391
                *base = 8 | (*base & SAFE_ATO_ALL_FLAGS);
4✔
392
                return k;
4✔
393
        }
394

395
        return s;
396
}
397

398
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
2,018,665✔
399
        char *x = NULL;
2,018,665✔
400
        unsigned long l;
2,018,665✔
401

402
        assert(s);
2,018,665✔
403
        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
2,018,665✔
404

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

410
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
2,018,665✔
411
            strchr(WHITESPACE, s[0]))
207,438✔
412
                return -EINVAL;
2,018,665✔
413

414
        s += strspn(s, WHITESPACE);
2,018,648✔
415

416
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
2,018,648✔
417
            IN_SET(s[0], '+', '-'))
319,406✔
418
                return -EINVAL; /* Note that we check the "-" prefix again a second time below, but return a
419
                                 * different error. I.e. if the SAFE_ATO_REFUSE_PLUS_MINUS flag is set we
420
                                 * blanket refuse +/- prefixed integers, while if it is missing we'll just
421
                                 * return ERANGE, because the string actually parses correctly, but doesn't
422
                                 * fit in the return type. */
423

424
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
2,018,631✔
425
            s[0] == '0' && !streq(s, "0"))
206,497✔
426
                return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
427
                                 * notation and assumed-to-be-decimal integers with a leading zero. */
428

429
        s = mangle_base(s, &base);
2,018,611✔
430

431
        errno = 0;
2,018,611✔
432
        l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
2,018,611✔
433
                                                      * base is left */);
434
        if (errno > 0)
2,018,611✔
435
                return -errno;
2✔
436
        if (!x || x == s || *x != 0)
2,018,609✔
437
                return -EINVAL;
438
        if (l != 0 && s[0] == '-')
1,816,853✔
439
                return -ERANGE;
440
        if ((unsigned long) (unsigned) l != l)
1,712,245✔
441
                return -ERANGE;
442

443
        if (ret_u)
1,816,825✔
444
                *ret_u = (unsigned) l;
1,816,752✔
445

446
        return 0;
447
}
448

449
int safe_atou_bounded(const char *s, unsigned min, unsigned max, unsigned *ret) {
97✔
450
        unsigned v;
97✔
451
        int r;
97✔
452

453
        r = safe_atou(s, &v);
97✔
454
        if (r < 0)
97✔
455
                return r;
97✔
456

457
        if (v < min || v > max)
96✔
458
                return -ERANGE;
459

460
        *ret = v;
94✔
461
        return 0;
94✔
462
}
463

464
int safe_atoi(const char *s, int *ret_i) {
2,237,805✔
465
        unsigned base = 0;
2,237,805✔
466
        char *x = NULL;
2,237,805✔
467
        long l;
2,237,805✔
468

469
        assert(s);
2,237,805✔
470

471
        s += strspn(s, WHITESPACE);
2,237,805✔
472
        s = mangle_base(s, &base);
2,237,805✔
473

474
        errno = 0;
2,237,805✔
475
        l = strtol(s, &x, base);
2,237,805✔
476
        if (errno > 0)
2,237,805✔
477
                return -errno;
8✔
478
        if (!x || x == s || *x != 0)
2,237,797✔
479
                return -EINVAL;
480
        if ((long) (int) l != l)
2,101,415✔
481
                return -ERANGE;
482

483
        if (ret_i)
2,101,409✔
484
                *ret_i = (int) l;
2,101,127✔
485

486
        return 0;
487
}
488

489
int safe_atollu_full(const char *s, unsigned base, unsigned long long *ret_llu) {
1,603,016✔
490
        char *x = NULL;
1,603,016✔
491
        unsigned long long l;
1,603,016✔
492

493
        assert(s);
1,603,016✔
494
        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
1,603,016✔
495

496
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
1,603,016✔
UNCOV
497
            strchr(WHITESPACE, s[0]))
×
498
                return -EINVAL;
1,603,016✔
499

500
        s += strspn(s, WHITESPACE);
1,603,016✔
501

502
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
1,603,016✔
UNCOV
503
            IN_SET(s[0], '+', '-'))
×
504
                return -EINVAL;
505

506
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
1,603,016✔
UNCOV
507
            s[0] == '0' && s[1] != 0)
×
508
                return -EINVAL;
509

510
        s = mangle_base(s, &base);
1,603,016✔
511

512
        errno = 0;
1,603,016✔
513
        l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
1,603,016✔
514
        if (errno > 0)
1,603,016✔
515
                return -errno;
3✔
516
        if (!x || x == s || *x != 0)
1,603,013✔
517
                return -EINVAL;
518
        if (l != 0 && s[0] == '-')
1,602,855✔
519
                return -ERANGE;
520

521
        if (ret_llu)
1,602,848✔
522
                *ret_llu = l;
1,602,848✔
523

524
        return 0;
525
}
526

527
int safe_atolli(const char *s, long long *ret_lli) {
35✔
528
        unsigned base = 0;
35✔
529
        char *x = NULL;
35✔
530
        long long l;
35✔
531

532
        assert(s);
35✔
533

534
        s += strspn(s, WHITESPACE);
35✔
535
        s = mangle_base(s, &base);
35✔
536

537
        errno = 0;
35✔
538
        l = strtoll(s, &x, base);
35✔
539
        if (errno > 0)
35✔
540
                return -errno;
4✔
541
        if (!x || x == s || *x != 0)
31✔
542
                return -EINVAL;
543

544
        if (ret_lli)
23✔
545
                *ret_lli = l;
23✔
546

547
        return 0;
548
}
549

550
int safe_atou8_full(const char *s, unsigned base, uint8_t *ret) {
143,331✔
551
        unsigned u;
143,331✔
552
        int r;
143,331✔
553

554
        r = safe_atou_full(s, base, &u);
143,331✔
555
        if (r < 0)
143,331✔
556
                return r;
143,331✔
557
        if (u > UINT8_MAX)
143,215✔
558
                return -ERANGE;
559

560
        *ret = (uint8_t) u;
143,214✔
561
        return 0;
143,214✔
562
}
563

564
int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
3,821✔
565
        unsigned u;
3,821✔
566
        int r;
3,821✔
567

568
        r = safe_atou_full(s, base, &u);
3,821✔
569
        if (r < 0)
3,821✔
570
                return r;
3,821✔
571
        if (u > UINT16_MAX)
3,738✔
572
                return -ERANGE;
573

574
        *ret = (uint16_t) u;
3,731✔
575
        return 0;
3,731✔
576
}
577

578
int safe_atoi16(const char *s, int16_t *ret) {
14✔
579
        unsigned base = 0;
14✔
580
        char *x = NULL;
14✔
581
        long l;
14✔
582

583
        assert(s);
14✔
584

585
        s += strspn(s, WHITESPACE);
14✔
586
        s = mangle_base(s, &base);
14✔
587

588
        errno = 0;
14✔
589
        l = strtol(s, &x, base);
14✔
590
        if (errno > 0)
14✔
UNCOV
591
                return -errno;
×
592
        if (!x || x == s || *x != 0)
14✔
593
                return -EINVAL;
594
        if ((long) (int16_t) l != l)
10✔
595
                return -ERANGE;
596

597
        if (ret)
8✔
598
                *ret = (int16_t) l;
8✔
599

600
        return 0;
601
}
602

603
int safe_atod(const char *s, double *ret_d) {
12✔
604
        _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
24✔
605
        char *x = NULL;
12✔
606
        double d = 0;
12✔
607

608
        assert(s);
12✔
609

610
        loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
12✔
611
        if (loc == (locale_t) 0)
12✔
UNCOV
612
                return -errno;
×
613

614
        errno = 0;
12✔
615
        d = strtod_l(s, &x, loc);
12✔
616
        if (errno > 0)
12✔
617
                return -errno;
×
618
        if (!x || x == s || *x != 0)
12✔
619
                return -EINVAL;
620

621
        if (ret_d)
7✔
622
                *ret_d = (double) d;
7✔
623

624
        return 0;
625
}
626

627
int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
457✔
628
        unsigned val = 0;
457✔
629
        const char *s;
457✔
630

631
        s = *p;
457✔
632

633
        /* accept any number of digits, strtoull is limited to 19 */
634
        for (size_t i = 0; i < digits; i++, s++) {
2,697✔
635
                if (!ascii_isdigit(*s)) {
2,416✔
636
                        if (i == 0)
176✔
637
                                return -EINVAL;
638

639
                        /* too few digits, pad with 0 */
640
                        for (; i < digits; i++)
678✔
641
                                val *= 10;
502✔
642

643
                        break;
644
                }
645

646
                val *= 10;
2,240✔
647
                val += *s - '0';
2,240✔
648
        }
649

650
        /* maybe round up */
651
        if (*s >= '5' && *s <= '9')
457✔
652
                val++;
4✔
653

654
        s += strspn(s, DIGITS);
457✔
655

656
        *p = s;
457✔
657
        *res = val;
457✔
658

659
        return 0;
457✔
660
}
661

662
int parse_nice(const char *p, int *ret) {
270✔
663
        int n, r;
270✔
664

665
        r = safe_atoi(p, &n);
270✔
666
        if (r < 0)
270✔
667
                return r;
270✔
668

669
        if (!nice_is_valid(n))
264✔
670
                return -ERANGE;
671

672
        *ret = n;
258✔
673
        return 0;
258✔
674
}
675

676
int parse_ip_port(const char *s, uint16_t *ret) {
289✔
677
        uint16_t l;
289✔
678
        int r;
289✔
679

680
        r = safe_atou16_full(s, SAFE_ATO_REFUSE_LEADING_WHITESPACE, &l);
289✔
681
        if (r < 0)
289✔
682
                return r;
289✔
683

684
        if (l == 0)
216✔
685
                return -EINVAL;
686

687
        *ret = (uint16_t) l;
211✔
688

689
        return 0;
211✔
690
}
691

692
int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high, bool allow_zero) {
32✔
693
        unsigned l, h;
32✔
694
        int r;
32✔
695

696
        r = parse_range(s, &l, &h);
32✔
697
        if (r < 0)
32✔
698
                return r;
32✔
699

700
        if (l > 65535 || h > 65535)
22✔
701
                return -EINVAL;
702

703
        if (!allow_zero && (l == 0 || h == 0))
20✔
704
                return -EINVAL;
705

706
        if (h < l)
20✔
707
                return -EINVAL;
708

709
        *low = l;
19✔
710
        *high = h;
19✔
711

712
        return 0;
19✔
713
}
714

715
int parse_oom_score_adjust(const char *s, int *ret) {
694✔
716
        int r, v;
694✔
717

718
        assert(s);
694✔
719
        assert(ret);
694✔
720

721
        r = safe_atoi(s, &v);
694✔
722
        if (r < 0)
694✔
723
                return r;
694✔
724

725
        if (!oom_score_adjust_is_valid(v))
692✔
726
                return -ERANGE;
727

728
        *ret = v;
692✔
729
        return 0;
692✔
730
}
731

732
int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret) {
577✔
733
        assert(ret);
577✔
734

735
        if (i >= (~0UL << LOADAVG_PRECISION_BITS))
577✔
736
                return -ERANGE;
737

738
        i = i << LOADAVG_PRECISION_BITS;
576✔
739
        f = DIV_ROUND_UP((f << LOADAVG_PRECISION_BITS), 100);
576✔
740

741
        if (f >= LOADAVG_FIXED_POINT_1_0)
576✔
742
                return -ERANGE;
743

744
        *ret = i | f;
574✔
745
        return 0;
574✔
746
}
747

748
int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
554✔
749
        const char *d, *f_str, *i_str;
554✔
750
        unsigned long i, f;
554✔
751
        int r;
554✔
752

753
        assert(s);
554✔
754
        assert(ret);
554✔
755

756
        d = strchr(s, '.');
554✔
757
        if (!d)
554✔
758
                return -EINVAL;
554✔
759

760
        i_str = strndupa_safe(s, d - s);
551✔
761
        f_str = d + 1;
551✔
762

763
        r = safe_atolu_full(i_str, 10, &i);
551✔
764
        if (r < 0)
551✔
765
                return r;
766

767
        r = safe_atolu_full(f_str, 10, &f);
549✔
768
        if (r < 0)
549✔
769
                return r;
770

771
        return store_loadavg_fixed_point(i, f, ret);
547✔
772
}
773

774
/* Limitations are described in https://www.netfilter.org/projects/nftables/manpage.html and
775
 * https://bugzilla.netfilter.org/show_bug.cgi?id=1175 */
776
bool nft_identifier_valid(const char *id) {
102✔
777
        if (isempty(id))
102✔
778
                return false;
779

780
        if (strlen(id) >= NFT_NAME_MAXLEN)
100✔
781
                return false;
782

783
        if (!ascii_isalpha(id[0]))
99✔
784
                return false;
785

786
        return in_charset(id + 1, ALPHANUMERICAL "/\\_.");
97✔
787
}
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