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

systemd / systemd / 14630481637

23 Apr 2025 07:04PM UTC coverage: 72.178% (-0.002%) from 72.18%
14630481637

push

github

DaanDeMeyer
mkosi: Run clangd within the tools tree instead of the build container

Running within the build sandbox has a number of disadvantages:
- We have a separate clangd cache for each distribution/release combo
- It requires to build the full image before clangd can be used
- It breaks every time the image becomes out of date and requires a
  rebuild
- We can't look at system headers as we don't have the knowledge to map
  them from inside the build sandbox to the corresponding path on the host

Instead, let's have mkosi.clangd run clangd within the tools tree. We
already require building systemd for both the host and the target anyway,
and all the dependencies to build systemd are installed in the tools tree
already for that, as well as clangd since it's installed together with the
other clang tooling we install in the tools tree. Unlike the previous approach,
this approach only requires the mkosi tools tree to be built upfront, which has
a much higher chance of not invalidating its cache. We can also trivially map
system header lookups from within the sandbox to the path within mkosi.tools
on the host so that starts working as well.

297054 of 411557 relevant lines covered (72.18%)

686269.58 hits per line

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

66.98
/src/core/executor.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

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

6
#include "sd-messages.h"
7

8
#include "alloc-util.h"
9
#include "argv-util.h"
10
#include "build.h"
11
#include "capability-util.h"
12
#include "cgroup.h"
13
#include "dynamic-user.h"
14
#include "exec-invoke.h"
15
#include "execute-serialize.h"
16
#include "execute.h"
17
#include "exit-status.h"
18
#include "fdset.h"
19
#include "fd-util.h"
20
#include "fileio.h"
21
#include "getopt-defs.h"
22
#include "label-util.h"
23
#include "parse-util.h"
24
#include "pretty-print.h"
25
#include "selinux-util.h"
26
#include "static-destruct.h"
27

28
static FILE *arg_serialization = NULL;
29

30
STATIC_DESTRUCTOR_REGISTER(arg_serialization, fclosep);
28✔
31

32
static int help(void) {
×
33
        _cleanup_free_ char *link = NULL;
×
34
        int r;
×
35

36
        r = terminal_urlify_man("systemd", "1", &link);
×
37
        if (r < 0)
×
38
                return log_oom();
×
39

40
        printf("%s [OPTIONS...]\n\n"
×
41
               "%sSandbox and execute processes.%s\n\n"
42
               "  -h --help                Show this help and exit\n"
43
               "     --version             Print version string and exit\n"
44
               "     --log-target=TARGET   Set log target (console, journal,\n"
45
               "                                           journal-or-kmsg,\n"
46
               "                                           kmsg, null)\n"
47
               "     --log-level=LEVEL     Set log level (debug, info, notice,\n"
48
               "                                          warning, err, crit,\n"
49
               "                                          alert, emerg)\n"
50
               "     --log-color=BOOL      Highlight important messages\n"
51
               "     --log-location=BOOL   Include code location in messages\n"
52
               "     --log-time=BOOL       Prefix messages with current time\n"
53
               "     --deserialize=FD      Deserialize process config from FD\n"
54
               "\nSee the %s for details.\n",
55
               program_invocation_short_name,
56
               ansi_highlight(),
57
               ansi_normal(),
58
               link);
59

60
        return 0;
61
}
62

