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

systemd / systemd / 22695774202

05 Mar 2026 12:03AM UTC coverage: 72.313% (-0.3%) from 72.603%
22695774202

push

github

YHNdnzj
hwdb/60-tpm2: correct prefix in comment (tpm -> tpm2)

Follow-up for f2eed3fa2

314964 of 435555 relevant lines covered (72.31%)

1184639.96 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 "parse-util.h"
21
#include "pidref.h"
22
#include "ratelimit.h"
23
#include "serialize.h"
24
#include "set.h"
25
#include "string-util.h"
26
#include "strv.h"
27
#include "time-util.h"
28

29
int serialize_item(FILE *f, const char *key, const char *value) {
567,837✔
30
        assert(f);
567,837✔
31
        assert(key);
567,837✔
32

33
        if (!value)
567,837✔
34
                return 0;
35

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

41
        fputs(key, f);
499,859✔
42
        fputc('=', f);
499,859✔
43
        fputs(value, f);
499,859✔
44
        fputc('\n', f);
499,859✔
45

46
        return 1;
499,859✔
47
}
48

49
int serialize_item_escaped(FILE *f, const char *key, const char *value) {
44,849✔
50
        _cleanup_free_ char *c = NULL;
44,849✔
51

52
        assert(f);
44,849✔
53
        assert(key);
44,849✔
54

55
        if (!value)
44,849✔
56
                return 0;
57

58
        c = xescape(value, " ");
28,790✔
59
        if (!c)
28,790✔
60
                return log_oom();
×
61

62
        return serialize_item(f, key, c);
28,790✔
63
}
64

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

73
        assert(f);
364,912✔
74
        assert(key);
364,912✔
75
        assert(format);
364,912✔
76

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

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

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

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

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

100
                b = allocated;
×
101
        }
102

103
        fputs(key, f);
364,912✔
104
        fputc('=', f);
364,912✔
105
        fputs(b, f);
364,912✔
106
        fputc('\n', f);
364,912✔
107

108
        return 1;
109
}
110

111
int serialize_fd(FILE *f, FDSet *fds, const char *key, int fd) {
57,774✔
112
        int copy;
57,774✔
113

114
        assert(f);
57,774✔
115
        assert(fds);
57,774✔
116
        assert(key);
57,774✔
117

118
        if (fd < 0)
57,774✔
119
                return 0;
120

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

125
        return serialize_item_format(f, key, "%i", copy);
8,000✔
126
}
127

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

131
        assert(f);
788✔
132

133
        if (n_fd_array == 0)
788✔
134
                return 0;
135

136
        assert(fd_array);
788✔
137

138
        for (size_t i = 0; i < n_fd_array; i++) {
2,117✔
139
                int copy;
1,329✔
140

141
                if (fd_array[i] < 0)
1,329✔
142
                        return -EBADF;
143

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

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

152
        return serialize_item(f, key, t);
788✔
153
}
154

155
int serialize_usec(FILE *f, const char *key, usec_t usec) {
23,320✔
156
        assert(f);
23,320✔
157
        assert(key);
23,320✔
158

159
        if (usec == USEC_INFINITY)
23,320✔
160
                return 0;
161

162
        return serialize_item_format(f, key, USEC_FMT, usec);
5,285✔
163
}
164

165
int serialize_dual_timestamp(FILE *f, const char *key, const dual_timestamp *t) {
184,646✔
166
        assert(f);
184,646✔
167
        assert(key);
184,646✔
168
        assert(t);
184,646✔
169

170
        if (!dual_timestamp_is_set(t))
184,646✔
171
                return 0;
172

173
        return serialize_item_format(f, key, USEC_FMT " " USEC_FMT, t->realtime, t->monotonic);
75,993✔
174
}
175

176
int serialize_strv(FILE *f, const char *key, char * const *l) {
44,395✔
177
        int ret = 0, r;
44,395✔
178

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

181
        assert(f);
44,395✔
182
        assert(key);
44,395✔
183

184
        STRV_FOREACH(i, l) {
71,736✔
185
                r = serialize_item_escaped(f, key, *i);
27,341✔
186
                if ((ret >= 0 && r < 0) ||
27,341✔
187
                    (ret == 0 && r > 0))
27,340✔
188
                        ret = r;
7,180✔
189
        }
190

191
        return ret;
44,395✔
192
}
193

194
int serialize_id128(FILE *f, const char *key, sd_id128_t id) {
24,115✔
195
        assert(f);
24,115✔
196
        assert(key);
24,115✔
197

198
        if (sd_id128_is_null(id))
24,115✔
199
                return 0;
8,588✔
200

201
        return serialize_item_format(f, key, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id));
15,527✔
202
}
203

