• 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

76.61
/src/basic/build-path.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <elf.h>
4
#include <fcntl.h>
5
#include <link.h>
6
#include <stdlib.h>
7
#include <sys/auxv.h>
8

9
#include "alloc-util.h"
10
#include "build-path.h"
11
#include "path-util.h"
12
#include "process-util.h"
13
#include "string-util.h"
14
#include "unistd.h"
15

16
static int get_runpath_from_dynamic(const ElfW(Dyn) *d, ElfW(Addr) bias, const char **ret) {
4,044✔
17
        size_t runpath_index = SIZE_MAX, rpath_index = SIZE_MAX;
4,044✔
18
        const char *strtab = NULL;
4,044✔
19

20
        assert(d);
4,044✔
21

22
        /* Iterates through the PT_DYNAMIC section to find the DT_RUNPATH/DT_RPATH entries */
23

24
        for (; d->d_tag != DT_NULL; d++) {
51,631✔
25

26
                switch (d->d_tag) {
51,631✔
27

28
                case DT_RUNPATH:
4,044✔
29
                        runpath_index = (size_t) d->d_un.d_val;
4,044✔
30
                        break;
4,044✔
31

UNCOV
32
                case DT_RPATH:
×
33
                        rpath_index = (size_t) d->d_un.d_val;
×
34
                        break;
×
35

36
                case DT_STRTAB:
4,044✔
37
                        /* On MIPS and RISC-V DT_STRTAB records an offset, not a valid address, so it has to be adjusted
38
                         * using the bias calculated earlier. */
39
                        if (d->d_un.d_val != 0)
4,044✔
40
                                strtab = (const char *) ((uintptr_t) d->d_un.d_val
4,044✔
41
#if defined(__mips__) || defined(__riscv)
42
                                         + bias
43
#endif
44
                                );
45
                        break;
46
                }
47

48
                /* runpath wins, hence if we have the table and runpath we can exit the loop early */
49
                if (strtab && runpath_index != SIZE_MAX)
51,631✔
50
                        break;
51
        }
52

53
        if (!strtab)
4,044✔
54
                return -ENOTRECOVERABLE;
55

56
        /* According to ld.so runpath wins if both runpath and rpath are defined. */
57
        if (runpath_index != SIZE_MAX) {
4,044✔
58
                if (ret)
4,044✔
59
                        *ret = strtab + runpath_index;
4,044✔
60
                return 1;
4,044✔
61
        }
62

UNCOV
63
        if (rpath_index != SIZE_MAX) {
×
64
                if (ret)
×
65
                        *ret = strtab + rpath_index;
×
66
                return 1;
×
67
        }
68

UNCOV
69
        if (ret)
×
70
                *ret = NULL;
×
71

72
        return 0;
73
}
74

75
static int get_runpath(const char **ret) {
4,044✔
76
        unsigned long phdr, phent, phnum;
4,044✔
77

78
        /* Finds the rpath/runpath in the program headers of the main executable we are running in */
79

80
        phdr = getauxval(AT_PHDR);      /* Start offset of phdr */
4,044✔
81
        if (phdr == 0)
4,044✔
82
                return -ENOTRECOVERABLE;
83

84
        phnum = getauxval(AT_PHNUM);    /* Number of entries in phdr */
4,044✔
85
        if (phnum == 0)
4,044✔
86
                return -ENOTRECOVERABLE;
87

88
        phent = getauxval(AT_PHENT);    /* Size of entries in phdr */
4,044✔
89
        if (phent < sizeof(ElfW(Phdr))) /* Safety check, that our idea of the structure matches the file */
4,044✔
90
                return -ENOTRECOVERABLE;
91

92
        ElfW(Addr) bias = 0, dyn = 0;
93
        bool found_bias = false, found_dyn = false;
94

95
        /* Iterate through the Phdr structures to find the PT_PHDR and PT_DYNAMIC sections */
96
        for (unsigned long i = 0; i < phnum; i++) {
28,308✔
97
                const ElfW(Phdr) *p = (const ElfW(Phdr)*) (phdr + (i * phent));
28,308✔
98

99
                switch (p->p_type) {
28,308✔
100

101
                case PT_PHDR:
4,044✔
102
                        if (p->p_vaddr > phdr) /* safety overflow check */
4,044✔
103
                                return -ENOTRECOVERABLE;
104

105
                        bias = (ElfW(Addr)) phdr - p->p_vaddr;
4,044✔
106
                        found_bias = true;
4,044✔
107
                        break;
4,044✔
108

109
                case PT_DYNAMIC:
4,044✔
110
                        dyn = p->p_vaddr;
4,044✔
111
                        found_dyn = true;
4,044✔
112
                        break;
4,044✔
113
                }
114

115
                if (found_bias && found_dyn)
28,308✔
116
                        break;
117
        }
118

119
        if (!found_dyn)
4,044✔
120
                return -ENOTRECOVERABLE;
121

122
        return get_runpath_from_dynamic((const ElfW(Dyn)*) (bias + dyn), bias, ret);
4,044✔
123
}
124

125
int get_build_exec_dir(char **ret) {
14,871✔
126
        int r;
14,871✔
127

128
        /* Returns the build execution directory if we are invoked in a build environment. Specifically, this
129
         * checks if the main program binary has an rpath/runpath set (i.e. an explicit directory where to
130
         * look for shared libraries) to $ORIGIN. If so we know that this is not a regular installed binary,
131
         * but one which shall acquire its libraries from below a directory it is located in, i.e. a build
132
         * directory or similar. In that case it typically makes sense to also search for our auxiliary
133
         * executables we fork() off in a directory close to our main program binary, rather than in the
134
         * system.
135
         *
136
         * This function is supposed to be used when looking for "callout" binaries that are closely related
137
         * to the main program (i.e. speak a specific protocol between each other). And where it's generally
138
         * a good idea to use the binary from the build tree (if there is one) instead of the system.
139
         *
140
         * Note that this does *not* actually return the rpath/runpath but the instead the directory the main
141
         * executable was found in. This follows the logic that the result is supposed to be used for
142
         * executable binaries (i.e. stuff in bindir), not for shared libraries (i.e. stuff in libdir), and
143
         * hence the literal shared library path would just be wrong.
144
         *
145
         * TLDR: if we look for callouts in this dir first, running binaries from the meson build tree
146
         * automatically uses the right callout.
147
         *
148
         * Returns:
149
         *     -ENOEXEC         → We are not running in an rpath/runpath $ORIGIN environment
150
         *     -ENOENT          → We don't know our own binary path
151
         *     -NOTRECOVERABLE  → Dynamic binary information missing?
152
         */
153

154
        static int runpath_cached = -ERRNO_MAX-1;
14,871✔
155
        if (runpath_cached == -ERRNO_MAX-1) {
14,871✔
156
                const char *runpath = NULL;
4,044✔
157

158
                runpath_cached = get_runpath(&runpath);
4,044✔
159

160
                /* We only care if the runpath starts with $ORIGIN/ */
161
                if (runpath_cached > 0 && !startswith(runpath, "$ORIGIN/"))
4,044✔
162
                        runpath_cached = 0;
4,044✔
163
        }
164
        if (runpath_cached < 0)
14,871✔
165
                return runpath_cached;
14,871✔
166
        if (runpath_cached == 0)
14,871✔
167
                return -ENOEXEC;
168

UNCOV
169
        _cleanup_free_ char *exe = NULL;
×
170
        r = get_process_exe(0, &exe);
×
171
        if (r < 0)
×
172
                return runpath_cached = r;
×
173

UNCOV
174
        return path_extract_directory(exe, ret);
×
175
}
176

177
static int find_build_dir_binary(const char *fn, char **ret) {
14,870✔
178
        int r;
14,870✔
179

180
        assert(fn);
14,870✔
181
        assert(ret);
14,870✔
182

183
        _cleanup_free_ char *build_dir = NULL;
14,870✔
184
        r = get_build_exec_dir(&build_dir);
14,870✔
185
        if (r < 0)
14,870✔
186
                return r;
187

UNCOV
188
        _cleanup_free_ char *np = path_join(build_dir, fn);
×
189
        if (!np)
×
190
                return -ENOMEM;
191

UNCOV
192
        *ret = TAKE_PTR(np);
×
193
        return 0;
×
194
}
195

196
static int find_environment_binary(const char *fn, const char **ret) {
14,870✔
197

198
        /* If a path such as /usr/lib/systemd/systemd-foobar is specified, then this will check for an
199
         * environment variable SYSTEMD_FOOBAR_PATH and return it if set. */
200

201
        _cleanup_free_ char *s = strdup(fn);
14,870✔
202
        if (!s)
14,870✔
203
                return -ENOMEM;
204

205
        ascii_strupper(s);
14,870✔
206
        string_replace_char(s, '-', '_');
14,870✔
207

208
        if (!strextend(&s, "_PATH"))
14,870✔
209
                return -ENOMEM;
210

211
        const char *e;
14,870✔
212
        e = secure_getenv(s);
14,870✔
213
        if (!e)
14,870✔
214
                return -ENXIO;
215

UNCOV
216
        *ret = e;
×
217
        return 0;
×
218
}
219

220
int invoke_callout_binary(const char *path, char *const argv[]) {
2,562✔
221
        int r;
2,562✔
222

223
        assert(path);
2,562✔
224

225
        /* Just like execv(), but tries to execute the specified binary in the build dir instead, if known */
226

227
        _cleanup_free_ char *fn = NULL;
2,562✔
228
        r = path_extract_filename(path, &fn);
2,562✔
229
        if (r < 0)
2,562✔
230
                return r;
231
        if (r == O_DIRECTORY) /* Uh? */
2,562✔
232
                return -EISDIR;
233

234
        const char *e;
2,562✔
235
        if (find_environment_binary(fn, &e) >= 0) {
2,562✔
236
                /* If there's an explicit environment variable set for this binary, prefer it */
UNCOV
237
                execv(e, argv);
×
238
                return -errno; /* The environment variable counts, let's fail otherwise */
×
239
        }
240

241
        _cleanup_free_ char *np = NULL;
2,562✔
242
        if (find_build_dir_binary(fn, &np) >= 0)
2,562✔
UNCOV
243
                execv(np, argv);
×
244

245
        execvp(path, argv);
2,562✔
246
        return -errno;
2,562✔
247
}
248

249
int pin_callout_binary(const char *path, char **ret_path) {
12,308✔
250
        int r, fd;
12,308✔
251

252
        assert(path);
12,308✔
253

254
        /* Similar to invoke_callout_binary(), but pins (i.e. O_PATH opens) the binary instead of executing
255
         * it, also optionally provides the path to the binary. */
256

257
        _cleanup_free_ char *fn = NULL;
12,308✔
258
        r = path_extract_filename(path, &fn);
12,308✔
259
        if (r < 0)
12,308✔
260
                return r;
261
        if (r == O_DIRECTORY) /* Uh? */
12,308✔
262
                return -EISDIR;
263

264
        const char *e;
12,308✔
265
        if (find_environment_binary(fn, &e) >= 0) {
12,308✔
266
                /* The environment variable counts. We'd fail if the executable is not available/invalid. */
UNCOV
267
                r = open_and_check_executable(e, /* root = */ NULL, ret_path, &fd);
×
268
                if (r < 0)
×
269
                        return r;
270

UNCOV
271
                return fd;
×
272
        }
273

274
        _cleanup_free_ char *np = NULL;
12,308✔
275
        if (find_build_dir_binary(fn, &np) >= 0) {
12,308✔
UNCOV
276
                r = open_and_check_executable(np, /* root = */ NULL, ret_path, &fd);
×
277
                if (r >= 0)
×
278
                        return fd;
×
279
        }
280

281
        r = find_executable_full(path, /* root = */ NULL,
12,308✔
282
                                 /* exec_search_path = */ NULL, /* use_path_envvar = */ true,
283
                                 ret_path, &fd);
284
        if (r < 0)
12,308✔
285
                return r;
286

287
        return fd;
12,308✔
288
}
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