• 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

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

3
#include <fcntl.h>
4
#include <sys/xattr.h>
5
#include <threads.h>
6

7
#include "alloc-util.h"
8
#include "errno-util.h"
9
#include "fd-util.h"
10
#include "fs-util.h"
11
#include "missing_syscall.h"
12
#include "nulstr-util.h"
13
#include "parse-util.h"
14
#include "sparse-endian.h"
15
#include "stat-util.h"
16
#include "string-util.h"
17
#include "strv.h"
18
#include "time-util.h"
19
#include "xattr-util.h"
20

21
/* Use a single cache for all of *xattrat syscalls (added in kernel 6.13) */
22
static thread_local bool have_xattrat = true;
23

24
static int normalize_and_maybe_pin_inode(
600,678✔
25
                int *fd,
26
                const char **path,
27
                int *at_flags,
28
                int *ret_tfd,
29
                bool *ret_opath) {
30

31
        int r;
600,678✔
32

33
        assert(fd);
600,678✔
34
        assert(*fd >= 0 || *fd == AT_FDCWD);
600,678✔
35
        assert(path);
600,678✔
36
        assert(at_flags);
600,678✔
37
        assert(ret_tfd);
600,678✔
38
        assert(ret_opath);
600,678✔
39

40
        if (isempty(*path))
600,678✔
41
                *path = NULL; /* Normalize "" to NULL */
445,568✔
42

43
        if (*fd == AT_FDCWD) {
600,678✔
44
                if (!*path) /* Both unspecified? Then operate on current working directory */
16,285✔
UNCOV
45
                        *path = ".";
×
46

47
                *ret_tfd = -EBADF;
16,285✔
48
                *ret_opath = false;
16,285✔
49
                return 0;
16,285✔
50
        }
51

52
        *at_flags |= AT_EMPTY_PATH;
584,393✔
53

54
        if (!*path) {
584,393✔
55
                r = fd_is_opath(*fd);
445,568✔
56
                if (r < 0)
445,568✔
57
                        return r;
58
                *ret_opath = r;
445,568✔
59
                *ret_tfd = -EBADF;
445,568✔
60
                return 0;
445,568✔
61
        }
62

63
        /* If both have been specified, then we go via O_PATH */
64

65
        int tfd = openat(*fd, *path, O_PATH|O_CLOEXEC|(FLAGS_SET(*at_flags, AT_SYMLINK_FOLLOW) ? 0 : O_NOFOLLOW));
277,330✔
66
        if (tfd < 0)
138,825✔
67
                return -errno;
1✔
68

69
        *fd = *ret_tfd = tfd;
138,824✔
70
        *path = NULL;
138,824✔
71
        *ret_opath = true;
138,824✔
72

73
        return 0;
138,824✔
74
}
75

76
static ssize_t getxattr_pinned_internal(
25,077✔
77
                int fd,
78
                const char *path,
79
                int at_flags,
80
                bool by_procfs,
81
                const char *name,
82
                char *buf,
83
                size_t size) {
84

85
        ssize_t n;
25,077✔
86

87
        assert(!path || !isempty(path));
25,077✔
88
        assert((fd >= 0) == !path);
25,077✔
89
        assert(path || FLAGS_SET(at_flags, AT_EMPTY_PATH));
25,077✔
90
        assert(name);
25,077✔
91
        assert(buf || size == 0);
25,077✔
92

93
        if (path)
25,077✔
94
                n = FLAGS_SET(at_flags, AT_SYMLINK_FOLLOW) ? getxattr(path, name, buf, size)
357✔
95
                                                           : lgetxattr(path, name, buf, size);
16,279✔
96
        else
97
                n = by_procfs ? getxattr(FORMAT_PROC_FD_PATH(fd), name, buf, size)
8,348✔
98
                              : fgetxattr(fd, name, buf, size);
8,798✔
99
        if (n < 0)
25,077✔
100
                return -errno;
23,715✔
101

102
        assert(size == 0 || (size_t) n <= size);
1,362✔
103
        return n;
104
}
105

106
int getxattr_at_malloc(
24,963✔
107
                int fd,
108
                const char *path,
109
                const char *name,
110
                int at_flags,
111
                char **ret,
112
                size_t *ret_size) {
113

114
        _cleanup_close_ int opened_fd = -EBADF;
24,963✔
115
        bool by_procfs;
24,963✔
116
        int r;
24,963✔
117

118
        assert(fd >= 0 || fd == AT_FDCWD);
24,963✔
119
        assert(name);
24,963✔
120
        assert((at_flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
24,963✔
121
        assert(ret);
24,963✔
122

123
        /* So, this is single function that does what getxattr()/lgetxattr()/fgetxattr() does, but in one go,
124
         * and with additional bells and whistles. Specifically:
125
         *
126
         * 1. This works on O_PATH fds (via /proc/self/fd/, since getxattrat() syscall refuses them...)
127
         * 2. As extension to openat()-style semantics implies AT_EMPTY_PATH if path is empty
128
         * 3. Does a malloc() loop, automatically sizing the allocation
129
         * 4. NUL-terminates the returned buffer (for safety)
130
         */
131

132
        r = normalize_and_maybe_pin_inode(&fd, &path, &at_flags, &opened_fd, &by_procfs);
24,963✔
133
        if (r < 0)
24,963✔
134
                return r;
135

136
        size_t l = 100;
137
        for (unsigned n_attempts = 7;;) {
57✔
138
                _cleanup_free_ char *v = NULL;
25,020✔
139

140
                if (n_attempts == 0) /* If someone is racing against us, give up eventually */
25,020✔
141
                        return -EBUSY;
142
                n_attempts--;
25,020✔
143

144
                v = new(char, l+1);
25,020✔
145
                if (!v)
25,020✔
146
                        return -ENOMEM;
147

148
                l = MALLOC_ELEMENTSOF(v) - 1;
25,020✔
149

150
                ssize_t n;
25,020✔
151
                n = getxattr_pinned_internal(fd, path, at_flags, by_procfs, name, v, l);
25,020✔
152
                if (n >= 0) {
25,020✔
153
                        /* Refuse extended attributes with embedded NUL bytes if the caller isn't interested
154
                         * in the size. After all this must mean the caller assumes we return a NUL
155
                         * terminated strings, but if there's a NUL byte embedded they are definitely not
156
                         * regular strings */
157
                        if (!ret_size && n > 1 && memchr(v, 0, n - 1))
1,305✔
158
                                return -EBADMSG;
159

160
                        v[n] = 0; /* NUL terminate */
1,304✔
161
                        *ret = TAKE_PTR(v);
1,304✔
162
                        if (ret_size)
1,304✔
163
                                *ret_size = (size_t) n;
705✔
164

165
                        return 0;
1,304✔
166
                }
167
                if (n != -ERANGE)
23,715✔
168
                        return (int) n;
23,658✔
169

170
                n = getxattr_pinned_internal(fd, path, at_flags, by_procfs, name, NULL, 0);
57✔
171
                if (n < 0)
57✔
UNCOV
172
                        return (int) n;
×
173

174
                l = (size_t) n;
57✔
175
        }
176
}
177

178
int getxattr_at_bool(int fd, const char *path, const char *name, int at_flags) {
1,140✔
179
        _cleanup_free_ char *v = NULL;
1,140✔
180
        int r;
1,140✔
181

182
        r = getxattr_at_malloc(fd, path, name, at_flags, &v, /* ret_size= */ NULL);
1,140✔
183
        if (r < 0)
1,140✔
184
                return r;
185

186
        return parse_boolean(v);
559✔
187
}
188

189
int getxattr_at_strv(int fd, const char *path, const char *name, int at_flags, char ***ret_strv) {
48✔
190
        _cleanup_free_ char *nulstr = NULL;
48✔
191
        size_t nulstr_size;
48✔
192
        int r;
48✔
193

194
        assert(ret_strv);
48✔
195

196
        r = getxattr_at_malloc(fd, path, name, at_flags, &nulstr, &nulstr_size);
48✔
197
        if (r < 0)
48✔
198
                return r;
199

200
        _cleanup_strv_free_ char **l = strv_parse_nulstr(nulstr, nulstr_size);
70✔
201
        if (!l)
35✔
202
                return -ENOMEM;
203

204
        *ret_strv = TAKE_PTR(l);
35✔
205
        return 0;
35✔
206
}
207

208
static int listxattr_pinned_internal(
570,659✔
209
                int fd,
210
                const char *path,
211
                int at_flags,
212
                bool by_procfs,
213
                char *buf,
214
                size_t size) {
215

216
        ssize_t n;
570,659✔
217

218
        assert(!path || !isempty(path));
570,659✔
219
        assert((fd >= 0) == !path);
570,659✔
220
        assert(path || FLAGS_SET(at_flags, AT_EMPTY_PATH));
570,659✔
221
        assert(buf || size == 0);
570,659✔
222

223
        if (path)
570,659✔
UNCOV
224
                n = FLAGS_SET(at_flags, AT_SYMLINK_FOLLOW) ? listxattr(path, buf, size)
×
225
                                                           : llistxattr(path, buf, size);
2✔
226
        else
227
                n = by_procfs ? listxattr(FORMAT_PROC_FD_PATH(fd), buf, size)
138,522✔
228
                              : flistxattr(fd, buf, size);
570,657✔
229
        if (n < 0)
570,659✔
230
                return -errno;
392✔
231

232
        assert(size == 0 || (size_t) n <= size);
570,267✔
233

234
        if (n > INT_MAX) /* We couldn't return this as 'int' anymore */
570,267✔
235
                return -E2BIG;
236

237
        return (int) n;
570,267✔
238
}
239

240
int listxattr_at_malloc(int fd, const char *path, int at_flags, char **ret) {
570,659✔
241
        _cleanup_close_ int opened_fd = -EBADF;
570,659✔
242
        bool by_procfs;
570,659✔
243
        int r;
570,659✔
244

245
        assert(fd >= 0 || fd == AT_FDCWD);
570,659✔
246
        assert((at_flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
570,659✔
247
        assert(ret);
570,659✔
248

249
        /* This is to listxattr()/llistattr()/flistattr() what getxattr_at_malloc() is to getxattr()/… */
250

251
        r = normalize_and_maybe_pin_inode(&fd, &path, &at_flags, &opened_fd, &by_procfs);
570,659✔
252
        if (r < 0)
570,659✔
253
                return r;
254

255
        size_t l = 100;
UNCOV
256
        for (unsigned n_attempts = 7;;) {
×
257
                _cleanup_free_ char *v = NULL;
570,659✔
258

259
                if (n_attempts == 0) /* If someone is racing against us, give up eventually */
570,659✔
260
                        return -EBUSY;
261
                n_attempts--;
570,659✔
262

263
                v = new(char, l+1);
570,659✔
264
                if (!v)
570,659✔
265
                        return -ENOMEM;
266

267
                l = MALLOC_ELEMENTSOF(v) - 1;
570,659✔
268

269
                r = listxattr_pinned_internal(fd, path, at_flags, by_procfs, v, l);
570,659✔
270
                if (r >= 0) {
570,659✔
271
                        v[r] = 0; /* NUL terminate */
570,267✔
272
                        *ret = TAKE_PTR(v);
570,267✔
273
                        return r;
570,267✔
274
                }
275
                if (r != -ERANGE)
392✔
276
                        return r;
277

UNCOV
278
                r = listxattr_pinned_internal(fd, path, at_flags, by_procfs, NULL, 0);
×
UNCOV
279
                if (r < 0)
×
280
                        return r;
281

UNCOV
282
                l = (size_t) r;
×
283
        }
284
}
285

286
int xsetxattr_full(
2,037✔
287
                int fd,
288
                const char *path,
289
                int at_flags,
290
                const char *name,
291
                const char *value,
292
                size_t size,
293
                int xattr_flags) {
294

295
        int r;
2,037✔
296

297
        assert(fd >= 0 || fd == AT_FDCWD);
2,037✔
298
        assert((at_flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
2,037✔
299
        assert(name);
2,037✔
300
        assert(value);
2,037✔
301

302
        if (size == SIZE_MAX)
2,037✔
303
                size = strlen(value);
17✔
304

305
        if (have_xattrat && !isempty(path)) {
2,037✔
306
                struct xattr_args args = {
1✔
307
                        .value = PTR_TO_UINT64(value),
1✔
308
                        .size = size,
309
                        .flags = xattr_flags,
310
                };
311

312
                r = RET_NERRNO(setxattrat(fd, path,
1✔
313
                                          at_flags_normalize_nofollow(at_flags),
314
                                          name,
315
                                          &args, sizeof(args)));
316
                if (r != -ENOSYS) /* No ERRNO_IS_NOT_SUPPORTED here, as EOPNOTSUPP denotes the fs doesn't
1✔
317
                                     support xattr */
UNCOV
318
                        return r;
×
319

320
                have_xattrat = false;
1✔
321
        }
322

323
        _cleanup_close_ int opened_fd = -EBADF;
2,037✔
324
        bool by_procfs;
2,037✔
325

326
        r = normalize_and_maybe_pin_inode(&fd, &path, &at_flags, &opened_fd, &by_procfs);
2,037✔
327
        if (r < 0)
2,037✔
328
                return r;
329

330
        if (path)
2,036✔
UNCOV
331
                r = FLAGS_SET(at_flags, AT_SYMLINK_FOLLOW) ? setxattr(path, name, value, size, xattr_flags)
×
332
                                                           : lsetxattr(path, name, value, size, xattr_flags);
3✔
333
        else
334
                r = by_procfs ? setxattr(FORMAT_PROC_FD_PATH(fd), name, value, size, xattr_flags)
11✔
335
                              : fsetxattr(fd, name, value, size, xattr_flags);
2,033✔
336
        if (r < 0)
2,036✔
337
                return -errno;
5✔
338

339
        return 0;
340
}
341

342
int xsetxattr_strv(int fd, const char *path, int at_flags, const char *name, char * const *l) {
160✔
343
        _cleanup_free_ char *nulstr = NULL;
160✔
344
        size_t size;
160✔
345
        int r;
160✔
346

347
        assert(name);
160✔
348

349
        r = strv_make_nulstr(l, &nulstr, &size);
160✔
350
        if (r < 0)
160✔
351
                return r;
352

353
        return xsetxattr_full(fd, path, at_flags, name, nulstr, size, /* xattr_flags= */ 0);
160✔
354
}
355

356
int xremovexattr(int fd, const char *path, int at_flags, const char *name) {
3,019✔
357
        int r;
3,019✔
358

359
        assert(fd >= 0 || fd == AT_FDCWD);
3,019✔
360
        assert((at_flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
3,019✔
361
        assert(name);
3,019✔
362

363
        if (have_xattrat && !isempty(path)) {
3,019✔
UNCOV
364
                r = RET_NERRNO(removexattrat(fd, path,
×
365
                                             at_flags_normalize_nofollow(at_flags),
366
                                             name));
UNCOV
367
                if (r != -ENOSYS) /* No ERRNO_IS_NOT_SUPPORTED here, as EOPNOTSUPP denotes the fs doesn't
×
368
                                     support xattr */
369
                        return r;
×
370

UNCOV
371
                have_xattrat = false;
×
372
        }
373

374
        _cleanup_close_ int tfd = -EBADF;
3,019✔
375
        bool by_procfs;
3,019✔
376

377
        r = normalize_and_maybe_pin_inode(&fd, &path, &at_flags, &tfd, &by_procfs);
3,019✔
378
        if (r < 0)
3,019✔
379
                return r;
380

381
        if (path)
3,019✔
UNCOV
382
                r = FLAGS_SET(at_flags, AT_SYMLINK_FOLLOW) ? removexattr(path, name)
×
383
                                                           : lremovexattr(path, name);
1✔
384
        else
385
                r = by_procfs ? removexattr(FORMAT_PROC_FD_PATH(fd), name)
1,148✔
386
                              : fremovexattr(fd, name);
3,018✔
387
        if (r < 0)
3,019✔
388
                return -errno;
6✔
389

390
        return 0;
391
}
392

393
static int parse_crtime(le64_t le, usec_t *ret) {
366✔
394
        usec_t u;
366✔
395

396
        assert(ret);
366✔
397

398
        assert_cc(sizeof(usec_t) == sizeof(uint64_t));
366✔
399
        assert_cc((usec_t) UINT64_MAX == USEC_INFINITY);
366✔
400

401
        u = (usec_t) le64toh(le);
366✔
402
        if (!timestamp_is_set(u))
366✔
403
                return -EIO;
404

405
        *ret = u;
366✔
406
        return 0;
366✔
407
}
408

409
int getcrtime_at(
7,335✔
410
                int fd,
411
                const char *path,
412
                int at_flags,
413
                usec_t *ret) {
414

415
        _cleanup_free_ le64_t *le = NULL;
7,335✔
416
        struct statx sx;
7,335✔
417
        usec_t a, b;
7,335✔
418
        int r;
7,335✔
419

420
        assert(fd >= 0 || fd == AT_FDCWD);
7,335✔
421
        assert((at_flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
7,335✔
422

423
        if (isempty(path))
7,335✔
424
                at_flags |= AT_EMPTY_PATH;
7,016✔
425

426
        /* So here's the deal: the creation/birth time (crtime/btime) of a file is a relatively newly supported concept
427
         * on Linux (or more strictly speaking: a concept that only recently got supported in the API, it was
428
         * implemented on various file systems on the lower level since a while, but never was accessible). However, we
429
         * needed a concept like that for vacuuming algorithms and such, hence we emulated it via a user xattr for a
430
         * long time. Starting with Linux 4.11 there's statx() which exposes the timestamp to userspace for the first
431
         * time, where it is available. This function will read it, but it tries to keep some compatibility with older
432
         * systems: we try to read both the crtime/btime and the xattr, and then use whatever is older. After all the
433
         * concept is useful for determining how "old" a file really is, and hence using the older of the two makes
434
         * most sense. */
435

436
        if (statx(fd, strempty(path),
14,351✔
437
                  at_flags_normalize_nofollow(at_flags)|AT_STATX_DONT_SYNC,
7,335✔
438
                  STATX_BTIME,
439
                  &sx) >= 0 &&
7,335✔
440
            FLAGS_SET(sx.stx_mask, STATX_BTIME) && sx.stx_btime.tv_sec != 0)
7,335✔
441
                a = statx_timestamp_load(&sx.stx_btime);
4,983✔
442
        else
443
                a = USEC_INFINITY;
444

445
        size_t le_size;
7,335✔
446
        r = getxattr_at_malloc(fd, path, "user.crtime_usec", at_flags, (char**) &le, &le_size);
7,335✔
447
        if (r >= 0) {
7,335✔
448
                if (le_size != sizeof(*le))
366✔
449
                        r = -EIO;
450
                else
451
                        r = parse_crtime(*le, &b);
366✔
452
        }
453
        if (r < 0) {
366✔
454
                if (a != USEC_INFINITY) {
6,969✔
455
                        if (ret)
4,617✔
456
                                *ret = a;
4,617✔
457
                        return 0;
4,617✔
458
                }
459

460
                return r;
461
        }
462

463
        if (ret)
366✔
464
                *ret = MIN(a, b);
366✔
465
        return 0;
466
}
467

468
int fd_setcrtime(int fd, usec_t usec) {
1,614✔
469
        le64_t le;
1,614✔
470

471
        assert(fd >= 0);
1,614✔
472

473
        if (!timestamp_is_set(usec))
1,614✔
474
                usec = now(CLOCK_REALTIME);
1,568✔
475

476
        le = htole64((uint64_t) usec);
1,614✔
477
        return xsetxattr_full(fd, /* path = */ NULL, AT_EMPTY_PATH,
1,614✔
478
                              "user.crtime_usec", (const char*) &le, sizeof(le),
479
                              /* xattr_flags = */ 0);
480
}
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