63
static int parse_argv(int argc, char *argv[]) {
11,503✔
64
        enum {
11,503✔
65
                COMMON_GETOPT_ARGS,
66
                ARG_VERSION,
67
                ARG_DESERIALIZE,
68
        };
69

70
        static const struct option options[] = {
11,503✔
71
                { "log-level",      required_argument, NULL, ARG_LOG_LEVEL      },
72
                { "log-target",     required_argument, NULL, ARG_LOG_TARGET     },
73
                { "log-color",      required_argument, NULL, ARG_LOG_COLOR      },
74
                { "log-location",   required_argument, NULL, ARG_LOG_LOCATION   },
75
                { "log-time",       required_argument, NULL, ARG_LOG_TIME       },
76
                { "help",           no_argument,       NULL, 'h'                },
77
                { "version",        no_argument,       NULL, ARG_VERSION        },
78
                { "deserialize",    required_argument, NULL, ARG_DESERIALIZE    },
79
                {}
80
        };
81

82
        int c, r;
11,503✔
83

84
        assert(argc >= 0);
11,503✔
85
        assert(argv);
11,503✔
86

87
        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
46,012✔
88
                switch (c) {
34,509✔
89
                case 'h':
×
90
                        return help();
×
91

92
                case ARG_VERSION:
×
93
                        return version();
×
94

95
                case ARG_LOG_LEVEL:
11,503✔
96
                        r = log_set_max_level_from_string(optarg);
11,503✔
97
                        if (r < 0)
11,503✔
98
                                return log_error_errno(r, "Failed to parse log level \"%s\": %m", optarg);
×
99

100
                        break;
101

102
                case ARG_LOG_TARGET:
11,503✔
103
                        r = log_set_target_from_string(optarg);
11,503✔
104
                        if (r < 0)
11,503✔
105
                                return log_error_errno(r, "Failed to parse log target \"%s\": %m", optarg);
×
106

107
                        break;
108

109
                case ARG_LOG_COLOR:
×
110
                        r = log_show_color_from_string(optarg);
×
111
                        if (r < 0)
×
112
                                return log_error_errno(
×
113
                                                r,
114
                                                "Failed to parse log color setting \"%s\": %m",
115
                                                optarg);
116

117
                        break;
118

119
                case ARG_LOG_LOCATION:
×
120
                        r = log_show_location_from_string(optarg);
×
121
                        if (r < 0)
×
122
                                return log_error_errno(
×
123
                                                r,
124
                                                "Failed to parse log location setting \"%s\": %m",
125
                                                optarg);
126

127
                        break;
128

129
                case ARG_LOG_TIME:
×
130
                        r = log_show_time_from_string(optarg);
×
131
                        if (r < 0)
×
132
                                return log_error_errno(
×
133
                                                r,
134
                                                "Failed to parse log time setting \"%s\": %m",
135
                                                optarg);
136

137
                        break;
138

139
                case ARG_DESERIALIZE: {
11,503✔
140
                        _cleanup_close_ int fd = -EBADF;
11,503✔
141
                        FILE *f;
11,503✔
142

143
                        fd = parse_fd(optarg);
11,503✔
144
                        if (fd < 0)
11,503✔
145
                                return log_error_errno(fd,
×
146
                                                       "Failed to parse serialization fd \"%s\": %m",
147
                                                       optarg);
148

149
                        r = fd_cloexec(fd, /* cloexec= */ true);
11,503✔
150
                        if (r < 0)
11,503✔
151
                                return log_error_errno(r,
×
152
                                                       "Failed to set serialization fd %d to close-on-exec: %m",
153
                                                       fd);
154

155
                        f = take_fdopen(&fd, "r");
11,503✔
156
                        if (!f)
11,503✔
157
                                return log_error_errno(errno, "Failed to open serialization fd %d: %m", fd);
×
158

159
                        safe_fclose(arg_serialization);
11,503✔
160
                        arg_serialization = f;
11,503✔
161

162
                        break;
11,503✔
163
                }
164

165
                case '?':
166
                        return -EINVAL;
167

168
                default:
×
169
                        assert_not_reached();
×
170
                }
171

172
        if (!arg_serialization)
11,503✔
173
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No serialization fd specified.");
×
174

175
        return 1 /* work to do */;
176
}
177

178
static int run(int argc, char *argv[]) {
11,503✔
179
        _cleanup_fdset_free_ FDSet *fdset = NULL;
28✔
180
        _cleanup_(cgroup_context_done) CGroupContext cgroup_context = {};
28✔
181
        _cleanup_(exec_context_done) ExecContext context = {};
28✔
182
        _cleanup_(exec_command_done) ExecCommand command = {};
28✔
183
        _cleanup_(exec_params_deep_clear) ExecParameters params = EXEC_PARAMETERS_INIT(/* flags= */ 0);
28✔
184
        _cleanup_(exec_shared_runtime_done) ExecSharedRuntime shared = {
28✔
185
                .netns_storage_socket = EBADF_PAIR,
186
                .ipcns_storage_socket = EBADF_PAIR,
187
        };
188
        _cleanup_(dynamic_creds_done) DynamicCreds dynamic_creds = {};
28✔
189
        _cleanup_(exec_runtime_clear) ExecRuntime runtime = {
28✔
190
                .ephemeral_storage_socket = EBADF_PAIR,
191
                .shared = &shared,
192
                .dynamic_creds = &dynamic_creds,
193
        };
194
        int exit_status = EXIT_SUCCESS, r;
11,503✔
195

196
        exec_context_init(&context);
11,503✔
197
        cgroup_context_init(&cgroup_context);
11,503✔
198

199
        /* We might be starting the journal itself, we'll be told by the caller what to do */
200
        log_set_always_reopen_console(true);
11,503✔
201
        log_set_prohibit_ipc(true);
11,503✔
202
        log_setup();
11,503✔
203

204
        r = parse_argv(argc, argv);
11,503✔
205
        if (r <= 0)
11,503✔
206
                return r;
207

208
        /* Now that we know the intended log target, allow IPC and open the final log target. */
209
        log_set_prohibit_ipc(false);
11,503✔
210
        log_open();
11,503✔
211

212
        /* Clear ambient capabilities, so services do not inherit them implicitly. Dropping them does
213
         * not affect the permitted and effective sets which are important for the executor itself to
214
         * operate. */
215
        r = capability_ambient_set_apply(0, /* also_inherit= */ false);
11,503✔
216
        if (r < 0)
11,503✔
217
                log_warning_errno(r, "Failed to clear ambient capabilities, ignoring: %m");
×
218

219
        /* This call would collect all passed fds and enable CLOEXEC. We'll unset it in exec_invoke (flag_fds)
220
         * for fds that shall be passed to the child.
221
         * The serialization fd is set to CLOEXEC in parse_argv, so it's also filtered. */
222
        r = fdset_new_fill(/* filter_cloexec= */ 0, &fdset);
11,503✔
223
        if (r < 0)
11,503✔
224
                return log_error_errno(r, "Failed to create fd set: %m");
×
225

226
        /* Initialize lazily. SMACK is just a few operations, but the SELinux is very slow as it requires
227
         * loading the entire database in memory, so we will do it lazily only if it is actually needed, to
228
         * avoid wasting 2ms-10ms for each sd-executor that gets spawned. */
229
        r = mac_init_lazy();
11,503✔
230
        if (r < 0)
11,503✔
231
                return log_error_errno(r, "Failed to initialize MAC layer: %m");
×
232

233
        r = exec_deserialize_invocation(arg_serialization,
11,503✔
234
                                        fdset,
235
                                        &context,
236
                                        &command,
237
                                        &params,
238
                                        &runtime,
239
                                        &cgroup_context);
240
        if (r < 0)
11,503✔
241
                return log_error_errno(r, "Failed to deserialize: %m");
×
242

243
        LOG_CONTEXT_PUSH_EXEC(&context, &params);
32,961✔
244

245
        arg_serialization = safe_fclose(arg_serialization);
11,503✔
246
        fdset = fdset_free(fdset);
11,503✔
247

248
        r = exec_invoke(&command,
11,503✔
249
                        &context,
250
                        &params,
251
                        &runtime,
252
                        &cgroup_context,
253
                        &exit_status);
254
        if (r < 0) {
28✔
255
                const char *status = ASSERT_PTR(
27✔
256
                                exit_status_to_string(exit_status, EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD));
257

258
                log_struct_errno(LOG_ERR, r,
27✔
259
                                 LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED_STR),
260
                                 LOG_EXEC_MESSAGE(&params, "Failed at step %s spawning %s: %m",
261
                                                  status, command.path),
262
                                 LOG_ITEM("EXECUTABLE=%s", command.path));
263
        } else
264
                /* r == 0: 'skip' is chosen in the confirm spawn prompt
265
                 * r > 0:  expected/ignored failure, do not log at error level */
266
                assert((r == 0) == (exit_status == EXIT_SUCCESS));
1✔
267

268
        return exit_status;
28✔
269
}
270

271
int main(int argc, char *argv[]) {
11,503✔
272
        int r;
11,503✔
273

274
        /* We use safe_fork() for spawning sd-pam helper process, which internally calls rename_process().
275
         * As the last step of renaming, all saved argvs are memzero()-ed. Hence, we need to save the argv
276
         * first to prevent showing "intense" cmdline. See #30352. */
277
        save_argc_argv(argc, argv);
11,503✔
278

279
        r = run(argc, argv);
11,503✔
280

281
        mac_selinux_finish();
28✔
282
        static_destruct();
28✔
283

284
        return r < 0 ? EXIT_FAILURE : r;
28✔
285
}
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