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

systemd / systemd / 29132483780

10 Jul 2026 08:43PM UTC coverage: 72.912% (+0.2%) from 72.702%
29132483780

push

github

bluca
man: run forgotten 'update-man-rules'

344600 of 472622 relevant lines covered (72.91%)

1365091.83 hits per line

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

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

3
#include <stdlib.h>
4

5
#include "sd-messages.h"
6

7
#include "alloc-util.h"
8
#include "argv-util.h"
9
#include "build.h"
10
#include "capability-util.h"
11
#include "cgroup.h"
12
#include "dlopen-note.h"
13
#include "dynamic-user.h"
14
#include "exec-invoke.h"
15
#include "execute.h"
16
#include "execute-serialize.h"
17
#include "executor.h"
18
#include "exit-status.h"
19
#include "fd-util.h"
20
#include "fdset.h"
21
#include "format-table.h"
22
#include "label-util.h"
23
#include "log.h"
24
#include "options.h"
25
#include "parse-util.h"
26
#include "pretty-print.h"
27
#include "selinux-util.h"
28
#include "static-destruct.h"
29

30
static FILE *arg_serialization = NULL;
31

32
STATIC_DESTRUCTOR_REGISTER(arg_serialization, fclosep);
36✔
33

34
static int help(void) {
×
35
        _cleanup_free_ char *link = NULL;
×
36
        _cleanup_(table_unrefp) Table *options = NULL;
×
37
        int r;
×
38

39
        r = terminal_urlify_man("systemd", "1", &link);
×
40
        if (r < 0)
×
41
                return log_oom();
×
42

43
        r = option_parser_get_help_table_ns("systemd-executor", &options);
×
44
        if (r < 0)
×
45
                return r;
46

47
        printf("%s [OPTIONS...]\n\n"
×
48
               "%sSandbox and execute processes.%s\n\n",
49
               program_invocation_short_name,
50
               ansi_highlight(),
51
               ansi_normal());
52

53
        r = table_print_or_warn(options);
×
54
        if (r < 0)
×
55
                return r;
56

57
        printf("\nSee the %s for details.\n", link);
×
58
        return 0;
59
}
60

