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

systemd / systemd / 13578340107

27 Feb 2025 09:12PM UTC coverage: 71.822% (+0.002%) from 71.82%
13578340107

push

github

web-flow
Issue OSC ANSI sequence whenever we change "context" of a TTY, i.e. acquire privs, enter container or VM or similar (#35224)

This is mostly a strawman to get a discussion going regarding how to
communicate to terminal emulators such as ptyxis about run0 (and nspawn,
and vmspawn, and moe) and what it does.

It's hierarchical and I think still relatively simple.

/cc @chergert

316 of 400 new or added lines in 18 files covered. (79.0%)

975 existing lines in 59 files now uncovered.

294628 of 410221 relevant lines covered (71.82%)

715614.58 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 <errno.h>
4
#include <inttypes.h>
5
#include <linux/ipv6.h>
6
#include <linux/netfilter/nf_tables.h>
7
#include <net/if.h>
8
#include <stdio.h>
9
#include <stdlib.h>
10
#include <sys/socket.h>
11

12
#include "alloc-util.h"
13
#include "errno-list.h"
14
#include "extract-word.h"
15
#include "locale-util.h"
16
#include "macro.h"
17
#include "missing_network.h"
18
#include "parse-util.h"
19
#include "process-util.h"
20
#include "stat-util.h"
21
#include "string-util.h"
22
#include "strv.h"
23

24
int parse_boolean(const char *v) {
691,847✔
25
        if (!v)
691,847✔
26
                return -EINVAL;
27

28
        if (STRCASE_IN_SET(v,
691,847✔
29
                           "1",
30
                           "yes",
31
                           "y",
32
                           "true",
33
                           "t",
34
                           "on"))
35
                return 1;
229,630✔
36

37
        if (STRCASE_IN_SET(v,
462,217✔
38
                           "0",
39
                           "no",
40
                           "n",
41
                           "false",
42
                           "f",
43
                           "off"))
44
                return 0;
435,437✔
45

46
        return -EINVAL;
26,780✔
47
}
48

49
int parse_tristate_full(const char *v, const char *third, int *ret) {
6,788✔
50
        int r;
6,788✔
51

52
        if (isempty(v) || streq_ptr(v, third)) { /* Empty string is always taken as the third/invalid/auto state */
13,576✔
53
                if (ret)
×
UNCOV
54
                        *ret = -1;
×
55
        } else {
56
                r = parse_boolean(v);
6,788✔
57
                if (r < 0)
6,788✔
58
                        return r;
59

60
                if (ret)
6,788✔
61
                        *ret = r;
6,788✔
62
        }
63

64
        return 0;
65
}
66

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

72
        assert(s);
104,220✔
73

74
        r = safe_atolu(s, &ul);
104,220✔
75
        if (r < 0)
104,220✔
76
                return r;
104,220✔
77

78
        pid = (pid_t) ul;
103,506✔
79

80
        if ((unsigned long) pid != ul)
103,506✔
81
                return -ERANGE;
82

83
        if (!pid_is_valid(pid))
103,506✔
84
                return -ERANGE;
85

86
        if (ret_pid)
103,504✔
87
                *ret_pid = pid;
103,502✔
88
        return 0;
89
}
90

91
int parse_mode(const char *s, mode_t *ret) {
127,550✔
92
        unsigned m;
127,550✔
93
        int r;
127,550✔
94

95
        assert(s);
127,550✔
96

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

108
        if (ret)
127,534✔
109
                *ret = m;
127,534✔
110
        return 0;
111
}
112

113
int parse_ifindex(const char *s) {
158,244✔
114
        int ifi, r;
158,244✔
115

116
        assert(s);
158,244✔
117

118
        r = safe_atoi(s, &ifi);
158,244✔
119
        if (r < 0)
158,244✔
120
                return r;
158,244✔
121
        if (ifi <= 0)
35,499✔
122
                return -EINVAL;
2✔
123

124
        return ifi;
125
}
126

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

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

135
        if (u > UINT32_MAX)
183✔
136
                return -ERANGE;
137

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

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

152
        *ret = (uint32_t) u;
175✔
153
        return 0;
175✔
154
}
155

156
int parse_size(const char *t, uint64_t base, uint64_t *size) {
15,360✔
157

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

172
        struct table {
15,360✔
173
                const char *suffix;
174
                unsigned long long factor;
175
        };
176

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

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

199
        const struct table *table;
15,360✔
200
        const char *p;
15,360✔
201
        unsigned long long r = 0;
15,360✔
202
        unsigned n_entries, start_pos = 0;
15,360✔
203

204
        assert(t);
15,360✔
205
        assert(IN_SET(base, 1000, 1024));
15,360✔
206
        assert(size);
15,360✔
207

208
        if (base == 1000) {
15,360✔
209
                table = si;
210
                n_entries = ELEMENTSOF(si);
211
        } else {
212
                table = iec;
15,303✔
213
                n_entries = ELEMENTSOF(iec);
15,303✔
214
        }
215

216
        p = t;
15,360✔
217
        do {
15,415✔
218
                unsigned long long l, tmp;
15,415✔
219
                double frac = 0;
15,415✔
220
                char *e;
15,415✔
221
                unsigned i;
15,415✔
222

223
                p += strspn(p, WHITESPACE);
15,415✔
224

225
                errno = 0;
15,415✔
226
                l = strtoull(p, &e, 10);
15,415✔
227
                if (errno > 0)
15,415✔
228
                        return -errno;
55✔
229
                if (e == p)
15,413✔
230
                        return -EINVAL;
231
                if (*p == '-')
15,376✔
232
                        return -ERANGE;
233

234
                if (*e == '.') {
15,364✔
235
                        e++;
42✔
236

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

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

246
                                /* Ignore failure. E.g. 10.M is valid */
247
                                frac = l2;
38✔
248
                                for (; e < e2; e++)
84✔
249
                                        frac /= 10;
46✔
250
                        }
251
                }
252

253
                e += strspn(e, WHITESPACE);
15,364✔
254

255
                for (i = start_pos; i < n_entries; i++)
118,116✔
256
                        if (startswith(e, table[i].suffix))
118,114✔
257
                                break;
258

259
                if (i >= n_entries)
15,362✔
260
                        return -EINVAL;
261

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

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

269
                r += tmp;
15,360✔
270
                if ((unsigned long long) (uint64_t) r != r)
15,360✔
271
                        return -ERANGE;
272

273
                p = e + strlen(table[i].suffix);
15,360✔
274

275
                start_pos = i + 1;
15,360✔
276

277
        } while (*p);
15,360✔
278

279
        *size = r;
15,305✔
280

281
        return 0;
15,305✔
282
}
283

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

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

290
        uint64_t ss;
4✔
291

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

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

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

309
        assert(lower);
331✔
310
        assert(upper);
331✔
311

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

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

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

336
        *lower = l;
289✔
337
        *upper = u;
289✔
338
        return 0;
289✔
339
}
340

341
int parse_errno(const char *t) {
2,120✔
342
        int r, e;
2,120✔
343

344
        assert(t);
2,120✔
345

346
        r = errno_from_name(t);
2,120✔
347
        if (r > 0)
2,120✔
348
                return r;
2,120✔
349

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

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

358
        return e;
359
}
360

361
int parse_fd(const char *t) {
200,216✔
362
        int r, fd;
200,216✔
363

364
        assert(t);
200,216✔
365

366
        r = safe_atoi(t, &fd);
200,216✔
367
        if (r < 0)
200,216✔
368
                return r;
200,216✔
369

370
        if (fd < 0)
200,212✔
371
                return -EBADF;
2✔
372

373
        return fd;
374
}
375

376
static const char *mangle_base(const char *s, unsigned *base) {
6,690,115✔
377
        const char *k;
6,690,115✔
378

379
        assert(s);
6,690,115✔
380
        assert(base);
6,690,115✔
381

382
        /* Base already explicitly specified, then don't do anything. */
383
        if (SAFE_ATO_MASK_FLAGS(*base) != 0)
6,690,115✔
384
                return s;
6,690,115✔
385

386
        /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
387
        k = STARTSWITH_SET(s, "0b", "0B");
6,258,239✔
388
        if (k) {
6,258,239✔
389
                *base = 2 | (*base & SAFE_ATO_ALL_FLAGS);
4✔
390
                return k;
4✔
391
        }
392

393
        k = STARTSWITH_SET(s, "0o", "0O");
6,258,235✔
394
        if (k) {
6,258,235✔
395
                *base = 8 | (*base & SAFE_ATO_ALL_FLAGS);
4✔
396
                return k;
4✔
397
        }
398

399
        return s;
400
}
401

402
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
2,089,923✔
403
        char *x = NULL;
2,089,923✔
404
        unsigned long l;
2,089,923✔
405

406
        assert(s);
2,089,923✔
407
        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
2,089,923✔
408

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

414
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
2,089,923✔
415
            strchr(WHITESPACE, s[0]))
235,573✔
416
                return -EINVAL;
2,089,923✔
417

418
        s += strspn(s, WHITESPACE);
2,089,906✔
419

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

428
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
2,089,889✔
429
            s[0] == '0' && !streq(s, "0"))
234,643✔
430
                return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
431
                                 * notation and assumed-to-be-decimal integers with a leading zero. */
432

433
        s = mangle_base(s, &base);
2,089,869✔
434

435
        errno = 0;
2,089,869✔
436
        l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
2,089,869✔
437
                                                      * base is left */);
438
        if (errno > 0)
2,089,869✔
439
                return -errno;
2✔
440
        if (!x || x == s || *x != 0)
2,089,867✔
441
                return -EINVAL;
442
        if (l != 0 && s[0] == '-')
1,855,865✔
443
                return -ERANGE;
444
        if ((unsigned long) (unsigned) l != l)
1,759,330✔
445
                return -ERANGE;
446

447
        if (ret_u)
1,855,837✔
448
                *ret_u = (unsigned) l;
1,855,792✔
449

450
        return 0;
451
}
452

453
int safe_atou_bounded(const char *s, unsigned min, unsigned max, unsigned *ret) {
94✔
454
        unsigned v;
94✔
455
        int r;
94✔
456

457
        r = safe_atou(s, &v);
94✔
458
        if (r < 0)
94✔
459
                return r;
94✔
460

461
        if (v < min || v > max)
93✔
462
                return -ERANGE;
463

464
        *ret = v;
91✔
465
        return 0;
91✔
466
}
467

468
int safe_atoi(const char *s, int *ret_i) {
2,753,836✔
469
        unsigned base = 0;
2,753,836✔
470
        char *x = NULL;
2,753,836✔
471
        long l;
2,753,836✔
472

473
        assert(s);
2,753,836✔
474

475
        s += strspn(s, WHITESPACE);
2,753,836✔
476
        s = mangle_base(s, &base);
2,753,836✔
477

478
        errno = 0;
2,753,836✔
479
        l = strtol(s, &x, base);
2,753,836✔
480
        if (errno > 0)
2,753,836✔
481
                return -errno;
8✔
482
        if (!x || x == s || *x != 0)
2,753,828✔
483
                return -EINVAL;
484
        if ((long) (int) l != l)
2,616,231✔
485
                return -ERANGE;
486

487
        if (ret_i)
2,616,225✔
488
                *ret_i = (int) l;
2,616,225✔
489

490
        return 0;
491
}
492

493
int safe_atollu_full(const char *s, unsigned base, unsigned long long *ret_llu) {
1,846,361✔
494
        char *x = NULL;
1,846,361✔
495
        unsigned long long l;
1,846,361✔
496

497
        assert(s);
1,846,361✔
498
        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
1,846,361✔
499

500
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
1,846,361✔
UNCOV
501
            strchr(WHITESPACE, s[0]))
×
502
                return -EINVAL;
1,846,361✔
503

504
        s += strspn(s, WHITESPACE);
1,846,361✔
505

506
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
1,846,361✔
UNCOV
507
            IN_SET(s[0], '+', '-'))
×
508
                return -EINVAL;
509

510
        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
1,846,361✔
UNCOV
511
            s[0] == '0' && s[1] != 0)
×
512
                return -EINVAL;
513

514
        s = mangle_base(s, &base);
1,846,361✔
515

516
        errno = 0;
1,846,361✔
517
        l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
1,846,361✔
518
        if (errno > 0)
1,846,361✔
519
                return -errno;
3✔
520
        if (!x || x == s || *x != 0)
1,846,358✔
521
                return -EINVAL;
522
        if (l != 0 && s[0] == '-')
1,845,628✔
523
                return -ERANGE;
524

525
        if (ret_llu)
1,845,621✔
526
                *ret_llu = l;
1,845,621✔
527

528
        return 0;
529
}
530

531
int safe_atolli(const char *s, long long int *ret_lli) {
35✔
532
        unsigned base = 0;
35✔
533
        char *x = NULL;
35✔
534
        long long l;
35✔
535

536
        assert(s);
35✔
537

538
        s += strspn(s, WHITESPACE);
35✔
539
        s = mangle_base(s, &base);
35✔
540

541
        errno = 0;
35✔
542
        l = strtoll(s, &x, base);
35✔
543
        if (errno > 0)
35✔
544
                return -errno;
4✔
545
        if (!x || x == s || *x != 0)
31✔
546
                return -EINVAL;
547

548
        if (ret_lli)
23✔
549
                *ret_lli = l;
23✔
550

551
        return 0;
552
}
553

554
int safe_atou8_full(const char *s, unsigned base, uint8_t *ret) {
144,579✔
555
        unsigned u;
144,579✔
556
        int r;
144,579✔
557

558
        r = safe_atou_full(s, base, &u);
144,579✔
559
        if (r < 0)
144,579✔
560
                return r;
144,579✔
561
        if (u > UINT8_MAX)
144,413✔
562
                return -ERANGE;
563

564
        *ret = (uint8_t) u;
144,412✔
565
        return 0;
144,412✔
566
}
567

568
int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
4,090✔
569
        unsigned u;
4,090✔
570
        int r;
4,090✔
571

572
        r = safe_atou_full(s, base, &u);
4,090✔
573
        if (r < 0)
4,090✔
574
                return r;
4,090✔
575
        if (u > UINT16_MAX)
4,007✔
576
                return -ERANGE;
577

578
        *ret = (uint16_t) u;
4,000✔
579
        return 0;
4,000✔
580
}
581

582
int safe_atoi16(const char *s, int16_t *ret) {
14✔
583
        unsigned base = 0;
14✔
584
        char *x = NULL;
14✔
585
        long l;
14✔
586

587
        assert(s);
14✔
588

589
        s += strspn(s, WHITESPACE);
14✔
590
        s = mangle_base(s, &base);
14✔
591

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

601
        if (ret)
8✔
602
                *ret = (int16_t) l;
8✔
603

604
        return 0;
605
}
606

607
int safe_atod(const char *s, double *ret_d) {
12✔
608
        _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
24✔
609
        char *x = NULL;
12✔
610
        double d = 0;
12✔
611

612
        assert(s);
12✔
613

614
        loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
12✔
615
        if (loc == (locale_t) 0)
12✔
UNCOV
616
                return -errno;
×
617

618
        errno = 0;
12✔
619
        d = strtod_l(s, &x, loc);
12✔
620
        if (errno > 0)
12✔
UNCOV
621
                return -errno;
×
622
        if (!x || x == s || *x != 0)
12✔
623
                return -EINVAL;
624

625
        if (ret_d)
7✔
626
                *ret_d = (double) d;
7✔
627

628
        return 0;
629
}
630

631
int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
458✔
632
        unsigned val = 0;
458✔
633
        const char *s;
458✔
634

635
        s = *p;
458✔
636

637
        /* accept any number of digits, strtoull is limited to 19 */
638
        for (size_t i = 0; i < digits; i++, s++) {
2,704✔
639
                if (!ascii_isdigit(*s)) {
2,422✔
640
                        if (i == 0)
176✔
641
                                return -EINVAL;
642

643
                        /* too few digits, pad with 0 */
644
                        for (; i < digits; i++)
678✔
645
                                val *= 10;
502✔
646

647
                        break;
648
                }
649

650
                val *= 10;
2,246✔
651
                val += *s - '0';
2,246✔
652
        }
653

654
        /* maybe round up */
655
        if (*s >= '5' && *s <= '9')
458✔
656
                val++;
4✔
657

658
        s += strspn(s, DIGITS);
458✔
659

660
        *p = s;
458✔
661
        *res = val;
458✔
662

663
        return 0;
458✔
664
}
665

666
int parse_nice(const char *p, int *ret) {
369✔
667
        int n, r;
369✔
668

669
        r = safe_atoi(p, &n);
369✔
670
        if (r < 0)
369✔
671
                return r;
369✔
672

673
        if (!nice_is_valid(n))
363✔
674
                return -ERANGE;
675

676
        *ret = n;
357✔
677
        return 0;
357✔
678
}
679

680
int parse_ip_port(const char *s, uint16_t *ret) {
292✔
681
        uint16_t l;
292✔
682
        int r;
292✔
683

684
        r = safe_atou16_full(s, SAFE_ATO_REFUSE_LEADING_WHITESPACE, &l);
292✔
685
        if (r < 0)
292✔
686
                return r;
292✔
687

688
        if (l == 0)
219✔
689
                return -EINVAL;
690

691
        *ret = (uint16_t) l;
214✔
692

693
        return 0;
214✔
694
}
695

696
int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high, bool allow_zero) {
32✔
697
        unsigned l, h;
32✔
698
        int r;
32✔
699

700
        r = parse_range(s, &l, &h);
32✔
701
        if (r < 0)
32✔
702
                return r;
32✔
703

704
        if (l > 65535 || h > 65535)
22✔
705
                return -EINVAL;
706

707
        if (!allow_zero && (l == 0 || h == 0))
20✔
708
                return -EINVAL;
709

710
        if (h < l)
20✔
711
                return -EINVAL;
712

713
        *low = l;
19✔
714
        *high = h;
19✔
715

716
        return 0;
19✔
717
}
718

719
int parse_oom_score_adjust(const char *s, int *ret) {
918✔
720
        int r, v;
918✔
721

722
        assert(s);
918✔
723
        assert(ret);
918✔
724

725
        r = safe_atoi(s, &v);
918✔
726
        if (r < 0)
918✔
727
                return r;
918✔
728

729
        if (!oom_score_adjust_is_valid(v))
916✔
730
                return -ERANGE;
731

732
        *ret = v;
916✔
733
        return 0;
916✔
734
}
735

736
int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret) {
532✔
737
        assert(ret);
532✔
738

739
        if (i >= (~0UL << LOADAVG_PRECISION_BITS))
532✔
740
                return -ERANGE;
741

742
        i = i << LOADAVG_PRECISION_BITS;
531✔
743
        f = DIV_ROUND_UP((f << LOADAVG_PRECISION_BITS), 100);
531✔
744

745
        if (f >= LOADAVG_FIXED_POINT_1_0)
531✔
746
                return -ERANGE;
747

748
        *ret = i | f;
529✔
749
        return 0;
529✔
750
}
751

752
int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
509✔
753
        const char *d, *f_str, *i_str;
509✔
754
        unsigned long i, f;
509✔
755
        int r;
509✔
756

757
        assert(s);
509✔
758
        assert(ret);
509✔
759

760
        d = strchr(s, '.');
509✔
761
        if (!d)
509✔
762
                return -EINVAL;
509✔
763

764
        i_str = strndupa_safe(s, d - s);
506✔
765
        f_str = d + 1;
506✔
766

767
        r = safe_atolu_full(i_str, 10, &i);
506✔
768
        if (r < 0)
506✔
769
                return r;
770

771
        r = safe_atolu_full(f_str, 10, &f);
504✔
772
        if (r < 0)
504✔
773
                return r;
774

775
        return store_loadavg_fixed_point(i, f, ret);
502✔
776
}
777

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

784
        if (strlen(id) >= NFT_NAME_MAXLEN)
100✔
785
                return false;
786

787
        if (!ascii_isalpha(id[0]))
99✔
788
                return false;
789

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