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

systemd / systemd / 15986406979

30 Jun 2025 05:03PM UTC coverage: 72.045% (-0.09%) from 72.13%
15986406979

push

github

bluca
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options

ephemeral/ephemeral-import are described as possible '--mutable' options but
not present in the list. Note, "systemd-sysext --help" lists them correctly.

300514 of 417119 relevant lines covered (72.05%)

708586.28 hits per line

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

88.46
/src/shared/serialize.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fcntl.h>
4
#include <unistd.h>
5

6
#include "sd-id128.h"
7

8
#include "alloc-util.h"
9
#include "env-util.h"
10
#include "escape.h"
11
#include "extract-word.h"
12
#include "fd-util.h"
13
#include "fdset.h"
14
#include "fileio.h"
15
#include "format-util.h"
16
#include "hexdecoct.h"
17
#include "image-policy.h"
18
#include "log.h"
19
#include "memfd-util.h"
20
#include "missing_mman.h"
21
#include "parse-util.h"
22
#include "pidref.h"
23
#include "ratelimit.h"
24
#include "serialize.h"
25
#include "set.h"
26
#include "string-util.h"
27
#include "strv.h"
28
#include "time-util.h"
29

30
int serialize_item(FILE *f, const char *key, const char *value) {
459,768✔
31
        assert(f);
459,768✔
32
        assert(key);
459,768✔
33

34
        if (!value)
459,768✔
35
                return 0;
36

37
        /* Make sure that anything we serialize we can also read back again with read_line() with a maximum line size
38
         * of LONG_LINE_MAX. This is a safety net only. All code calling us should filter this out earlier anyway. */
39
        if (strlen(key) + 1 + strlen(value) + 1 > LONG_LINE_MAX)
402,078✔
40
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Attempted to serialize overly long item '%s', refusing.", key);
7✔
41

42
        fputs(key, f);
402,071✔
43
        fputc('=', f);
402,071✔
44
        fputs(value, f);
402,071✔
45
        fputc('\n', f);
402,071✔
46

47
        return 1;
402,071✔
48
}
49

50
int serialize_item_escaped(FILE *f, const char *key, const char *value) {
39,430✔
51
        _cleanup_free_ char *c = NULL;
39,430✔
52

53
        assert(f);
39,430✔
54
        assert(key);
39,430✔
55

56
        if (!value)
39,430✔
57
                return 0;
58

59
        c = xescape(value, " ");
26,825✔
60
        if (!c)
26,825✔
61
                return log_oom();
×
62

63
        return serialize_item(f, key, c);
26,825✔
64
}
65

66
int serialize_item_format(FILE *f, const char *key, const char *format, ...) {
308,605✔
67
        _cleanup_free_ char *allocated = NULL;
308,605✔
68
        char buf[256]; /* Something reasonably short that fits nicely on any stack (i.e. is considerably less
308,605✔
69
                        * than LONG_LINE_MAX (1MiB!) */
70
        const char *b;
308,605✔
71
        va_list ap;
308,605✔
72
        int k;
308,605✔
73

74
        assert(f);
308,605✔
75
        assert(key);
308,605✔
76
        assert(format);
308,605✔
77

78
        /* First, let's try to format this into a stack buffer */
79
        va_start(ap, format);
308,605✔
80
        k = vsnprintf(buf, sizeof(buf), format, ap);
308,605✔
81
        va_end(ap);
308,605✔
82

83
        if (k < 0)
308,605✔
84
                return log_warning_errno(errno, "Failed to serialize item '%s', ignoring: %m", key);
×
85
        if (strlen(key) + 1 + k + 1 > LONG_LINE_MAX) /* See above */
308,605✔
86
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Attempted to serialize overly long item '%s', refusing.", key);
×
87

88
        if ((size_t) k < sizeof(buf))
308,605✔
89
                b = buf; /* Yay, it fit! */
90
        else {
91
                /* So the string didn't fit in the short buffer above, but was not above our total limit,
92
                 * hence let's format it via dynamic memory */
93

94
                va_start(ap, format);
×
95
                k = vasprintf(&allocated, format, ap);
×
96
                va_end(ap);
×
97

98
                if (k < 0)
×
99
                        return log_warning_errno(errno, "Failed to serialize item '%s', ignoring: %m", key);
×
100

101
                b = allocated;
×
102
        }
103

104
        fputs(key, f);
308,605✔
105
        fputc('=', f);
308,605✔
106
        fputs(b, f);
308,605✔
107
        fputc('\n', f);
308,605✔
108

109
        return 1;
110
}
111