204
int serialize_pidref(FILE *f, FDSet *fds, const char *key, PidRef *pidref) {
15,257✔
205
        int r;
15,257✔
206

207
        assert(f);
15,257✔
208
        assert(fds);
15,257✔
209

210
        if (!pidref_is_set(pidref))
15,257✔
211
                return 0;
212

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

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

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

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

232
int serialize_ratelimit(FILE *f, const char *key, const RateLimit *rl) {
51,697✔
233
        assert(rl);
51,697✔
234

235
        return serialize_item_format(f, key,
103,394✔
236
                                     USEC_FMT " " USEC_FMT " %u %u",
237
                                     rl->begin,
51,697✔
238
                                     rl->interval,
51,697✔
239
                                     rl->num,
51,697✔
240
                                     rl->burst);
51,697✔
241
}
242

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

247
        assert(f);
2,494✔
248
        assert(key);
2,494✔
249

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

253
        if (l == 0)
2,494✔
254
                return 0;
255

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

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

264
        return 1;
265
}
266

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

272
        assert(f);
2,494✔
273
        assert(key);
2,494✔
274

275
        if (!p && l > 0)
2,494✔
276
                return -EINVAL;
277

278
        if (l == 0)
2,494✔
279
                return 0;
280

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

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

289
        return 1;
290
}
291

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

295
        assert(f);
4,986✔
296
        assert(key);
4,986✔
297

298
        if (set_isempty(s))
4,986✔
299
                return 0;
4,986✔
300

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

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

310
        return 1;
1✔
311
}
312

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

317
        assert(f);
7,476✔
318
        assert(key);
7,476✔
319

320
        if (!p)
7,476✔
321
                return 0;
322

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

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

331
        return 1;
332
}
333

334
int serialize_bool(FILE *f, const char *key, bool b) {
242,442✔
335
        return serialize_item(f, key, yes_no(b));
453,234✔
336
}
337

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

342
int deserialize_read_line(FILE *f, char **ret) {
1,916,321✔
343
        _cleanup_free_ char *line = NULL;
1,916,321✔
344
        int r;
1,916,321✔
345

346
        assert(f);
1,916,321✔
347
        assert(ret);
1,916,321✔
348

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

357
        if (isempty(line)) { /* End marker */
1,916,290✔
358
                *ret = NULL;
69,879✔
359
                return 0;
69,879✔
360
        }
361

362
        *ret = TAKE_PTR(line);
1,846,411✔
363
        return 1;
1,846,411✔
364
}
365

366
int deserialize_fd(FDSet *fds, const char *value) {
38,413✔
367
        _cleanup_close_ int our_fd = -EBADF;
38,413✔
368
        int parsed_fd;
38,413✔
369

370
        assert(value);
38,413✔
371

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

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

380
        return TAKE_FD(our_fd);
381
}
382

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

387
        assert(value);
2,086✔
388

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

393
        CLEANUP_ARRAY(fd_array, m, close_many_and_free);
4,172✔
394

395
        for (;;) {
12,002✔
396
                _cleanup_free_ char *w = NULL;
4,958✔
397
                int fd;
7,044✔
398

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

406
                        break;
2,086✔
407
                }
408

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

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

416
                fd_array[m++] = fd;
4,958✔
417
        }
418

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

422
        return 0;
2,086✔
423
}
424

425
int deserialize_strv(const char *value, char ***l) {
83,327✔
426
        ssize_t unescaped_len;
83,327✔
427
        char *unescaped;
83,327✔
428

429
        assert(l);
83,327✔
430
        assert(value);
83,327✔
431

432
        unescaped_len = cunescape(value, 0, &unescaped);
83,327✔
433
        if (unescaped_len < 0)
83,327✔
434
                return unescaped_len;
×
435

436
        return strv_consume(l, unescaped);
83,327✔
437
}
438

439
int deserialize_usec(const char *value, usec_t *ret) {
13,694✔
440
        int r;
13,694✔
441

442
        assert(value);
13,694✔
443
        assert(ret);
13,694✔
444

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

449
        return 0;
450
}
451

452
int deserialize_dual_timestamp(const char *value, dual_timestamp *ret) {
59,465✔
453
        uint64_t a, b;
59,465✔
454
        int r, pos;
59,465✔
455

456
        assert(value);
59,465✔
457
        assert(ret);
59,465✔
458

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

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

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

477
        *ret = (dual_timestamp) {
59,461✔
478
                .realtime = a,
479
                .monotonic = b,
480
        };
481

482
        return 0;
59,461✔
483
}
484

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

490
        assert(value);
622✔
491
        assert(list);
622✔
492

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

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

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

503
        return 0;
504
}
505

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

510
        assert(value);
698✔
511
        assert(ret);
698✔
512

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

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

524
                assert(r <= 2);
698✔
525

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

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

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

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

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

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

560
        return 0;
561
}
562

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

567
        assert(rl);
40,734✔
568
        assert(name);
40,734✔
569
        assert(value);
40,734✔
570

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

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

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

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

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

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

594
        assert(ret);
2,648✔
595

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

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

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

608
int finish_serialization_fd(int fd) {
2,193✔
609
        assert(fd >= 0);
2,193✔
610

611
        if (lseek(fd, 0, SEEK_SET) < 0)
2,193✔
612
                return -errno;
×
613

614
        return memfd_set_sealed(fd);
2,193✔
615
}
616

617
int finish_serialization_file(FILE *f) {
2,648✔
618
        int r;
2,648✔
619

620
        assert(f);
2,648✔
621

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

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

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

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