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

systemd / systemd / 15199265962

22 May 2025 09:40PM UTC coverage: 72.061% (-0.02%) from 72.079%
15199265962

push

github

bluca
tests: fix TEST-74-AUX-UTILS.varlinkctl.sh (#37562)

per Daan's explanation:
other subtests running as testuser apparently use systemd-run --user
--machine testuser@.host which turns user tracking in logind into "by
pin" mode. when the last pinning session exits it terminates the user.

299156 of 415145 relevant lines covered (72.06%)

703915.84 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 <stdlib.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.h"
16
#include "execute-serialize.h"
17
#include "exit-status.h"
18
#include "fd-util.h"
19
#include "fdset.h"
20
#include "fileio.h"
21
#include "getopt-defs.h"
22
#include "label-util.h"
23
#include "log.h"
24
#include "parse-util.h"
25
#include "pretty-print.h"
26
#include "selinux-util.h"
27
#include "static-destruct.h"
28

29
static FILE *arg_serialization = NULL;
30

31
STATIC_DESTRUCTOR_REGISTER(arg_serialization, fclosep);
28✔
32

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

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

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

61
        return 0;
62
}
63

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

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

83
        int c, r;
11,579✔
84

85
        assert(argc >= 0);
11,579✔
86
        assert(argv);
11,579✔
87

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

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

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

101
                        break;
102

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

108
                        break;
109

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

118
                        break;
119

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

128
                        break;
129

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

138
                        break;
139

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

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

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

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

160
                        safe_fclose(arg_serialization);
11,579✔
161
                        arg_serialization = f;
11,579✔
162

163
                        break;
11,579✔
164
                }
165

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

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

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

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

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

197
        exec_context_init(&context);
11,579✔
198
        cgroup_context_init(&cgroup_context);
11,579✔
199

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

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

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

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

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

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

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

244
        LOG_CONTEXT_PUSH_EXEC(&context, &params);
33,153✔
245

246
        arg_serialization = safe_fclose(arg_serialization);
11,579✔
247
        fdset = fdset_free(fdset);
11,579✔
248

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

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

269
        return exit_status;
28✔
270
}
271

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

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

280
        r = run(argc, argv);
11,579✔
281

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

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