112
int serialize_fd(FILE *f, FDSet *fds, const char *key, int fd) {
45,122✔
113
        int copy;
45,122✔
114

115
        assert(f);
45,122✔
116
        assert(fds);
45,122✔
117
        assert(key);
45,122✔
118

119
        if (fd < 0)
45,122✔
120
                return 0;
121

122
        copy = fdset_put_dup(fds, fd);
6,736✔
123
        if (copy < 0)
6,736✔
124
                return log_error_errno(copy, "Failed to add file descriptor to serialization set: %m");
×
125

126
        return serialize_item_format(f, key, "%i", copy);
6,736✔
127
}
128

129
int serialize_fd_many(FILE *f, FDSet *fds, const char *key, const int fd_array[], size_t n_fd_array) {
580✔
130
        _cleanup_free_ char *t = NULL;
580✔
131

132
        assert(f);
580✔
133

134
        if (n_fd_array == 0)
580✔
135
                return 0;
136

137
        assert(fd_array);
580✔
138

139
        for (size_t i = 0; i < n_fd_array; i++) {
1,557✔
140
                int copy;
977✔
141

142
                if (fd_array[i] < 0)
977✔
143
                        return -EBADF;
144

145
                copy = fdset_put_dup(fds, fd_array[i]);
977✔
146
                if (copy < 0)
977✔
147
                        return log_error_errno(copy, "Failed to add file descriptor to serialization set: %m");
×
148

149
                if (strextendf_with_separator(&t, " ", "%i", copy) < 0)
977✔
150
                        return log_oom();
×
151
        }
152

153
        return serialize_item(f, key, t);
580✔
154
}
155

156
int serialize_usec(FILE *f, const char *key, usec_t usec) {
22,039✔
157
        assert(f);
22,039✔
158
        assert(key);
22,039✔
159

160
        if (usec == USEC_INFINITY)
22,039✔
161
                return 0;
162

163
        return serialize_item_format(f, key, USEC_FMT, usec);
5,009✔
164
}
165

166
int serialize_dual_timestamp(FILE *f, const char *name, const dual_timestamp *t) {
142,975✔
167
        assert(f);
142,975✔
168
        assert(name);
142,975✔
169
        assert(t);
142,975✔
170

171
        if (!dual_timestamp_is_set(t))
142,975✔
172
                return 0;
173

174
        return serialize_item_format(f, name, USEC_FMT " " USEC_FMT, t->realtime, t->monotonic);
56,637✔
175
}
176

177
int serialize_strv(FILE *f, const char *key, char * const *l) {
41,525✔
178
        int ret = 0, r;
41,525✔
179

180
        /* Returns the first error, or positive if anything was serialized, 0 otherwise. */
181

182
        assert(f);
41,525✔
183
        assert(key);
41,525✔
184

185
        STRV_FOREACH(i, l) {
66,914✔
186
                r = serialize_item_escaped(f, key, *i);
25,389✔
187
                if ((ret >= 0 && r < 0) ||
25,389✔
188
                    (ret == 0 && r > 0))
25,388✔
189
                        ret = r;
6,396✔
190
        }
191

192
        return ret;
41,525✔
193
}
194

195
int serialize_id128(FILE *f, const char *key, sd_id128_t id) {
18,251✔
196
        assert(f);
18,251✔
197
        assert(key);
18,251✔
198

199
        if (sd_id128_is_null(id))
18,251✔
200
                return 0;
8,266✔
201

202
        return serialize_item_format(f, key, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id));
9,985✔
203
}
204

205
int serialize_pidref(FILE *f, FDSet *fds, const char *key, PidRef *pidref) {
13,577✔
206
        int r;
13,577✔
207

208
        assert(f);
13,577✔
209
        assert(fds);
13,577✔
210

211
        if (!pidref_is_set(pidref))
13,577✔
212
                return 0;
213

214
        /* We always serialize the pid separately, to keep downgrades mostly working (older versions will
215
         * deserialize the pid and silently fail to deserialize the pidfd). If we also have a pidfd, we
216
         * serialize both the pid and pidfd, so that we can construct the exact same pidref after
217
         * deserialization (this doesn't work with only the pidfd, as we can't retrieve the original pid
218
         * from the pidfd anymore if the process is reaped). */
219

220
        if (pidref->fd >= 0) {
795✔
221
                int copy = fdset_put_dup(fds, pidref->fd);
795✔
222
                if (copy < 0)
795✔
223
                        return log_error_errno(copy, "Failed to add file descriptor to serialization set: %m");
×
224

225
                r = serialize_item_format(f, key, "@%i:" PID_FMT, copy, pidref->pid);
795✔
226
                if (r < 0)
795✔
227
                        return r;
228
        }
229

230
        return serialize_item_format(f, key, PID_FMT, pidref->pid);
795✔
231
}
232

233
int serialize_ratelimit(FILE *f, const char *key, const RateLimit *rl) {
39,117✔
234
        assert(rl);
39,117✔
235

236
        return serialize_item_format(f, key,
78,234✔
237
                                     USEC_FMT " " USEC_FMT " %u %u",
238
                                     rl->begin,
39,117✔
239
                                     rl->interval,
39,117✔
240
                                     rl->num,
39,117✔
241
                                     rl->burst);
39,117✔
242
}
243

244
int serialize_item_hexmem(FILE *f, const char *key, const void *p, size_t l) {
2,236✔
245
        _cleanup_free_ char *encoded = NULL;
2,236✔
246
        int r;
2,236✔
247

248
        assert(f);
2,236✔
249
        assert(key);
2,236✔
250

251
        if (!p && l > 0)
2,236✔
252
                return -EINVAL;
253

254
        if (l == 0)
2,236✔
255
                return 0;
256

257
        encoded = hexmem(p, l);
1✔
258
        if (!encoded)
1✔
259
                return log_oom_debug();
×
260

261
        r = serialize_item(f, key, encoded);
1✔
262
        if (r < 0)
1✔
263
                return r;
×
264

265
        return 1;
266
}
267

268
int serialize_item_base64mem(FILE *f, const char *key, const void *p, size_t l) {
4,470✔
269
        _cleanup_free_ char *encoded = NULL;
4,470✔
270
        ssize_t len;
4,470✔
271
        int r;
4,470✔
272

273
        assert(f);
4,470✔
274
        assert(key);
4,470✔
275

276
        if (!p && l > 0)
4,470✔
277
                return -EINVAL;
278

279
        if (l == 0)
4,470✔
280
                return 0;
281

282
        len = base64mem(p, l, &encoded);
1✔
283
        if (len <= 0)
1✔
284
                return log_oom_debug();
×
285

286
        r = serialize_item(f, key, encoded);
1✔
287
        if (r < 0)
1✔
288
                return r;
×
289

290
        return 1;
291
}
292

293
int serialize_string_set(FILE *f, const char *key, const Set *s) {
4,470✔
294
        int r;
4,470✔
295

296
        assert(f);
4,470✔
297
        assert(key);
4,470✔
298

299
        if (set_isempty(s))
4,470✔
300
                return 0;
4,470✔
301

302
        /* Serialize as individual items, as each element might contain separators and escapes */
303

304
        const char *e;
1✔
305
        SET_FOREACH(e, s) {
3✔
306
                r = serialize_item(f, key, e);
2✔
307
                if (r < 0)
2✔
308
                        return r;
×
309
        }
310

311
        return 1;
1✔
312
}
313