61
static int parse_argv(int argc, char *argv[]) {
12,880✔
62
        int r;
12,880✔
63

64
        assert(argc >= 0);
12,880✔
65
        assert(argv);
12,880✔
66

67
        OptionParser opts = { argc, argv, .namespace = "systemd-executor" };
12,880✔
68

69
        FOREACH_OPTION_OR_RETURN(c, &opts)
64,400✔
70
                switch (c) {
38,640✔
71

72
                OPTION_NAMESPACE("systemd-executor"): {}
×
73

74
                OPTION_COMMON_HELP:
×
75
                        return help();
×
76

77
                OPTION_COMMON_VERSION:
×
78
                        return version();
×
79

80
                OPTION_COMMON_LOG_LEVEL:
12,880✔
81
                        r = log_set_max_level_from_string(opts.arg);
12,880✔
82
                        if (r < 0)
12,880✔
83
                                return log_error_errno(r, "Failed to parse log level \"%s\": %m", opts.arg);
×
84
                        break;
85

86
                OPTION_COMMON_LOG_TARGET:
12,880✔
87
                        r = log_set_target_from_string(opts.arg);
12,880✔
88
                        if (r < 0)
12,880✔
89
                                return log_error_errno(r, "Failed to parse log target \"%s\": %m", opts.arg);
×
90
                        break;
91

92
                OPTION_COMMON_LOG_COLOR:
×
93
                        r = log_show_color_from_string(opts.arg);
×
94
                        if (r < 0)
×
95
                                return log_error_errno(r, "Failed to parse log color setting \"%s\": %m", opts.arg);
×
96
                        break;
97

98
                OPTION_COMMON_LOG_LOCATION:
×
99
                        r = log_show_location_from_string(opts.arg);
×
100
                        if (r < 0)
×
101
                                return log_error_errno(r, "Failed to parse log location setting \"%s\": %m", opts.arg);
×
102
                        break;
103

104
                OPTION_COMMON_LOG_TIME:
×
105
                        r = log_show_time_from_string(opts.arg);
×
106
                        if (r < 0)
×
107
                                return log_error_errno(r, "Failed to parse log time setting \"%s\": %m", opts.arg);
×
108
                        break;
109

110
                OPTION_LONG("deserialize", "FD", "Deserialize process config from FD"): {
12,880✔
111
                        int fd = parse_fd(opts.arg);
12,880✔
112
                        if (fd < 0)
12,880✔
113
                                return log_error_errno(fd, "Failed to parse serialization fd \"%s\": %m", opts.arg);
×
114

115
                        /* Set O_CLOEXEC and as a side effect, verify that the fd is valid. */
116
                        r = fd_cloexec(fd, /* cloexec= */ true);
12,880✔
117
                        if (r == -EBADF)
12,880✔
118
                                return log_error_errno(r, "Serialization fd %d is not valid.", fd);
×
119
                        if (r < 0)
12,880✔
120
                                return log_error_errno(r, "Failed to set serialization fd %d to close-on-exec: %m",
×
121
                                                       fd);
122

123
                        FILE *f = fdopen(fd, "r");
12,880✔
124
                        if (!f)
12,880✔
125
                                return log_error_errno(errno, "Failed to open serialization fd %d: %m", fd);
×
126

127
                        safe_fclose(arg_serialization);
12,880✔
128
                        arg_serialization = f;
12,880✔
129
                        break;
12,880✔
130
                }
131
                }
132

133
        if (!arg_serialization)
12,880✔
134
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No serialization fd specified.");
×
135

136
        return 1 /* work to do */;
137
}
138