314
int serialize_image_policy(FILE *f, const char *key, const ImagePolicy *p) {
6,702✔
315
        _cleanup_free_ char *policy = NULL;
6,702✔
316
        int r;
6,702✔
317

318
        assert(f);
6,702✔
319
        assert(key);
6,702✔
320

321
        if (!p)
6,702✔
322
                return 0;
323

324
        r = image_policy_to_string(p, /* simplify= */ false, &policy);
×
325
        if (r < 0)
×
326
                return r;
327

328
        r = serialize_item(f, key, policy);
×
329
        if (r < 0)
×
330
                return r;
×
331

332
        return 1;
333
}
334

335
int serialize_bool(FILE *f, const char *key, bool b) {
192,232✔
336
        return serialize_item(f, key, yes_no(b));
355,974✔
337
}
338

339
int serialize_bool_elide(FILE *f, const char *key, bool b) {
111,758✔
340
        return b ? serialize_item(f, key, yes_no(b)) : 0;
111,758✔
341
}
342

343
int deserialize_read_line(FILE *f, char **ret) {
2,235,428✔
344
        _cleanup_free_ char *line = NULL;
2,235,428✔
345
        int r;
2,235,428✔
346

347
        assert(f);
2,235,428✔
348
        assert(ret);
2,235,428✔
349

350
        r = read_stripped_line(f, LONG_LINE_MAX, &line);
2,235,428✔
351
        if (r < 0)
2,235,428✔
352
                return log_error_errno(r, "Failed to read serialization line: %m");
×
353
        if (r == 0) { /* eof */
2,235,428✔
354
                *ret = NULL;
30✔
355
                return 0;
30✔
356
        }
357

358
        if (isempty(line)) { /* End marker */
2,235,398✔
359
                *ret = NULL;
72,812✔
360
                return 0;
72,812✔
361
        }
362

363
        *ret = TAKE_PTR(line);
2,162,586✔
364
        return 1;
2,162,586✔
365
}
366

367
int deserialize_fd(FDSet *fds, const char *value) {
42,849✔
368
        _cleanup_close_ int our_fd = -EBADF;
42,849✔
369
        int parsed_fd;
42,849✔
370

371
        assert(value);
42,849✔
372

373
        parsed_fd = parse_fd(value);
42,849✔
374
        if (parsed_fd < 0)
42,849✔
375
                return log_debug_errno(parsed_fd, "Failed to parse file descriptor serialization: %s", value);
×
376

377
        our_fd = fdset_remove(fds, parsed_fd); /* Take possession of the fd */
42,849✔
378
        if (our_fd < 0)
42,849✔
379
                return log_debug_errno(our_fd, "Failed to acquire fd from serialization fds: %m");
×
380

381
        return TAKE_FD(our_fd);
382
}
383

384
int deserialize_fd_many(FDSet *fds, const char *value, size_t n, int *ret) {
2,632✔
385
        int r, *fd_array = NULL;
2,632✔
386
        size_t m = 0;
2,632✔
387

388
        assert(value);
2,632✔
389

390
        fd_array = new(int, n);
2,632✔
391
        if (!fd_array)
2,632✔
392
                return -ENOMEM;
2,632✔
393

394
        CLEANUP_ARRAY(fd_array, m, close_many_and_free);
5,264✔
395

396
        for (;;) {
12,510✔
397
                _cleanup_free_ char *w = NULL;
4,939✔
398
                int fd;
7,571✔
399

400
                r = extract_first_word(&value, &w, NULL, 0);
7,571✔
401
                if (r < 0)
7,571✔
402
                        return r;
403
                if (r == 0) {
7,571✔
404
                        if (m < n) /* Too few */
2,632✔
405
                                return -EINVAL;
406

407
                        break;
2,632✔
408
                }
409

410
                if (m >= n) /* Too many */
4,939✔
411
                        return -EINVAL;
412

413
                fd = deserialize_fd(fds, w);
4,939✔
414
                if (fd < 0)
4,939✔
415
                        return fd;
416

417
                fd_array[m++] = fd;
4,939✔
418
        }
419

420
        memcpy(ret, fd_array, m * sizeof(int));
2,632✔
421
        fd_array = mfree(fd_array);
2,632✔
422

423
        return 0;
2,632✔
424
}
425

426
int deserialize_strv(const char *value, char ***l) {
93,482✔
427
        ssize_t unescaped_len;
93,482✔
428
        char *unescaped;
93,482✔
429

430
        assert(l);
93,482✔
431
        assert(value);
93,482✔
432

433
        unescaped_len = cunescape(value, 0, &unescaped);
93,482✔
434
        if (unescaped_len < 0)
93,482✔
435
                return unescaped_len;
×
436

437
        return strv_consume(l, unescaped);
93,482✔
438
}
439

440
int deserialize_usec(const char *value, usec_t *ret) {
16,066✔
441
        int r;
16,066✔
442

443
        assert(value);
16,066✔
444
        assert(ret);
16,066✔
445

446
        r = safe_atou64(value, ret);
16,066✔
447
        if (r < 0)
16,066✔
448
                return log_debug_errno(r, "Failed to parse usec value \"%s\": %m", value);
×
449

450
        return 0;
451
}
452

453
int deserialize_dual_timestamp(const char *value, dual_timestamp *ret) {
43,340✔
454
        uint64_t a, b;
43,340✔
455
        int r, pos;
43,340✔
456

457
        assert(value);
43,340✔
458
        assert(ret);
43,340✔
459

460
        pos = strspn(value, WHITESPACE);
43,340✔
461
        if (value[pos] == '-')
43,340✔
462
                return -EINVAL;
43,340✔
463
        pos += strspn(value + pos, DIGITS);
43,339✔
464
        pos += strspn(value + pos, WHITESPACE);
43,339✔
465
        if (value[pos] == '-')
43,339✔
466
                return -EINVAL;
467

468
        r = sscanf(value, "%" PRIu64 "%" PRIu64 "%n", &a, &b, &pos);
43,338✔
469
        if (r != 2)
43,338✔
470
                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
1✔
471
                                       "Failed to parse dual timestamp value \"%s\".",
472
                                       value);
473

474
        if (value[pos] != '\0')
43,337✔
475
                /* trailing garbage */
476
                return -EINVAL;
477

478
        *ret = (dual_timestamp) {
43,336✔
479
                .realtime = a,
480
                .monotonic = b,
481
        };
482

483
        return 0;
43,336✔
484
}
485

486
int deserialize_environment(const char *value, char ***list) {
553✔
487
        _cleanup_free_ char *unescaped = NULL;
553✔
488
        ssize_t l;
553✔
489
        int r;
553✔
490

491
        assert(value);
553✔
492
        assert(list);
553✔
493

494
        /* Changes the *environment strv inline. */
495

496
        l = cunescape(value, 0, &unescaped);
553✔
497
        if (l < 0)
553✔
498
                return log_error_errno(l, "Failed to unescape: %m");
2✔
499

500
        r = strv_env_replace_consume(list, TAKE_PTR(unescaped));
551✔
501
        if (r < 0)
551✔
502
                return log_error_errno(r, "Failed to append environment variable: %m");
×
503

504
        return 0;
505
}
506

507
int deserialize_pidref(FDSet *fds, const char *value, PidRef *ret) {
659✔
508
        const char *e;
659✔
509
        int r;
659✔
510

511
        assert(value);
659✔
512
        assert(ret);
659✔
513

514
        e = startswith(value, "@");
659✔
515
        if (e) {
659✔
516
                _cleanup_free_ char *fdstr = NULL, *pidstr = NULL;
657✔
517
                _cleanup_close_ int fd = -EBADF;
657✔
518

519
                r = extract_many_words(&e, ":", /* flags = */ 0, &fdstr, &pidstr);
657✔
520
                if (r < 0)
657✔
521
                        return log_debug_errno(r, "Failed to deserialize pidref '%s': %m", e);
×
522
                if (r == 0)
657✔
523
                        return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot deserialize pidref from empty string.");
×
524

525
                assert(r <= 2);
657✔
526

527
                fd = deserialize_fd(fds, fdstr);
657✔
528
                if (fd < 0)
657✔
529
                        return fd;
530

531
                /* The serialization format changed after 255.4. In systemd <= 255.4 only pidfd is
532
                 * serialized, but that causes problems when reconstructing pidref (see serialize_pidref for
533
                 * details). After 255.4 the pid is serialized as well even if we have a pidfd, but we still
534
                 * need to support older format as we might be upgrading from a version that still uses the
535
                 * old format. */
536
                if (pidstr) {
657✔
537
                        pid_t pid;
657✔
538

539
                        r = parse_pid(pidstr, &pid);
657✔
540
                        if (r < 0)
657✔
541
                                return log_debug_errno(r, "Failed to parse PID: %s", pidstr);
×
542

543
                        *ret = (PidRef) {
657✔
544
                                .pid = pid,
545
                                .fd = TAKE_FD(fd),
657✔
546
                        };
547
                } else
548
                        r = pidref_set_pidfd_consume(ret, TAKE_FD(fd));
×
549
        } else {
550
                pid_t pid;
2✔
551

552
                r = parse_pid(value, &pid);
2✔
553
                if (r < 0)
2✔
554
                        return log_debug_errno(r, "Failed to parse PID: %s", value);
×
555

556
                r = pidref_set_pid(ret, pid);
2✔
557
        }
558
        if (r < 0)
659✔
559
                return log_debug_errno(r, "Failed to initialize pidref: %m");
×
560

561
        return 0;
562
}
563

564
void deserialize_ratelimit(RateLimit *rl, const char *name, const char *value) {
30,316✔
565
        usec_t begin, interval;
30,316✔
566
        unsigned num, burst;
30,316✔
567

568
        assert(rl);
30,316✔
569
        assert(name);
30,316✔
570
        assert(value);
30,316✔
571

572
        if (sscanf(value, USEC_FMT " " USEC_FMT " %u %u", &begin, &interval, &num, &burst) != 4)
30,316✔
573
                return log_notice("Failed to parse %s, ignoring: %s", name, value);
×
574

575
        /* Preserve the counter only if the configuration didn't change. */
576
        rl->num = (interval == rl->interval && burst == rl->burst) ? num : 0;
30,316✔
577
        rl->begin = begin;
30,316✔
578
}
579

580
int open_serialization_fd(const char *ident) {
4,330✔
581
        assert(ident);
4,330✔
582

583
        int fd = memfd_new_full(ident, MFD_ALLOW_SEALING);
4,330✔
584
        if (fd < 0)
4,330✔
585
                return fd;
586

587
        log_debug("Serializing %s to memfd.", ident);
4,330✔
588
        return fd;
589
}
590

591
int open_serialization_file(const char *ident, FILE **ret) {
2,364✔
592
        _cleanup_fclose_ FILE *f = NULL;
2,364✔
593
        _cleanup_close_ int fd;
2,364✔
594

595
        assert(ret);
2,364✔
596

597
        fd = open_serialization_fd(ident);
2,364✔
598
        if (fd < 0)
2,364✔
599
                return fd;
600

601
        f = take_fdopen(&fd, "w+");
2,364✔
602
        if (!f)
2,364✔
603
                return -errno;
×
604

605
        *ret = TAKE_PTR(f);
2,364✔
606
        return 0;
2,364✔
607
}
608

609
int finish_serialization_fd(int fd) {
1,966✔
610
        assert(fd >= 0);
1,966✔
611

612
        if (lseek(fd, 0, SEEK_SET) < 0)
1,966✔
613
                return -errno;
×
614

615
        return memfd_set_sealed(fd);
1,966✔
616
}
617

618
int finish_serialization_file(FILE *f) {
2,364✔
619
        int r;
2,364✔
620

621
        assert(f);
2,364✔
622

623
        r = fflush_and_check(f);
2,364✔
624
        if (r < 0)
2,364✔
625
                return r;
626

627
        if (fseeko(f, 0, SEEK_SET) < 0)
2,364✔
628
                return -errno;
×
629

630
        int fd = fileno(f);
2,364✔
631
        if (fd < 0)
2,364✔
632
                return -EBADF;
633

634
        return memfd_set_sealed(fd);
2,364✔
635
}
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