139
static int run(int argc, char *argv[]) {
12,880✔
140
        _cleanup_fdset_free_ FDSet *fdset = NULL;
36✔
141
        _cleanup_(cgroup_context_done) CGroupContext cgroup_context = {};
36✔
142
        _cleanup_(exec_context_done) ExecContext context = {};
36✔
143
        _cleanup_(exec_command_done) ExecCommand command = {};
36✔
144
        _cleanup_(exec_params_deep_clear) ExecParameters params = EXEC_PARAMETERS_INIT(/* flags= */ 0);
36✔
145
        _cleanup_(exec_shared_runtime_done) ExecSharedRuntime shared = {
36✔
146
                .userns_storage_socket = EBADF_PAIR,
147
                .netns_storage_socket = EBADF_PAIR,
148
                .ipcns_storage_socket = EBADF_PAIR,
149
        };
150
        _cleanup_(dynamic_creds_done) DynamicCreds dynamic_creds = {};
36✔
151
        _cleanup_(exec_runtime_clear) ExecRuntime runtime = {
36✔
152
                .ephemeral_storage_socket = EBADF_PAIR,
153
                .shared = &shared,
154
                .dynamic_creds = &dynamic_creds,
155
        };
156
        int exit_status = EXIT_SUCCESS, r;
12,880✔
157

158
        exec_context_init(&context);
12,880✔
159
        cgroup_context_init(&cgroup_context);
12,880✔
160

161
        /* We might be starting the journal itself, we'll be told by the caller what to do */
162
        log_set_prohibit_ipc(true);
12,880✔
163
        log_setup();
12,880✔
164

165
        r = parse_argv(argc, argv);
12,880✔
166
        if (r <= 0)
12,880✔
167
                return r;
168

169
        /* Now that we know the intended log target, allow IPC and open the final log target. */
170
        log_set_always_reopen_console(true);
12,880✔
171
        log_set_prohibit_ipc(false);
12,880✔
172
        log_open();
12,880✔
173

174
        /* Clear ambient capabilities, so services do not inherit them implicitly. Dropping them does
175
         * not affect the permitted and effective sets which are important for the executor itself to
176
         * operate. */
177
        r = capability_ambient_set_apply(0, /* also_inherit= */ false);
12,880✔
178
        if (r < 0)
12,880✔
179
                log_warning_errno(r, "Failed to clear ambient capabilities, ignoring: %m");
×
180

181
        /* This call would collect all passed fds and enable CLOEXEC. We'll unset it in exec_invoke (flag_fds)
182
         * for fds that shall be passed to the child.
183
         * The serialization fd is set to CLOEXEC in parse_argv, so it's also filtered. */
184
        r = fdset_new_fill(/* filter_cloexec= */ 0, &fdset);
12,880✔
185
        if (r < 0)
12,880✔
186
                return log_error_errno(r, "Failed to create fd set: %m");
×
187

188
        /* Initialize lazily. SMACK is just a few operations, but the SELinux is very slow as it requires
189
         * loading the entire database in memory, so we will do it lazily only if it is actually needed, to
190
         * avoid wasting 2ms-10ms for each sd-executor that gets spawned. */
191
        r = mac_init_lazy();
12,880✔
192
        if (r < 0)
12,880✔
193
                return log_error_errno(r, "Failed to initialize MAC layer: %m");
×
194

195
        r = exec_deserialize_invocation(arg_serialization,
12,880✔
196
                                        fdset,
197
                                        &context,
198
                                        &command,
199
                                        &params,
200
                                        &runtime,
201
                                        &cgroup_context);
202
        if (r < 0)
12,880✔
203
                return log_error_errno(r, "Failed to deserialize: %m");
×
204

205
        LOG_CONTEXT_PUSH_EXEC(&context, &params);
37,096✔
206

207
        arg_serialization = safe_fclose(arg_serialization);
12,880✔
208
        fdset = fdset_free(fdset);
12,880✔
209

210
        r = exec_invoke(&command,
12,880✔
211
                        &context,
212
                        &params,
213
                        &runtime,
214
                        &cgroup_context,
215
                        &exit_status);
216
        if (r < 0) {
36✔
217
                const char *status = ASSERT_PTR(
35✔
218
                                exit_status_to_string(exit_status, EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD));
219

220
                log_struct_errno(LOG_ERR, r,
35✔
221
                                 LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED_STR),
222
                                 LOG_EXEC_MESSAGE(&params, "Failed at step %s spawning %s: %m",
223
                                                  status, command.path),
224
                                 LOG_ITEM("EXECUTABLE=%s", command.path));
225
        } else
226
                /* r == 0: 'skip' is chosen in the confirm spawn prompt
227
                 * r > 0:  expected/ignored failure, do not log at error level */
228
                assert((r == 0) == (exit_status == EXIT_SUCCESS));
1✔
229

230
        return exit_status;
36✔
231
}
232

233
int run_executor(int argc, char *argv[]) {
12,880✔
234
        int r;
12,880✔
235

236
        LIBACL_NOTE(recommended);
12,880✔
237
        LIBAPPARMOR_NOTE(recommended);
12,880✔
238
        LIBBLKID_NOTE(recommended);
12,880✔
239
        LIBSELINUX_NOTE(recommended);
12,880✔
240
        TPM2_NOTE(suggested);
12,880✔
241

242
        /* We use safe_fork() for spawning sd-pam helper process, which internally calls rename_process().
243
         * As the last step of renaming, all saved argvs are memzero()-ed. Hence, we need to save the argv
244
         * first to prevent showing "intense" cmdline. See #30352. */
245
        save_argc_argv(argc, argv);
12,880✔
246

247
        r = run(argc, argv);
12,880✔
248

249
        mac_selinux_finish();
36✔
250
        static_destruct();
36✔
251

252
        return r < 0 ? EXIT_FAILURE : r;
36✔
253
}
254

255
#if !SYSTEMD_MULTICALL_BINARY
256
_alias_(run_executor) main;
257
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc