]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/execute.c
dev-setup: normalize logging around lock_dev_console()
[thirdparty/systemd.git] / src / core / execute.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
a7334b09 2
034c6ed7
LP
3#include <errno.h>
4#include <fcntl.h>
8dd4c05b 5#include <poll.h>
ac8db36c 6#include <sys/file.h>
f3e43635 7#include <sys/mman.h>
8dd4c05b 8#include <sys/personality.h>
94f04347 9#include <sys/prctl.h>
d2ffa389 10#include <sys/shm.h>
d2ffa389 11#include <sys/types.h>
8dd4c05b
LP
12#include <sys/un.h>
13#include <unistd.h>
023a4f67 14#include <utmpx.h>
5cb5a6ff 15
9c0c6701
DDM
16#include <linux/fs.h> /* Must be included after <sys/mount.h> */
17
24882e06 18#include "sd-messages.h"
8dd4c05b
LP
19
20#include "af-list.h"
b5efdb8a 21#include "alloc-util.h"
8dd4c05b 22#include "async.h"
8dd4c05b 23#include "cap-list.h"
430f0182 24#include "capability-util.h"
fdb3deca 25#include "cgroup-setup.h"
28db6fbf 26#include "constants.h"
da681e1b 27#include "cpu-set-util.h"
af189d7b 28#include "dev-setup.h"
686d13b9 29#include "env-file.h"
4d1a6904 30#include "env-util.h"
17df7223 31#include "errno-list.h"
8a62620e 32#include "escape.h"
43962c30 33#include "exec-credential.h"
3ffd4af2 34#include "execute.h"
bb5232b6 35#include "execute-serialize.h"
8dd4c05b 36#include "exit-status.h"
3ffd4af2 37#include "fd-util.h"
154eb43f 38#include "fileio.h"
f97b34a6 39#include "format-util.h"
7d50b32a 40#include "glob-util.h"
0389f4fa 41#include "hexdecoct.h"
032b3afb 42#include "ioprio-util.h"
9c0c6701 43#include "lock-util.h"
8dd4c05b
LP
44#include "log.h"
45#include "macro.h"
e8a565cb 46#include "manager.h"
2a341bb9 47#include "manager-dump.h"
0a970718 48#include "memory-util.h"
f5947a5e 49#include "missing_fs.h"
7a114ed4 50#include "missing_prctl.h"
35cd0ba5 51#include "mkdir-label.h"
8dd4c05b 52#include "namespace.h"
6bedfcbb 53#include "parse-util.h"
8dd4c05b 54#include "path-util.h"
0b452006 55#include "process-util.h"
78f22b97 56#include "rlimit-util.h"
8dd4c05b 57#include "rm-rf.h"
3ffd4af2 58#include "seccomp-util.h"
07d46372 59#include "securebits-util.h"
8dd4c05b 60#include "selinux-util.h"
bb5232b6 61#include "serialize.h"
a2ab603c 62#include "sort-util.h"
fd63e712 63#include "special.h"
949befd3 64#include "stat-util.h"
8b43440b 65#include "string-table.h"
07630cea 66#include "string-util.h"
8dd4c05b 67#include "strv.h"
7ccbd1ae 68#include "syslog-util.h"
8dd4c05b 69#include "terminal-util.h"
bb0c0d6f 70#include "tmpfile-util.h"
566b7d23 71#include "umask-util.h"
2d3b784d 72#include "unit-serialize.h"
b1d4f8e1 73#include "user-util.h"
8dd4c05b 74#include "utmp-wtmp.h"
5cb5a6ff 75
43efbc39
LB
76static bool is_terminal_input(ExecInput i) {
77 return IN_SET(i,
78 EXEC_INPUT_TTY,
79 EXEC_INPUT_TTY_FORCE,
80 EXEC_INPUT_TTY_FAIL);
81}
82
83static bool is_terminal_output(ExecOutput o) {
84 return IN_SET(o,
85 EXEC_OUTPUT_TTY,
86 EXEC_OUTPUT_KMSG_AND_CONSOLE,
87 EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
88}
89
75689fb2 90const char *exec_context_tty_path(const ExecContext *context) {
80876c20
LP
91 assert(context);
92
1e22b5cd
LP
93 if (context->stdio_as_fds)
94 return NULL;
95
80876c20
LP
96 if (context->tty_path)
97 return context->tty_path;
98
99 return "/dev/console";
100}
101
d2b9e755
LP
102static void exec_context_determine_tty_size(
103 const ExecContext *context,
104 const char *tty_path,
105 unsigned *ret_rows,
106 unsigned *ret_cols) {
107
4d62ee55 108 unsigned rows, cols;
4d62ee55
DDM
109
110 assert(context);
111 assert(ret_rows);
112 assert(ret_cols);
113
d2b9e755
LP
114 if (!tty_path)
115 tty_path = exec_context_tty_path(context);
116
4d62ee55
DDM
117 rows = context->tty_rows;
118 cols = context->tty_cols;
119
d2b9e755
LP
120 if (tty_path && (rows == UINT_MAX || cols == UINT_MAX))
121 (void) proc_cmdline_tty_size(
122 tty_path,
123 rows == UINT_MAX ? &rows : NULL,
124 cols == UINT_MAX ? &cols : NULL);
4d62ee55
DDM
125
126 *ret_rows = rows;
127 *ret_cols = cols;
4d62ee55
DDM
128}
129
d2b9e755
LP
130int exec_context_apply_tty_size(
131 const ExecContext *context,
132 int tty_fd,
133 const char *tty_path) {
134
135 unsigned rows, cols;
136
137 exec_context_determine_tty_size(context, tty_path, &rows, &cols);
138
139 return terminal_set_size_fd(tty_fd, tty_path, rows, cols);
140 }
141
75689fb2 142void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p) {
af189d7b 143 _cleanup_close_ int _fd = -EBADF, lock_fd = -EBADF;
af189d7b 144 int fd;
1e22b5cd 145
adabcbab
LP
146 assert(context);
147
148 const char *path = exec_context_tty_path(context);
149
dd9c8da8 150 if (p && p->stdin_fd >= 0 && isatty_safe(p->stdin_fd))
af189d7b 151 fd = p->stdin_fd;
43efbc39
LB
152 else if (path && (context->tty_path || is_terminal_input(context->std_input) ||
153 is_terminal_output(context->std_output) || is_terminal_output(context->std_error))) {
af189d7b 154 fd = _fd = open_terminal(path, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
75689fb2 155 if (fd < 0)
adabcbab 156 return (void) log_debug_errno(fd, "Failed to open terminal '%s', ignoring: %m", path);
75689fb2
LB
157 } else
158 return; /* nothing to do */
b83d5050 159
af189d7b 160 /* Take a synchronization lock for the duration of the setup that we do here.
adabcbab
LP
161 * systemd-vconsole-setup.service also takes the lock to avoid being interrupted. We open a new fd
162 * that will be closed automatically, and operate on it for convenience. */
af189d7b 163 lock_fd = lock_dev_console();
f121efd3
LP
164 if (ERRNO_IS_NEG_PRIVILEGE(lock_fd))
165 log_debug_errno(lock_fd, "No privileges to lock /dev/console, proceeding without: %m");
166 else if (lock_fd < 0)
167 return (void) log_debug_errno(lock_fd, "Failed to lock /dev/console: %m");
af189d7b 168
75689fb2
LB
169 if (context->tty_vhangup)
170 (void) terminal_vhangup_fd(fd);
49590d67 171
75689fb2 172 if (context->tty_reset)
29ed1f02 173 (void) reset_terminal_fd(fd, /* switch_to_text= */ true);
49590d67 174
c34eaeb5 175 (void) exec_context_apply_tty_size(context, fd, path);
e66cf1a3 176
75689fb2
LB
177 if (context->tty_vt_disallocate && path)
178 (void) vt_disallocate(path);
179}
e66cf1a3 180
75689fb2
LB
181bool exec_needs_network_namespace(const ExecContext *context) {
182 assert(context);
37ac2744 183
75689fb2
LB
184 return context->private_network || context->network_namespace_path;
185}
3b8bddde 186
75689fb2
LB
187static bool exec_needs_ephemeral(const ExecContext *context) {
188 return (context->root_image || context->root_directory) && context->root_ephemeral;
189}
755d4b67 190
75689fb2
LB
191bool exec_needs_ipc_namespace(const ExecContext *context) {
192 assert(context);
fa97f630 193
75689fb2
LB
194 return context->private_ipc || context->ipc_namespace_path;
195}
165a31c0 196
75689fb2
LB
197bool exec_needs_mount_namespace(
198 const ExecContext *context,
199 const ExecParameters *params,
200 const ExecRuntime *runtime) {
755d4b67 201
75689fb2 202 assert(context);
d35fbf6b 203
75689fb2
LB
204 if (context->root_image)
205 return true;
5cd9cd35 206
75689fb2
LB
207 if (!strv_isempty(context->read_write_paths) ||
208 !strv_isempty(context->read_only_paths) ||
209 !strv_isempty(context->inaccessible_paths) ||
210 !strv_isempty(context->exec_paths) ||
211 !strv_isempty(context->no_exec_paths))
212 return true;
5cd9cd35 213
75689fb2
LB
214 if (context->n_bind_mounts > 0)
215 return true;
5b6319dc 216
75689fb2
LB
217 if (context->n_temporary_filesystems > 0)
218 return true;
d35fbf6b 219
75689fb2
LB
220 if (context->n_mount_images > 0)
221 return true;
04aa0cb9 222
75689fb2
LB
223 if (context->n_extension_images > 0)
224 return true;
f4170c67 225
75689fb2
LB
226 if (!strv_isempty(context->extension_directories))
227 return true;
f4170c67 228
75689fb2
LB
229 if (!IN_SET(context->mount_propagation_flag, 0, MS_SHARED))
230 return true;
f69567cb 231
75689fb2
LB
232 if (context->private_tmp && runtime && runtime->shared && (runtime->shared->tmp_dir || runtime->shared->var_tmp_dir))
233 return true;
add00535 234
75689fb2
LB
235 if (context->private_devices ||
236 context->private_mounts > 0 ||
237 (context->private_mounts < 0 && exec_needs_network_namespace(context)) ||
238 context->protect_system != PROTECT_SYSTEM_NO ||
239 context->protect_home != PROTECT_HOME_NO ||
240 context->protect_kernel_tunables ||
241 context->protect_kernel_modules ||
242 context->protect_kernel_logs ||
243 context->protect_control_groups ||
244 context->protect_proc != PROTECT_PROC_DEFAULT ||
245 context->proc_subset != PROC_SUBSET_ALL ||
246 exec_needs_ipc_namespace(context))
247 return true;
502d704e 248
75689fb2
LB
249 if (context->root_directory) {
250 if (exec_context_get_effective_mount_apivfs(context))
251 return true;
59eeb84b 252
75689fb2
LB
253 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
254 if (params && !params->prefix[t])
255 continue;
84703040 256
75689fb2
LB
257 if (context->directories[t].n_items > 0)
258 return true;
fc64760d 259 }
75689fb2 260 }
fc64760d 261
75689fb2
LB
262 if (context->dynamic_user &&
263 (context->directories[EXEC_DIRECTORY_STATE].n_items > 0 ||
264 context->directories[EXEC_DIRECTORY_CACHE].n_items > 0 ||
265 context->directories[EXEC_DIRECTORY_LOGS].n_items > 0))
266 return true;
469830d1 267
75689fb2
LB
268 if (context->log_namespace)
269 return true;
ba128bb8 270
75689fb2
LB
271 return false;
272}
78e864e5 273
75689fb2
LB
274bool exec_directory_is_private(const ExecContext *context, ExecDirectoryType type) {
275 assert(context);
9df2cdd8 276
75689fb2
LB
277 if (!context->dynamic_user)
278 return false;
b1994387 279
75689fb2
LB
280 if (type == EXEC_DIRECTORY_CONFIGURATION)
281 return false;
b1994387 282
75689fb2
LB
283 if (type == EXEC_DIRECTORY_RUNTIME && context->runtime_directory_preserve_mode == EXEC_PRESERVE_NO)
284 return false;
034c6ed7 285
75689fb2
LB
286 return true;
287}
00819cc1 288
75689fb2
LB
289int exec_params_get_cgroup_path(
290 const ExecParameters *params,
291 const CGroupContext *c,
292 char **ret) {
00819cc1 293
75689fb2
LB
294 const char *subgroup = NULL;
295 char *p;
00819cc1 296
75689fb2
LB
297 assert(params);
298 assert(ret);
f331434d 299
75689fb2
LB
300 if (!params->cgroup_path)
301 return -EINVAL;
f331434d 302
75689fb2
LB
303 /* If we are called for a unit where cgroup delegation is on, and the payload created its own populated
304 * subcgroup (which we expect it to do, after all it asked for delegation), then we cannot place the control
305 * processes started after the main unit's process in the unit's main cgroup because it is now an inner one,
306 * and inner cgroups may not contain processes. Hence, if delegation is on, and this is a control process,
307 * let's use ".control" as subcgroup instead. Note that we do so only for ExecStartPost=, ExecReload=,
308 * ExecStop=, ExecStopPost=, i.e. for the commands where the main process is already forked. For ExecStartPre=
309 * this is not necessary, the cgroup is still empty. We distinguish these cases with the EXEC_CONTROL_CGROUP
310 * flag, which is only passed for the former statements, not for the latter. */
034c6ed7 311
75689fb2
LB
312 if (FLAGS_SET(params->flags, EXEC_CGROUP_DELEGATE) && (FLAGS_SET(params->flags, EXEC_CONTROL_CGROUP) || c->delegate_subgroup)) {
313 if (FLAGS_SET(params->flags, EXEC_IS_CONTROL))
314 subgroup = ".control";
315 else
316 subgroup = c->delegate_subgroup;
317 }
dd305ec9 318
75689fb2
LB
319 if (subgroup)
320 p = path_join(params->cgroup_path, subgroup);
321 else
322 p = strdup(params->cgroup_path);
323 if (!p)
324 return -ENOMEM;
5686391b 325
75689fb2
LB
326 *ret = p;
327 return !!subgroup;
328}
5686391b 329
75689fb2
LB
330bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
331 assert(c);
5686391b 332
75689fb2
LB
333 return c->cpu_affinity_from_numa;
334}
5686391b 335
75689fb2
LB
336static void log_command_line(Unit *unit, const char *msg, const char *executable, char **argv) {
337 assert(unit);
338 assert(msg);
339 assert(executable);
5686391b 340
75689fb2
LB
341 if (!DEBUG_LOGGING)
342 return;
5686391b 343
75689fb2 344 _cleanup_free_ char *cmdline = quote_command_line(argv, SHELL_ESCAPE_EMPTY);
12145637 345
75689fb2
LB
346 log_unit_struct(unit, LOG_DEBUG,
347 "EXECUTABLE=%s", executable,
348 LOG_UNIT_MESSAGE(unit, "%s: %s", msg, strnull(cmdline)),
349 LOG_UNIT_INVOCATION_ID(unit));
d35fbf6b 350}
81a2b7ce 351
75689fb2
LB
352static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
353
f2341e0a
LP
354int exec_spawn(Unit *unit,
355 ExecCommand *command,
d35fbf6b 356 const ExecContext *context,
154eb43f 357 ExecParameters *params,
28135da3 358 ExecRuntime *runtime,
6bb00842 359 const CGroupContext *cgroup_context,
556d2bc4 360 PidRef *ret) {
8351ceae 361
bb5232b6
LB
362 char serialization_fd_number[DECIMAL_STR_MAX(int) + 1];
363 _cleanup_free_ char *subcgroup_path = NULL, *log_level = NULL, *executor_path = NULL;
556d2bc4 364 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
bb5232b6
LB
365 _cleanup_fdset_free_ FDSet *fdset = NULL;
366 _cleanup_fclose_ FILE *f = NULL;
154eb43f 367 int r;
8351ceae 368
f2341e0a 369 assert(unit);
154eb43f 370 assert(unit->manager);
bb5232b6 371 assert(unit->manager->executor_fd >= 0);
d35fbf6b
DM
372 assert(command);
373 assert(context);
d35fbf6b 374 assert(params);
25b583d7 375 assert(params->fds || (params->n_socket_fds + params->n_storage_fds <= 0));
b646fc32 376 assert(!params->files_env); /* We fill this field, ensure it comes NULL-initialized to us */
c9033540 377 assert(ret);
4298d0b5 378
4b2af439
DDM
379 LOG_CONTEXT_PUSH_UNIT(unit);
380
154eb43f 381 r = exec_context_load_environment(unit, context, &params->files_env);
ff0af2a1 382 if (r < 0)
f2341e0a 383 return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
034c6ed7 384
3ff67ec4
ZJS
385 /* We won't know the real executable path until we create the mount namespace in the child, but we
386 want to log from the parent, so we use the possibly inaccurate path here. */
75689fb2 387 log_command_line(unit, "About to execute", command->path, command->argv);
12145637 388
78f93209 389 if (params->cgroup_path) {
75689fb2 390 r = exec_params_get_cgroup_path(params, cgroup_context, &subcgroup_path);
78f93209
LP
391 if (r < 0)
392 return log_unit_error_errno(unit, r, "Failed to acquire subcgroup path: %m");
18c1e481
LP
393 if (r > 0) {
394 /* If there's a subcgroup, then let's create it here now (the main cgroup was already
395 * realized by the unit logic) */
396
78f93209
LP
397 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path);
398 if (r < 0)
a8b993dc 399 return log_unit_error_errno(unit, r, "Failed to create subcgroup '%s': %m", subcgroup_path);
78f93209
LP
400 }
401 }
402
bb5232b6
LB
403 /* In order to avoid copy-on-write traps and OOM-kills when pid1's memory.current is above the
404 * child's memory.max, serialize all the state needed to start the unit, and pass it to the
405 * systemd-executor binary. clone() with CLONE_VM + CLONE_VFORK will pause the parent until the exec
406 * and ensure all memory is shared. The child immediately execs the new binary so the delay should
2e106312
LB
407 * be minimal. If glibc 2.39 is available pidfd_spawn() is used in order to get a race-free pid fd
408 * and to clone directly into the target cgroup (if we booted with cgroupv2). */
d35fbf6b 409
bb5232b6
LB
410 r = open_serialization_file("sd-executor-state", &f);
411 if (r < 0)
412 return log_unit_error_errno(unit, r, "Failed to open serialization stream: %m");
ff0af2a1 413
bb5232b6
LB
414 fdset = fdset_new();
415 if (!fdset)
416 return log_oom();
12145637 417
bb5232b6
LB
418 r = exec_serialize_invocation(f, fdset, context, command, params, runtime, cgroup_context);
419 if (r < 0)
420 return log_unit_error_errno(unit, r, "Failed to serialize parameters: %m");
e1714f02 421
86cbbc6d 422 if (fseeko(f, 0, SEEK_SET) < 0)
bb5232b6 423 return log_unit_error_errno(unit, errno, "Failed to reseek on serialization stream: %m");
4c2630eb 424
bb5232b6
LB
425 r = fd_cloexec(fileno(f), false);
426 if (r < 0)
427 return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialization fd: %m");
428
429 r = fdset_cloexec(fdset, false);
430 if (r < 0)
431 return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialized fds: %m");
432
36013380
YW
433 /* If LogLevelMax= is specified, then let's use the specified log level at the beginning of the
434 * executor process. To achieve that the specified log level is passed as an argument, rather than
435 * the one for the manager process. */
436 r = log_level_to_string_alloc(context->log_level_max >= 0 ? context->log_level_max : log_get_max_level(), &log_level);
bb5232b6
LB
437 if (r < 0)
438 return log_unit_error_errno(unit, r, "Failed to convert log level to string: %m");
439
440 r = fd_get_path(unit->manager->executor_fd, &executor_path);
441 if (r < 0)
442 return log_unit_error_errno(unit, r, "Failed to get executor path from fd: %m");
443
444 xsprintf(serialization_fd_number, "%i", fileno(f));
445
446 /* The executor binary is pinned, to avoid compatibility problems during upgrades. */
4520681d
MY
447 r = posix_spawn_wrapper(
448 FORMAT_PROC_FD_PATH(unit->manager->executor_fd),
bb5232b6
LB
449 STRV_MAKE(executor_path,
450 "--deserialize", serialization_fd_number,
451 "--log-level", log_level,
452 "--log-target", log_target_to_string(manager_get_executor_log_target(unit->manager))),
453 environ,
2e106312 454 cg_unified() > 0 ? subcgroup_path : NULL,
556d2bc4 455 &pidref);
bb5232b6
LB
456 if (r < 0)
457 return log_unit_error_errno(unit, r, "Failed to spawn executor: %m");
78f93209
LP
458 /* We add the new process to the cgroup both in the child (so that we can be sure that no user code is ever
459 * executed outside of the cgroup) and in the parent (so that we can be sure that when we kill the cgroup the
460 * process will be killed too). */
c9033540 461 if (r == 0 && subcgroup_path)
556d2bc4 462 (void) cg_attach(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path, pidref.pid);
c9033540
MY
463 /* r > 0: Already in the right cgroup thanks to CLONE_INTO_CGROUP */
464
465 log_unit_debug(unit, "Forked %s as " PID_FMT " (%s CLONE_INTO_CGROUP)",
466 command->path, pidref.pid, r > 0 ? "via" : "without");
2da3263a 467
556d2bc4 468 exec_status_start(&command->exec_status, pidref.pid);
9fb86720 469
556d2bc4 470 *ret = TAKE_PIDREF(pidref);
5cb5a6ff
LP
471 return 0;
472}
473
034c6ed7
LP
474void exec_context_init(ExecContext *c) {
475 assert(c);
476
154eb43f
LB
477 /* When initializing a bool member to 'true', make sure to serialize in execute-serialize.c using
478 * serialize_bool() instead of serialize_bool_elide(). */
479
02131627
LB
480 *c = (ExecContext) {
481 .umask = 0022,
482 .ioprio = IOPRIO_DEFAULT_CLASS_AND_PRIO,
483 .cpu_sched_policy = SCHED_OTHER,
484 .syslog_priority = LOG_DAEMON|LOG_INFO,
485 .syslog_level_prefix = true,
486 .ignore_sigpipe = true,
487 .timer_slack_nsec = NSEC_INFINITY,
488 .personality = PERSONALITY_INVALID,
489 .timeout_clean_usec = USEC_INFINITY,
490 .capability_bounding_set = CAP_MASK_UNSET,
491 .restrict_namespaces = NAMESPACE_FLAGS_INITIAL,
492 .log_level_max = -1,
005bfaf1 493#if HAVE_SECCOMP
02131627 494 .syscall_errno = SECCOMP_ERROR_NUMBER_KILL,
005bfaf1 495#endif
02131627
LB
496 .tty_rows = UINT_MAX,
497 .tty_cols = UINT_MAX,
498 .private_mounts = -1,
499 .memory_ksm = -1,
854eca4a 500 .set_login_environment = -1,
02131627
LB
501 };
502
59026bcc
MY
503 FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
504 d->mode = 0755;
02131627 505
b070c7c0 506 numa_policy_reset(&c->numa_policy);
02131627
LB
507
508 assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
034c6ed7
LP
509}
510
613b411c 511void exec_context_done(ExecContext *c) {
5cb5a6ff
LP
512 assert(c);
513
6796073e
LP
514 c->environment = strv_free(c->environment);
515 c->environment_files = strv_free(c->environment_files);
b4c14404 516 c->pass_environment = strv_free(c->pass_environment);
00819cc1 517 c->unset_environment = strv_free(c->unset_environment);
8c7be95e 518
31ce987c 519 rlimit_free_all(c->rlimit);
034c6ed7 520
5b10116e 521 for (size_t l = 0; l < 3; l++) {
52c239d7 522 c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
2038c3f5
LP
523 c->stdio_file[l] = mfree(c->stdio_file[l]);
524 }
52c239d7 525
a1e58e8e
LP
526 c->working_directory = mfree(c->working_directory);
527 c->root_directory = mfree(c->root_directory);
915e6d16 528 c->root_image = mfree(c->root_image);
18d73705 529 c->root_image_options = mount_options_free_all(c->root_image_options);
0389f4fa
LB
530 c->root_hash = mfree(c->root_hash);
531 c->root_hash_size = 0;
532 c->root_hash_path = mfree(c->root_hash_path);
d4d55b0d
LB
533 c->root_hash_sig = mfree(c->root_hash_sig);
534 c->root_hash_sig_size = 0;
535 c->root_hash_sig_path = mfree(c->root_hash_sig_path);
0389f4fa 536 c->root_verity = mfree(c->root_verity);
93f59701 537 c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
a07b9926 538 c->extension_directories = strv_free(c->extension_directories);
a1e58e8e
LP
539 c->tty_path = mfree(c->tty_path);
540 c->syslog_identifier = mfree(c->syslog_identifier);
541 c->user = mfree(c->user);
542 c->group = mfree(c->group);
034c6ed7 543
6796073e 544 c->supplementary_groups = strv_free(c->supplementary_groups);
94f04347 545
a1e58e8e 546 c->pam_name = mfree(c->pam_name);
5b6319dc 547
2a624c36
AP
548 c->read_only_paths = strv_free(c->read_only_paths);
549 c->read_write_paths = strv_free(c->read_write_paths);
550 c->inaccessible_paths = strv_free(c->inaccessible_paths);
ddc155b2
TM
551 c->exec_paths = strv_free(c->exec_paths);
552 c->no_exec_paths = strv_free(c->no_exec_paths);
8c35c10d 553 c->exec_search_path = strv_free(c->exec_search_path);
82c121a4 554
d2d6c096 555 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
8e06d57c
YW
556 c->bind_mounts = NULL;
557 c->n_bind_mounts = 0;
2abd4e38
YW
558 temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
559 c->temporary_filesystems = NULL;
560 c->n_temporary_filesystems = 0;
b3d13314 561 c->mount_images = mount_image_free_many(c->mount_images, &c->n_mount_images);
d2d6c096 562
0985c7c4 563 cpu_set_reset(&c->cpu_set);
b070c7c0 564 numa_policy_reset(&c->numa_policy);
86a3475b 565
a1e58e8e
LP
566 c->utmp_id = mfree(c->utmp_id);
567 c->selinux_context = mfree(c->selinux_context);
568 c->apparmor_profile = mfree(c->apparmor_profile);
5b8e1b77 569 c->smack_process_label = mfree(c->smack_process_label);
eef65bf3 570
9b412709 571 c->restrict_filesystems = set_free_free(c->restrict_filesystems);
b1994387 572
8cfa775f 573 c->syscall_filter = hashmap_free(c->syscall_filter);
525d3cc7
LP
574 c->syscall_archs = set_free(c->syscall_archs);
575 c->address_families = set_free(c->address_families);
e66cf1a3 576
fc932ed4
MY
577 FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
578 exec_directory_done(d);
d3070fbd
LP
579
580 c->log_level_max = -1;
581
582 exec_context_free_log_extra_fields(c);
9b412709
FS
583 c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns);
584 c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns);
08f3be7a 585
5ac1530e
ZJS
586 c->log_ratelimit_interval_usec = 0;
587 c->log_ratelimit_burst = 0;
90fc172e 588
08f3be7a
LP
589 c->stdin_data = mfree(c->stdin_data);
590 c->stdin_data_size = 0;
a8d08f39
LP
591
592 c->network_namespace_path = mfree(c->network_namespace_path);
71d1e583 593 c->ipc_namespace_path = mfree(c->ipc_namespace_path);
91dd5f7c
LP
594
595 c->log_namespace = mfree(c->log_namespace);
bb0c0d6f 596
43144be4 597 c->load_credentials = hashmap_free(c->load_credentials);
bb0c0d6f 598 c->set_credentials = hashmap_free(c->set_credentials);
9b412709 599 c->import_credentials = set_free_free(c->import_credentials);
84be0c71
LP
600
601 c->root_image_policy = image_policy_free(c->root_image_policy);
602 c->mount_image_policy = image_policy_free(c->mount_image_policy);
603 c->extension_image_policy = image_policy_free(c->extension_image_policy);
e66cf1a3
LP
604}
605
34cf6c43 606int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
e66cf1a3
LP
607 assert(c);
608
609 if (!runtime_prefix)
610 return 0;
611
f7df8adb 612 FOREACH_ARRAY(i, c->directories[EXEC_DIRECTORY_RUNTIME].items, c->directories[EXEC_DIRECTORY_RUNTIME].n_items) {
c2b2df60 613 _cleanup_free_ char *p = NULL;
e66cf1a3 614
494d0247 615 if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
f7df8adb 616 p = path_join(runtime_prefix, "private", i->path);
494d0247 617 else
f7df8adb 618 p = path_join(runtime_prefix, i->path);
e66cf1a3
LP
619 if (!p)
620 return -ENOMEM;
621
7bc4bf4a
LP
622 /* We execute this synchronously, since we need to be sure this is gone when we start the
623 * service next. */
c6878637 624 (void) rm_rf(p, REMOVE_ROOT);
211a3d87 625
f7df8adb 626 STRV_FOREACH(symlink, i->symlinks) {
211a3d87
LB
627 _cleanup_free_ char *symlink_abs = NULL;
628
629 if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
630 symlink_abs = path_join(runtime_prefix, "private", *symlink);
631 else
632 symlink_abs = path_join(runtime_prefix, *symlink);
633 if (!symlink_abs)
634 return -ENOMEM;
635
636 (void) unlink(symlink_abs);
637 }
e66cf1a3
LP
638 }
639
640 return 0;
5cb5a6ff
LP
641}
642
b9f976fb
MK
643int exec_context_destroy_mount_ns_dir(Unit *u) {
644 _cleanup_free_ char *p = NULL;
645
646 if (!u || !MANAGER_IS_SYSTEM(u->manager))
647 return 0;
648
649 p = path_join("/run/systemd/propagate/", u->id);
650 if (!p)
651 return -ENOMEM;
652
653 /* This is only filled transiently (see mount_in_namespace()), should be empty or even non-existent*/
654 if (rmdir(p) < 0 && errno != ENOENT)
655 log_unit_debug_errno(u, errno, "Unable to remove propagation dir '%s', ignoring: %m", p);
656
657 return 0;
658}
659
bb5232b6 660void exec_command_done(ExecCommand *c) {
43d0fcbd
LP
661 assert(c);
662
a1e58e8e 663 c->path = mfree(c->path);
6796073e 664 c->argv = strv_free(c->argv);
43d0fcbd
LP
665}
666
da6053d0 667void exec_command_done_array(ExecCommand *c, size_t n) {
f7df8adb
MY
668 FOREACH_ARRAY(i, c, n)
669 exec_command_done(i);
43d0fcbd
LP
670}
671
f1acf85a 672ExecCommand* exec_command_free_list(ExecCommand *c) {
5cb5a6ff
LP
673 ExecCommand *i;
674
52e3671b 675 while ((i = LIST_POP(command, c))) {
43d0fcbd 676 exec_command_done(i);
5cb5a6ff
LP
677 free(i);
678 }
f1acf85a
ZJS
679
680 return NULL;
5cb5a6ff
LP
681}
682
da6053d0 683void exec_command_free_array(ExecCommand **c, size_t n) {
f7df8adb
MY
684 FOREACH_ARRAY(i, c, n)
685 *i = exec_command_free_list(*i);
034c6ed7
LP
686}
687
6a1d4d9f 688void exec_command_reset_status_array(ExecCommand *c, size_t n) {
f7df8adb
MY
689 FOREACH_ARRAY(i, c, n)
690 exec_status_reset(&i->exec_status);
6a1d4d9f
LP
691}
692
693void exec_command_reset_status_list_array(ExecCommand **c, size_t n) {
f7df8adb
MY
694 FOREACH_ARRAY(i, c, n)
695 LIST_FOREACH(command, z, *i)
6a1d4d9f 696 exec_status_reset(&z->exec_status);
6a1d4d9f
LP
697}
698
039f0e70 699typedef struct InvalidEnvInfo {
34cf6c43 700 const Unit *unit;
039f0e70
LP
701 const char *path;
702} InvalidEnvInfo;
703
704static void invalid_env(const char *p, void *userdata) {
705 InvalidEnvInfo *info = userdata;
706
f2341e0a 707 log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path);
039f0e70
LP
708}
709
52c239d7
LB
710const char* exec_context_fdname(const ExecContext *c, int fd_index) {
711 assert(c);
712
713 switch (fd_index) {
5073ff6b 714
52c239d7
LB
715 case STDIN_FILENO:
716 if (c->std_input != EXEC_INPUT_NAMED_FD)
717 return NULL;
5073ff6b 718
52c239d7 719 return c->stdio_fdname[STDIN_FILENO] ?: "stdin";
5073ff6b 720
52c239d7
LB
721 case STDOUT_FILENO:
722 if (c->std_output != EXEC_OUTPUT_NAMED_FD)
723 return NULL;
5073ff6b 724
52c239d7 725 return c->stdio_fdname[STDOUT_FILENO] ?: "stdout";
5073ff6b 726
52c239d7
LB
727 case STDERR_FILENO:
728 if (c->std_error != EXEC_OUTPUT_NAMED_FD)
729 return NULL;
5073ff6b 730
52c239d7 731 return c->stdio_fdname[STDERR_FILENO] ?: "stderr";
5073ff6b 732
52c239d7
LB
733 default:
734 return NULL;
735 }
736}
737
398a5009
ZJS
738static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***ret) {
739 _cleanup_strv_free_ char **v = NULL;
398a5009 740 int r;
8c7be95e
LP
741
742 assert(c);
398a5009 743 assert(ret);
8c7be95e
LP
744
745 STRV_FOREACH(i, c->environment_files) {
7fd1b19b 746 _cleanup_globfree_ glob_t pglob = {};
398a5009
ZJS
747 bool ignore = false;
748 char *fn = *i;
8c7be95e
LP
749
750 if (fn[0] == '-') {
751 ignore = true;
313cefa1 752 fn++;
8c7be95e
LP
753 }
754
755 if (!path_is_absolute(fn)) {
8c7be95e
LP
756 if (ignore)
757 continue;
8c7be95e
LP
758 return -EINVAL;
759 }
760
2bef10ab 761 /* Filename supports globbing, take all matching files */
398a5009
ZJS
762 r = safe_glob(fn, 0, &pglob);
763 if (r < 0) {
2bef10ab
PL
764 if (ignore)
765 continue;
398a5009 766 return r;
2bef10ab 767 }
8c7be95e 768
d8c92e8b
ZJS
769 /* When we don't match anything, -ENOENT should be returned */
770 assert(pglob.gl_pathc > 0);
771
f7df8adb 772 FOREACH_ARRAY(path, pglob.gl_pathv, pglob.gl_pathc) {
398a5009
ZJS
773 _cleanup_strv_free_ char **p = NULL;
774
f7df8adb 775 r = load_env_file(NULL, *path, &p);
398a5009 776 if (r < 0) {
2bef10ab
PL
777 if (ignore)
778 continue;
398a5009 779 return r;
e9c1ea9d 780 }
398a5009 781
ebc05a09 782 /* Log invalid environment variables with filename */
039f0e70
LP
783 if (p) {
784 InvalidEnvInfo info = {
f2341e0a 785 .unit = unit,
f7df8adb 786 .path = *path,
039f0e70
LP
787 };
788
789 p = strv_env_clean_with_callback(p, invalid_env, &info);
790 }
8c7be95e 791
398a5009
ZJS
792 if (!v)
793 v = TAKE_PTR(p);
2bef10ab 794 else {
398a5009 795 char **m = strv_env_merge(v, p);
c84a9488 796 if (!m)
2bef10ab 797 return -ENOMEM;
2bef10ab 798
398a5009 799 strv_free_and_replace(v, m);
2bef10ab 800 }
8c7be95e
LP
801 }
802 }
803
398a5009 804 *ret = TAKE_PTR(v);
8c7be95e
LP
805
806 return 0;
807}
808
6ac8fdc9 809static bool tty_may_match_dev_console(const char *tty) {
7b912648 810 _cleanup_free_ char *resolved = NULL;
6ac8fdc9 811
1e22b5cd
LP
812 if (!tty)
813 return true;
814
a119ec7c 815 tty = skip_dev_prefix(tty);
6ac8fdc9
MS
816
817 /* trivial identity? */
818 if (streq(tty, "console"))
819 return true;
820
7b912648
LP
821 if (resolve_dev_console(&resolved) < 0)
822 return true; /* if we could not resolve, assume it may */
6ac8fdc9
MS
823
824 /* "tty0" means the active VC, so it may be the same sometimes */
955f1c85 825 return path_equal(resolved, tty) || (streq(resolved, "tty0") && tty_is_vc(tty));
6ac8fdc9
MS
826}
827
6c0ae739
LP
828static bool exec_context_may_touch_tty(const ExecContext *ec) {
829 assert(ec);
1e22b5cd 830
6c0ae739 831 return ec->tty_reset ||
1e22b5cd
LP
832 ec->tty_vhangup ||
833 ec->tty_vt_disallocate ||
6ac8fdc9
MS
834 is_terminal_input(ec->std_input) ||
835 is_terminal_output(ec->std_output) ||
6c0ae739
LP
836 is_terminal_output(ec->std_error);
837}
838
839bool exec_context_may_touch_console(const ExecContext *ec) {
840
841 return exec_context_may_touch_tty(ec) &&
1e22b5cd 842 tty_may_match_dev_console(exec_context_tty_path(ec));
6ac8fdc9
MS
843}
844
15ae422b 845static void strv_fprintf(FILE *f, char **l) {
15ae422b
LP
846 assert(f);
847
848 STRV_FOREACH(g, l)
849 fprintf(f, " %s", *g);
850}
851
ddc155b2
TM
852static void strv_dump(FILE* f, const char *prefix, const char *name, char **strv) {
853 assert(f);
854 assert(prefix);
855 assert(name);
856
857 if (!strv_isempty(strv)) {
a7bd1656 858 fprintf(f, "%s%s:", prefix, name);
ddc155b2
TM
859 strv_fprintf(f, strv);
860 fputs("\n", f);
861 }
862}
863
97f53fec
LB
864void exec_params_dump(const ExecParameters *p, FILE* f, const char *prefix) {
865 assert(p);
866 assert(f);
867
868 prefix = strempty(prefix);
869
870 fprintf(f,
871 "%sRuntimeScope: %s\n"
872 "%sExecFlags: %u\n"
873 "%sSELinuxContextNetwork: %s\n"
874 "%sCgroupSupportedMask: %u\n"
875 "%sCgroupPath: %s\n"
876 "%sCrededentialsDirectory: %s\n"
877 "%sEncryptedCredentialsDirectory: %s\n"
878 "%sConfirmSpawn: %s\n"
879 "%sShallConfirmSpawn: %s\n"
880 "%sWatchdogUSec: " USEC_FMT "\n"
881 "%sNotifySocket: %s\n"
882 "%sFallbackSmackProcessLabel: %s\n",
883 prefix, runtime_scope_to_string(p->runtime_scope),
884 prefix, p->flags,
885 prefix, yes_no(p->selinux_context_net),
886 prefix, p->cgroup_supported,
887 prefix, p->cgroup_path,
888 prefix, strempty(p->received_credentials_directory),
889 prefix, strempty(p->received_encrypted_credentials_directory),
890 prefix, strempty(p->confirm_spawn),
891 prefix, yes_no(p->shall_confirm_spawn),
892 prefix, p->watchdog_usec,
893 prefix, strempty(p->notify_socket),
894 prefix, strempty(p->fallback_smack_process_label));
895
896 strv_dump(f, prefix, "FdNames", p->fd_names);
897 strv_dump(f, prefix, "Environment", p->environment);
898 strv_dump(f, prefix, "Prefix", p->prefix);
899
900 LIST_FOREACH(open_files, file, p->open_files)
901 fprintf(f, "%sOpenFile: %s %s", prefix, file->path, open_file_flags_to_string(file->flags));
902
903 strv_dump(f, prefix, "FilesEnv", p->files_env);
904}
905
34cf6c43 906void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
add00535 907 int r;
9eba9da4 908
5cb5a6ff
LP
909 assert(c);
910 assert(f);
911
4ad49000 912 prefix = strempty(prefix);
5cb5a6ff
LP
913
914 fprintf(f,
94f04347
LP
915 "%sUMask: %04o\n"
916 "%sWorkingDirectory: %s\n"
451a074f 917 "%sRootDirectory: %s\n"
9c0c6701 918 "%sRootEphemeral: %s\n"
15ae422b 919 "%sNonBlocking: %s\n"
64747e2d 920 "%sPrivateTmp: %s\n"
7f112f50 921 "%sPrivateDevices: %s\n"
59eeb84b 922 "%sProtectKernelTunables: %s\n"
e66a2f65 923 "%sProtectKernelModules: %s\n"
84703040 924 "%sProtectKernelLogs: %s\n"
fc64760d 925 "%sProtectClock: %s\n"
59eeb84b 926 "%sProtectControlGroups: %s\n"
d251207d
LP
927 "%sPrivateNetwork: %s\n"
928 "%sPrivateUsers: %s\n"
1b8689f9
LP
929 "%sProtectHome: %s\n"
930 "%sProtectSystem: %s\n"
5d997827 931 "%sMountAPIVFS: %s\n"
f3e43635 932 "%sIgnoreSIGPIPE: %s\n"
f4170c67 933 "%sMemoryDenyWriteExecute: %s\n"
b1edf445 934 "%sRestrictRealtime: %s\n"
f69567cb 935 "%sRestrictSUIDSGID: %s\n"
aecd5ac6 936 "%sKeyringMode: %s\n"
4e399953
LP
937 "%sProtectHostname: %s\n"
938 "%sProtectProc: %s\n"
939 "%sProcSubset: %s\n",
5cb5a6ff 940 prefix, c->umask,
14eb3285
LP
941 prefix, empty_to_root(c->working_directory),
942 prefix, empty_to_root(c->root_directory),
9c0c6701 943 prefix, yes_no(c->root_ephemeral),
15ae422b 944 prefix, yes_no(c->non_blocking),
64747e2d 945 prefix, yes_no(c->private_tmp),
7f112f50 946 prefix, yes_no(c->private_devices),
59eeb84b 947 prefix, yes_no(c->protect_kernel_tunables),
e66a2f65 948 prefix, yes_no(c->protect_kernel_modules),
84703040 949 prefix, yes_no(c->protect_kernel_logs),
fc64760d 950 prefix, yes_no(c->protect_clock),
59eeb84b 951 prefix, yes_no(c->protect_control_groups),
d251207d
LP
952 prefix, yes_no(c->private_network),
953 prefix, yes_no(c->private_users),
1b8689f9
LP
954 prefix, protect_home_to_string(c->protect_home),
955 prefix, protect_system_to_string(c->protect_system),
5e98086d 956 prefix, yes_no(exec_context_get_effective_mount_apivfs(c)),
f3e43635 957 prefix, yes_no(c->ignore_sigpipe),
f4170c67 958 prefix, yes_no(c->memory_deny_write_execute),
b1edf445 959 prefix, yes_no(c->restrict_realtime),
f69567cb 960 prefix, yes_no(c->restrict_suid_sgid),
aecd5ac6 961 prefix, exec_keyring_mode_to_string(c->keyring_mode),
4e399953
LP
962 prefix, yes_no(c->protect_hostname),
963 prefix, protect_proc_to_string(c->protect_proc),
964 prefix, proc_subset_to_string(c->proc_subset));
fb33a393 965
06120a15
MY
966 if (c->set_login_environment >= 0)
967 fprintf(f, "%sSetLoginEnvironment: %s\n", prefix, yes_no(c->set_login_environment > 0));
968
915e6d16
LP
969 if (c->root_image)
970 fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
971
18d73705 972 if (c->root_image_options) {
18d73705
LB
973 fprintf(f, "%sRootImageOptions:", prefix);
974 LIST_FOREACH(mount_options, o, c->root_image_options)
975 if (!isempty(o->options))
9ece6444
LB
976 fprintf(f, " %s:%s",
977 partition_designator_to_string(o->partition_designator),
978 o->options);
18d73705
LB
979 fprintf(f, "\n");
980 }
981
0389f4fa
LB
982 if (c->root_hash) {
983 _cleanup_free_ char *encoded = NULL;
984 encoded = hexmem(c->root_hash, c->root_hash_size);
985 if (encoded)
986 fprintf(f, "%sRootHash: %s\n", prefix, encoded);
987 }
988
989 if (c->root_hash_path)
990 fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
991
d4d55b0d
LB
992 if (c->root_hash_sig) {
993 _cleanup_free_ char *encoded = NULL;
994 ssize_t len;
995 len = base64mem(c->root_hash_sig, c->root_hash_sig_size, &encoded);
996 if (len)
997 fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded);
998 }
999
1000 if (c->root_hash_sig_path)
1001 fprintf(f, "%sRootHashSignature: %s\n", prefix, c->root_hash_sig_path);
1002
0389f4fa
LB
1003 if (c->root_verity)
1004 fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
1005
8c7be95e
LP
1006 STRV_FOREACH(e, c->environment)
1007 fprintf(f, "%sEnvironment: %s\n", prefix, *e);
1008
1009 STRV_FOREACH(e, c->environment_files)
1010 fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
94f04347 1011
b4c14404
FB
1012 STRV_FOREACH(e, c->pass_environment)
1013 fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
1014
00819cc1
LP
1015 STRV_FOREACH(e, c->unset_environment)
1016 fprintf(f, "%sUnsetEnvironment: %s\n", prefix, *e);
1017
53f47dfc
YW
1018 fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
1019
5b10116e 1020 for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
3536f49e
YW
1021 fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode);
1022
211a3d87
LB
1023 for (size_t i = 0; i < c->directories[dt].n_items; i++) {
1024 fprintf(f, "%s%s: %s\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].items[i].path);
1025
1026 STRV_FOREACH(d, c->directories[dt].items[i].symlinks)
1027 fprintf(f, "%s%s: %s:%s\n", prefix, exec_directory_type_symlink_to_string(dt), c->directories[dt].items[i].path, *d);
1028 }
3536f49e 1029 }
c2bbd90b 1030
5291f26d 1031 fprintf(f, "%sTimeoutCleanSec: %s\n", prefix, FORMAT_TIMESPAN(c->timeout_clean_usec, USEC_PER_SEC));
12213aed 1032
06120a15
MY
1033 if (c->memory_ksm >= 0)
1034 fprintf(f, "%sMemoryKSM: %s\n", prefix, yes_no(c->memory_ksm > 0));
1035
fb33a393 1036 if (c->nice_set)
5291f26d 1037 fprintf(f, "%sNice: %i\n", prefix, c->nice);
fb33a393 1038
dd6c17b1 1039 if (c->oom_score_adjust_set)
5291f26d 1040 fprintf(f, "%sOOMScoreAdjust: %i\n", prefix, c->oom_score_adjust);
9eba9da4 1041
ad21e542 1042 if (c->coredump_filter_set)
5291f26d 1043 fprintf(f, "%sCoredumpFilter: 0x%"PRIx64"\n", prefix, c->coredump_filter);
ad21e542 1044
5b10116e 1045 for (unsigned i = 0; i < RLIM_NLIMITS; i++)
3c11da9d 1046 if (c->rlimit[i]) {
4c3a2b84 1047 fprintf(f, "%sLimit%s: " RLIM_FMT "\n",
3c11da9d 1048 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
4c3a2b84 1049 fprintf(f, "%sLimit%sSoft: " RLIM_FMT "\n",
3c11da9d
EV
1050 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
1051 }
94f04347 1052
f8b69d1d 1053 if (c->ioprio_set) {
1756a011 1054 _cleanup_free_ char *class_str = NULL;
f8b69d1d 1055
5bead76e 1056 r = ioprio_class_to_string_alloc(ioprio_prio_class(c->ioprio), &class_str);
837df140
YW
1057 if (r >= 0)
1058 fprintf(f, "%sIOSchedulingClass: %s\n", prefix, class_str);
1059
5bead76e 1060 fprintf(f, "%sIOPriority: %d\n", prefix, ioprio_prio_data(c->ioprio));
f8b69d1d 1061 }
94f04347 1062
f8b69d1d 1063 if (c->cpu_sched_set) {
1756a011 1064 _cleanup_free_ char *policy_str = NULL;
f8b69d1d 1065
837df140
YW
1066 r = sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
1067 if (r >= 0)
1068 fprintf(f, "%sCPUSchedulingPolicy: %s\n", prefix, policy_str);
1069
94f04347 1070 fprintf(f,
38b48754
LP
1071 "%sCPUSchedulingPriority: %i\n"
1072 "%sCPUSchedulingResetOnFork: %s\n",
38b48754
LP
1073 prefix, c->cpu_sched_priority,
1074 prefix, yes_no(c->cpu_sched_reset_on_fork));
b929bf04 1075 }
94f04347 1076
0985c7c4 1077 if (c->cpu_set.set) {
e7fca352
MS
1078 _cleanup_free_ char *affinity = NULL;
1079
1080 affinity = cpu_set_to_range_string(&c->cpu_set);
1081 fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity);
94f04347
LP
1082 }
1083
b070c7c0
MS
1084 if (mpol_is_valid(numa_policy_get_type(&c->numa_policy))) {
1085 _cleanup_free_ char *nodes = NULL;
1086
1087 nodes = cpu_set_to_range_string(&c->numa_policy.nodes);
1088 fprintf(f, "%sNUMAPolicy: %s\n", prefix, mpol_to_string(numa_policy_get_type(&c->numa_policy)));
1089 fprintf(f, "%sNUMAMask: %s\n", prefix, strnull(nodes));
1090 }
1091
3a43da28 1092 if (c->timer_slack_nsec != NSEC_INFINITY)
ccd06097 1093 fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec);
94f04347
LP
1094
1095 fprintf(f,
80876c20
LP
1096 "%sStandardInput: %s\n"
1097 "%sStandardOutput: %s\n"
1098 "%sStandardError: %s\n",
1099 prefix, exec_input_to_string(c->std_input),
1100 prefix, exec_output_to_string(c->std_output),
1101 prefix, exec_output_to_string(c->std_error));
1102
befc4a80
LP
1103 if (c->std_input == EXEC_INPUT_NAMED_FD)
1104 fprintf(f, "%sStandardInputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDIN_FILENO]);
1105 if (c->std_output == EXEC_OUTPUT_NAMED_FD)
1106 fprintf(f, "%sStandardOutputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDOUT_FILENO]);
1107 if (c->std_error == EXEC_OUTPUT_NAMED_FD)
1108 fprintf(f, "%sStandardErrorFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDERR_FILENO]);
1109
1110 if (c->std_input == EXEC_INPUT_FILE)
1111 fprintf(f, "%sStandardInputFile: %s\n", prefix, c->stdio_file[STDIN_FILENO]);
1112 if (c->std_output == EXEC_OUTPUT_FILE)
1113 fprintf(f, "%sStandardOutputFile: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
566b7d23
ZD
1114 if (c->std_output == EXEC_OUTPUT_FILE_APPEND)
1115 fprintf(f, "%sStandardOutputFileToAppend: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
8d7dab1f
LW
1116 if (c->std_output == EXEC_OUTPUT_FILE_TRUNCATE)
1117 fprintf(f, "%sStandardOutputFileToTruncate: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
befc4a80
LP
1118 if (c->std_error == EXEC_OUTPUT_FILE)
1119 fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
566b7d23
ZD
1120 if (c->std_error == EXEC_OUTPUT_FILE_APPEND)
1121 fprintf(f, "%sStandardErrorFileToAppend: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
8d7dab1f
LW
1122 if (c->std_error == EXEC_OUTPUT_FILE_TRUNCATE)
1123 fprintf(f, "%sStandardErrorFileToTruncate: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
befc4a80 1124
80876c20
LP
1125 if (c->tty_path)
1126 fprintf(f,
6ea832a2
LP
1127 "%sTTYPath: %s\n"
1128 "%sTTYReset: %s\n"
1129 "%sTTYVHangup: %s\n"
51462135
DDM
1130 "%sTTYVTDisallocate: %s\n"
1131 "%sTTYRows: %u\n"
1132 "%sTTYColumns: %u\n",
6ea832a2
LP
1133 prefix, c->tty_path,
1134 prefix, yes_no(c->tty_reset),
1135 prefix, yes_no(c->tty_vhangup),
51462135
DDM
1136 prefix, yes_no(c->tty_vt_disallocate),
1137 prefix, c->tty_rows,
1138 prefix, c->tty_cols);
94f04347 1139
9f6444eb 1140 if (IN_SET(c->std_output,
9f6444eb
LP
1141 EXEC_OUTPUT_KMSG,
1142 EXEC_OUTPUT_JOURNAL,
9f6444eb
LP
1143 EXEC_OUTPUT_KMSG_AND_CONSOLE,
1144 EXEC_OUTPUT_JOURNAL_AND_CONSOLE) ||
1145 IN_SET(c->std_error,
9f6444eb
LP
1146 EXEC_OUTPUT_KMSG,
1147 EXEC_OUTPUT_JOURNAL,
9f6444eb
LP
1148 EXEC_OUTPUT_KMSG_AND_CONSOLE,
1149 EXEC_OUTPUT_JOURNAL_AND_CONSOLE)) {
f8b69d1d 1150
5ce70e5b 1151 _cleanup_free_ char *fac_str = NULL, *lvl_str = NULL;
f8b69d1d 1152
837df140
YW
1153 r = log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
1154 if (r >= 0)
1155 fprintf(f, "%sSyslogFacility: %s\n", prefix, fac_str);
f8b69d1d 1156
837df140
YW
1157 r = log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str);
1158 if (r >= 0)
1159 fprintf(f, "%sSyslogLevel: %s\n", prefix, lvl_str);
f8b69d1d 1160 }
94f04347 1161
d3070fbd
LP
1162 if (c->log_level_max >= 0) {
1163 _cleanup_free_ char *t = NULL;
1164
1165 (void) log_level_to_string_alloc(c->log_level_max, &t);
1166
1167 fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t));
1168 }
1169
5291f26d 1170 if (c->log_ratelimit_interval_usec > 0)
90fc172e
AZ
1171 fprintf(f,
1172 "%sLogRateLimitIntervalSec: %s\n",
5291f26d 1173 prefix, FORMAT_TIMESPAN(c->log_ratelimit_interval_usec, USEC_PER_SEC));
90fc172e 1174
5ac1530e
ZJS
1175 if (c->log_ratelimit_burst > 0)
1176 fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_ratelimit_burst);
90fc172e 1177
523ea123
QD
1178 if (!set_isempty(c->log_filter_allowed_patterns) || !set_isempty(c->log_filter_denied_patterns)) {
1179 fprintf(f, "%sLogFilterPatterns:", prefix);
1180
1181 char *pattern;
1182 SET_FOREACH(pattern, c->log_filter_allowed_patterns)
1183 fprintf(f, " %s", pattern);
1184 SET_FOREACH(pattern, c->log_filter_denied_patterns)
1185 fprintf(f, " ~%s", pattern);
1186 fputc('\n', f);
1187 }
1188
f7df8adb 1189 FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields) {
5b10116e 1190 fprintf(f, "%sLogExtraFields: ", prefix);
f7df8adb 1191 fwrite(field->iov_base, 1, field->iov_len, f);
5b10116e 1192 fputc('\n', f);
d3070fbd
LP
1193 }
1194
91dd5f7c
LP
1195 if (c->log_namespace)
1196 fprintf(f, "%sLogNamespace: %s\n", prefix, c->log_namespace);
1197
07d46372
YW
1198 if (c->secure_bits) {
1199 _cleanup_free_ char *str = NULL;
1200
1201 r = secure_bits_to_string_alloc(c->secure_bits, &str);
1202 if (r >= 0)
1203 fprintf(f, "%sSecure Bits: %s\n", prefix, str);
1204 }
94f04347 1205
3fd5190b 1206 if (c->capability_bounding_set != CAP_MASK_UNSET) {
dd1f5bd0 1207 _cleanup_free_ char *str = NULL;
94f04347 1208
8142d735 1209 r = capability_set_to_string(c->capability_bounding_set, &str);
dd1f5bd0
YW
1210 if (r >= 0)
1211 fprintf(f, "%sCapabilityBoundingSet: %s\n", prefix, str);
755d4b67
IP
1212 }
1213
1214 if (c->capability_ambient_set != 0) {
dd1f5bd0 1215 _cleanup_free_ char *str = NULL;
755d4b67 1216
8142d735 1217 r = capability_set_to_string(c->capability_ambient_set, &str);
dd1f5bd0
YW
1218 if (r >= 0)
1219 fprintf(f, "%sAmbientCapabilities: %s\n", prefix, str);
94f04347
LP
1220 }
1221
1222 if (c->user)
f2d3769a 1223 fprintf(f, "%sUser: %s\n", prefix, c->user);
94f04347 1224 if (c->group)
f2d3769a 1225 fprintf(f, "%sGroup: %s\n", prefix, c->group);
94f04347 1226
29206d46
LP
1227 fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
1228
ddc155b2 1229 strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups);
94f04347 1230
5b6319dc 1231 if (c->pam_name)
f2d3769a 1232 fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
5b6319dc 1233
ddc155b2
TM
1234 strv_dump(f, prefix, "ReadWritePaths", c->read_write_paths);
1235 strv_dump(f, prefix, "ReadOnlyPaths", c->read_only_paths);
1236 strv_dump(f, prefix, "InaccessiblePaths", c->inaccessible_paths);
1237 strv_dump(f, prefix, "ExecPaths", c->exec_paths);
1238 strv_dump(f, prefix, "NoExecPaths", c->no_exec_paths);
8c35c10d 1239 strv_dump(f, prefix, "ExecSearchPath", c->exec_search_path);
2e22afe9 1240
f7df8adb 1241 FOREACH_ARRAY(mount, c->bind_mounts, c->n_bind_mounts)
5b10116e 1242 fprintf(f, "%s%s: %s%s:%s:%s\n", prefix,
f7df8adb
MY
1243 mount->read_only ? "BindReadOnlyPaths" : "BindPaths",
1244 mount->ignore_enoent ? "-": "",
1245 mount->source,
1246 mount->destination,
1247 mount->recursive ? "rbind" : "norbind");
2abd4e38 1248
f7df8adb 1249 FOREACH_ARRAY(tmpfs, c->temporary_filesystems, c->n_temporary_filesystems)
5b10116e 1250 fprintf(f, "%sTemporaryFileSystem: %s%s%s\n", prefix,
f7df8adb
MY
1251 tmpfs->path,
1252 isempty(tmpfs->options) ? "" : ":",
1253 strempty(tmpfs->options));
2abd4e38 1254
169c1bda
LP
1255 if (c->utmp_id)
1256 fprintf(f,
1257 "%sUtmpIdentifier: %s\n",
1258 prefix, c->utmp_id);
7b52a628
MS
1259
1260 if (c->selinux_context)
1261 fprintf(f,
5f8640fb
LP
1262 "%sSELinuxContext: %s%s\n",
1263 prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
17df7223 1264
80c21aea
WC
1265 if (c->apparmor_profile)
1266 fprintf(f,
1267 "%sAppArmorProfile: %s%s\n",
1268 prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
1269
1270 if (c->smack_process_label)
1271 fprintf(f,
1272 "%sSmackProcessLabel: %s%s\n",
1273 prefix, c->smack_process_label_ignore ? "-" : "", c->smack_process_label);
1274
050f7277 1275 if (c->personality != PERSONALITY_INVALID)
ac45f971
LP
1276 fprintf(f,
1277 "%sPersonality: %s\n",
1278 prefix, strna(personality_to_string(c->personality)));
1279
78e864e5
TM
1280 fprintf(f,
1281 "%sLockPersonality: %s\n",
1282 prefix, yes_no(c->lock_personality));
1283
17df7223 1284 if (c->syscall_filter) {
17df7223 1285 fprintf(f,
57183d11 1286 "%sSystemCallFilter: ",
17df7223
LP
1287 prefix);
1288
6b000af4 1289 if (!c->syscall_allow_list)
17df7223
LP
1290 fputc('~', f);
1291
349cc4a5 1292#if HAVE_SECCOMP
d5a99b7c
JJ
1293 void *id, *val;
1294 bool first = true;
90e74a66 1295 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
17df7223 1296 _cleanup_free_ char *name = NULL;
8cfa775f
YW
1297 const char *errno_name = NULL;
1298 int num = PTR_TO_INT(val);
17df7223
LP
1299
1300 if (first)
1301 first = false;
1302 else
1303 fputc(' ', f);
1304
57183d11 1305 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
17df7223 1306 fputs(strna(name), f);
8cfa775f
YW
1307
1308 if (num >= 0) {
005bfaf1 1309 errno_name = seccomp_errno_or_action_to_string(num);
8cfa775f
YW
1310 if (errno_name)
1311 fprintf(f, ":%s", errno_name);
1312 else
1313 fprintf(f, ":%d", num);
1314 }
17df7223 1315 }
351a19b1 1316#endif
17df7223
LP
1317
1318 fputc('\n', f);
1319 }
1320
57183d11 1321 if (c->syscall_archs) {
57183d11
LP
1322 fprintf(f,
1323 "%sSystemCallArchitectures:",
1324 prefix);
1325
349cc4a5 1326#if HAVE_SECCOMP
d5a99b7c 1327 void *id;
90e74a66 1328 SET_FOREACH(id, c->syscall_archs)
57183d11
LP
1329 fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1)));
1330#endif
1331 fputc('\n', f);
1332 }
1333
add00535
LP
1334 if (exec_context_restrict_namespaces_set(c)) {
1335 _cleanup_free_ char *s = NULL;
1336
86c2a9f1 1337 r = namespace_flags_to_string(c->restrict_namespaces, &s);
add00535
LP
1338 if (r >= 0)
1339 fprintf(f, "%sRestrictNamespaces: %s\n",
dd0395b5 1340 prefix, strna(s));
add00535
LP
1341 }
1342
b1994387 1343#if HAVE_LIBBPF
8fe84dc8
YW
1344 if (exec_context_restrict_filesystems_set(c)) {
1345 char *fs;
1346 SET_FOREACH(fs, c->restrict_filesystems)
1347 fprintf(f, "%sRestrictFileSystems: %s\n", prefix, fs);
1348 }
b1994387
ILG
1349#endif
1350
a8d08f39
LP
1351 if (c->network_namespace_path)
1352 fprintf(f,
1353 "%sNetworkNamespacePath: %s\n",
1354 prefix, c->network_namespace_path);
1355
3df90f24 1356 if (c->syscall_errno > 0) {
3df90f24
YW
1357 fprintf(f, "%sSystemCallErrorNumber: ", prefix);
1358
005bfaf1 1359#if HAVE_SECCOMP
d5a99b7c 1360 const char *errno_name = seccomp_errno_or_action_to_string(c->syscall_errno);
3df90f24 1361 if (errno_name)
005bfaf1 1362 fputs(errno_name, f);
3df90f24 1363 else
005bfaf1
TM
1364 fprintf(f, "%d", c->syscall_errno);
1365#endif
1366 fputc('\n', f);
3df90f24 1367 }
b3d13314 1368
f7df8adb 1369 FOREACH_ARRAY(mount, c->mount_images, c->n_mount_images) {
79e20ceb 1370 fprintf(f, "%sMountImages: %s%s:%s", prefix,
f7df8adb
MY
1371 mount->ignore_enoent ? "-": "",
1372 mount->source,
1373 mount->destination);
1374 LIST_FOREACH(mount_options, o, mount->mount_options)
79e20ceb 1375 fprintf(f, ":%s:%s",
427353f6 1376 partition_designator_to_string(o->partition_designator),
79e20ceb 1377 strempty(o->options));
427353f6
LB
1378 fprintf(f, "\n");
1379 }
93f59701 1380
f7df8adb 1381 FOREACH_ARRAY(mount, c->extension_images, c->n_extension_images) {
93f59701 1382 fprintf(f, "%sExtensionImages: %s%s", prefix,
f7df8adb
MY
1383 mount->ignore_enoent ? "-": "",
1384 mount->source);
1385 LIST_FOREACH(mount_options, o, mount->mount_options)
93f59701
LB
1386 fprintf(f, ":%s:%s",
1387 partition_designator_to_string(o->partition_designator),
1388 strempty(o->options));
1389 fprintf(f, "\n");
1390 }
a07b9926
LB
1391
1392 strv_dump(f, prefix, "ExtensionDirectories", c->extension_directories);
5cb5a6ff
LP
1393}
1394
34cf6c43 1395bool exec_context_maintains_privileges(const ExecContext *c) {
a931ad47
LP
1396 assert(c);
1397
61233823 1398 /* Returns true if the process forked off would run under
a931ad47
LP
1399 * an unchanged UID or as root. */
1400
1401 if (!c->user)
1402 return true;
1403
1404 if (streq(c->user, "root") || streq(c->user, "0"))
1405 return true;
1406
1407 return false;
1408}
1409
34cf6c43 1410int exec_context_get_effective_ioprio(const ExecContext *c) {
7f452159
LP
1411 int p;
1412
1413 assert(c);
1414
1415 if (c->ioprio_set)
1416 return c->ioprio;
1417
1418 p = ioprio_get(IOPRIO_WHO_PROCESS, 0);
1419 if (p < 0)
0692548c 1420 return IOPRIO_DEFAULT_CLASS_AND_PRIO;
7f452159 1421
8b330d7d 1422 return ioprio_normalize(p);
7f452159
LP
1423}
1424
5e98086d
ZJS
1425bool exec_context_get_effective_mount_apivfs(const ExecContext *c) {
1426 assert(c);
1427
61198784 1428 /* Explicit setting wins */
5e98086d
ZJS
1429 if (c->mount_apivfs_set)
1430 return c->mount_apivfs;
1431
61198784 1432 /* Default to "yes" if root directory or image are specified */
74e12520 1433 if (exec_context_with_rootfs(c))
61198784
ZJS
1434 return true;
1435
5e98086d
ZJS
1436 return false;
1437}
1438
d3070fbd 1439void exec_context_free_log_extra_fields(ExecContext *c) {
d3070fbd
LP
1440 assert(c);
1441
f7df8adb
MY
1442 FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields)
1443 free(field->iov_base);
1444
d3070fbd
LP
1445 c->log_extra_fields = mfree(c->log_extra_fields);
1446 c->n_log_extra_fields = 0;
1447}
1448
6f765baf 1449void exec_context_revert_tty(ExecContext *c) {
254d1313 1450 _cleanup_close_ int fd = -EBADF;
0ba976e8
LP
1451 const char *path;
1452 struct stat st;
6f765baf
LP
1453 int r;
1454
1455 assert(c);
1456
1457 /* First, reset the TTY (possibly kicking everybody else from the TTY) */
f121efd3 1458 exec_context_tty_reset(c, /* parameters= */ NULL);
6f765baf
LP
1459
1460 /* And then undo what chown_terminal() did earlier. Note that we only do this if we have a path
1461 * configured. If the TTY was passed to us as file descriptor we assume the TTY is opened and managed
1462 * by whoever passed it to us and thus knows better when and how to chmod()/chown() it back. */
0ba976e8
LP
1463 if (!exec_context_may_touch_tty(c))
1464 return;
6f765baf 1465
0ba976e8
LP
1466 path = exec_context_tty_path(c);
1467 if (!path)
1468 return;
6f765baf 1469
026a8b02 1470 fd = open(path, O_PATH|O_CLOEXEC); /* Pin the inode */
0ba976e8
LP
1471 if (fd < 0)
1472 return (void) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
1473 "Failed to open TTY inode of '%s' to adjust ownership/access mode, ignoring: %m",
1474 path);
1475
1476 if (fstat(fd, &st) < 0)
1477 return (void) log_warning_errno(errno, "Failed to stat TTY '%s', ignoring: %m", path);
1478
1479 /* Let's add a superficial check that we only do this for stuff that looks like a TTY. We only check
1480 * if things are a character device, since a proper check either means we'd have to open the TTY and
1481 * use isatty(), but we'd rather not do that since opening TTYs comes with all kinds of side-effects
1482 * and is slow. Or we'd have to hardcode dev_t major information, which we'd rather avoid. Why bother
1483 * with this at all? → https://github.com/systemd/systemd/issues/19213 */
1484 if (!S_ISCHR(st.st_mode))
1485 return log_warning("Configured TTY '%s' is not actually a character device, ignoring.", path);
1486
1487 r = fchmod_and_chown(fd, TTY_MODE, 0, TTY_GID);
1488 if (r < 0)
026a8b02 1489 log_warning_errno(r, "Failed to reset TTY ownership/access mode of %s to " UID_FMT ":" GID_FMT ", ignoring: %m", path, (uid_t) 0, (gid_t) TTY_GID);
6f765baf
LP
1490}
1491
4c2f5842
LP
1492int exec_context_get_clean_directories(
1493 ExecContext *c,
1494 char **prefix,
1495 ExecCleanMask mask,
1496 char ***ret) {
1497
1498 _cleanup_strv_free_ char **l = NULL;
4c2f5842
LP
1499 int r;
1500
1501 assert(c);
1502 assert(prefix);
1503 assert(ret);
1504
5b10116e 1505 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
4c2f5842
LP
1506 if (!FLAGS_SET(mask, 1U << t))
1507 continue;
1508
1509 if (!prefix[t])
1510 continue;
1511
f7df8adb 1512 FOREACH_ARRAY(i, c->directories[t].items, c->directories[t].n_items) {
4c2f5842
LP
1513 char *j;
1514
f7df8adb 1515 j = path_join(prefix[t], i->path);
4c2f5842
LP
1516 if (!j)
1517 return -ENOMEM;
1518
1519 r = strv_consume(&l, j);
1520 if (r < 0)
1521 return r;
7f622a19
YW
1522
1523 /* Also remove private directories unconditionally. */
1524 if (t != EXEC_DIRECTORY_CONFIGURATION) {
f7df8adb 1525 j = path_join(prefix[t], "private", i->path);
211a3d87
LB
1526 if (!j)
1527 return -ENOMEM;
1528
1529 r = strv_consume(&l, j);
1530 if (r < 0)
1531 return r;
1532 }
1533
f7df8adb 1534 STRV_FOREACH(symlink, i->symlinks) {
211a3d87 1535 j = path_join(prefix[t], *symlink);
7f622a19
YW
1536 if (!j)
1537 return -ENOMEM;
1538
1539 r = strv_consume(&l, j);
1540 if (r < 0)
1541 return r;
1542 }
4c2f5842
LP
1543 }
1544 }
1545
1546 *ret = TAKE_PTR(l);
1547 return 0;
1548}
1549
1550int exec_context_get_clean_mask(ExecContext *c, ExecCleanMask *ret) {
1551 ExecCleanMask mask = 0;
1552
1553 assert(c);
1554 assert(ret);
1555
1556 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
211a3d87 1557 if (c->directories[t].n_items > 0)
4c2f5842
LP
1558 mask |= 1U << t;
1559
1560 *ret = mask;
1561 return 0;
1562}
1563
ef44aa83
DDM
1564int exec_context_get_oom_score_adjust(const ExecContext *c) {
1565 int n = 0, r;
1566
1567 assert(c);
1568
1569 if (c->oom_score_adjust_set)
1570 return c->oom_score_adjust;
1571
1572 r = get_oom_score_adjust(&n);
1573 if (r < 0)
1574 log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
1575
1576 return n;
1577}
1578
1579uint64_t exec_context_get_coredump_filter(const ExecContext *c) {
1580 _cleanup_free_ char *t = NULL;
1581 uint64_t n = COREDUMP_FILTER_MASK_DEFAULT;
1582 int r;
1583
1584 assert(c);
1585
1586 if (c->coredump_filter_set)
1587 return c->coredump_filter;
1588
1589 r = read_one_line_file("/proc/self/coredump_filter", &t);
1590 if (r < 0)
1591 log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
1592 else {
1593 r = safe_atoux64(t, &n);
1594 if (r < 0)
1595 log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
1596 }
1597
1598 return n;
1599}
1600
1601int exec_context_get_nice(const ExecContext *c) {
1602 int n;
1603
1604 assert(c);
1605
1606 if (c->nice_set)
1607 return c->nice;
1608
1609 errno = 0;
1610 n = getpriority(PRIO_PROCESS, 0);
1611 if (errno > 0) {
1612 log_debug_errno(errno, "Failed to get process nice value, ignoring: %m");
1613 n = 0;
1614 }
1615
1616 return n;
1617}
1618
1619int exec_context_get_cpu_sched_policy(const ExecContext *c) {
1620 int n;
1621
1622 assert(c);
1623
1624 if (c->cpu_sched_set)
1625 return c->cpu_sched_policy;
1626
1627 n = sched_getscheduler(0);
1628 if (n < 0)
1629 log_debug_errno(errno, "Failed to get scheduler policy, ignoring: %m");
1630
1631 return n < 0 ? SCHED_OTHER : n;
1632}
1633
1634int exec_context_get_cpu_sched_priority(const ExecContext *c) {
1635 struct sched_param p = {};
1636 int r;
1637
1638 assert(c);
1639
1640 if (c->cpu_sched_set)
1641 return c->cpu_sched_priority;
1642
1643 r = sched_getparam(0, &p);
1644 if (r < 0)
1645 log_debug_errno(errno, "Failed to get scheduler priority, ignoring: %m");
1646
1647 return r >= 0 ? p.sched_priority : 0;
1648}
1649
1650uint64_t exec_context_get_timer_slack_nsec(const ExecContext *c) {
1651 int r;
1652
1653 assert(c);
1654
1655 if (c->timer_slack_nsec != NSEC_INFINITY)
1656 return c->timer_slack_nsec;
1657
1658 r = prctl(PR_GET_TIMERSLACK);
1659 if (r < 0)
1660 log_debug_errno(r, "Failed to get timer slack, ignoring: %m");
1661
1662 return (uint64_t) MAX(r, 0);
1663}
1664
d1a5be82
LP
1665bool exec_context_get_set_login_environment(const ExecContext *c) {
1666 assert(c);
1667
1668 if (c->set_login_environment >= 0)
1669 return c->set_login_environment;
1670
1671 return c->user || c->dynamic_user || c->pam_name;
1672}
1673
ef44aa83
DDM
1674char** exec_context_get_syscall_filter(const ExecContext *c) {
1675 _cleanup_strv_free_ char **l = NULL;
1676
1677 assert(c);
1678
1679#if HAVE_SECCOMP
1680 void *id, *val;
1681 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
1682 _cleanup_free_ char *name = NULL;
1683 const char *e = NULL;
1684 char *s;
1685 int num = PTR_TO_INT(val);
1686
1687 if (c->syscall_allow_list && num >= 0)
1688 /* syscall with num >= 0 in allow-list is denied. */
1689 continue;
1690
1691 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1692 if (!name)
1693 continue;
1694
1695 if (num >= 0) {
1696 e = seccomp_errno_or_action_to_string(num);
1697 if (e) {
1698 s = strjoin(name, ":", e);
1699 if (!s)
1700 return NULL;
1701 } else {
1702 if (asprintf(&s, "%s:%d", name, num) < 0)
1703 return NULL;
1704 }
1705 } else
1706 s = TAKE_PTR(name);
1707
1708 if (strv_consume(&l, s) < 0)
1709 return NULL;
1710 }
1711
1712 strv_sort(l);
1713#endif
1714
1715 return l ? TAKE_PTR(l) : strv_new(NULL);
1716}
1717
1718char** exec_context_get_syscall_archs(const ExecContext *c) {
1719 _cleanup_strv_free_ char **l = NULL;
1720
1721 assert(c);
1722
1723#if HAVE_SECCOMP
1724 void *id;
1725 SET_FOREACH(id, c->syscall_archs) {
1726 const char *name;
1727
1728 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
1729 if (!name)
1730 continue;
1731
1732 if (strv_extend(&l, name) < 0)
1733 return NULL;
1734 }
1735
1736 strv_sort(l);
1737#endif
1738
1739 return l ? TAKE_PTR(l) : strv_new(NULL);
1740}
1741
1742char** exec_context_get_syscall_log(const ExecContext *c) {
1743 _cleanup_strv_free_ char **l = NULL;
1744
1745 assert(c);
1746
1747#if HAVE_SECCOMP
1748 void *id, *val;
1749 HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
1750 char *name = NULL;
1751
1752 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1753 if (!name)
1754 continue;
1755
1756 if (strv_consume(&l, name) < 0)
1757 return NULL;
1758 }
1759
1760 strv_sort(l);
1761#endif
1762
1763 return l ? TAKE_PTR(l) : strv_new(NULL);
1764}
1765
1766char** exec_context_get_address_families(const ExecContext *c) {
1767 _cleanup_strv_free_ char **l = NULL;
1768 void *af;
1769
1770 assert(c);
1771
1772 SET_FOREACH(af, c->address_families) {
1773 const char *name;
1774
1775 name = af_to_name(PTR_TO_INT(af));
1776 if (!name)
1777 continue;
1778
1779 if (strv_extend(&l, name) < 0)
1780 return NULL;
1781 }
1782
1783 strv_sort(l);
1784
1785 return l ? TAKE_PTR(l) : strv_new(NULL);
1786}
1787
1788char** exec_context_get_restrict_filesystems(const ExecContext *c) {
1789 _cleanup_strv_free_ char **l = NULL;
1790
1791 assert(c);
1792
1793#if HAVE_LIBBPF
1794 l = set_get_strv(c->restrict_filesystems);
1795 if (!l)
1796 return NULL;
1797
1798 strv_sort(l);
1799#endif
1800
1801 return l ? TAKE_PTR(l) : strv_new(NULL);
1802}
1803
b58b4116 1804void exec_status_start(ExecStatus *s, pid_t pid) {
034c6ed7 1805 assert(s);
5cb5a6ff 1806
2ed26ed0
LP
1807 *s = (ExecStatus) {
1808 .pid = pid,
1809 };
1810
fa5a0251 1811 dual_timestamp_now(&s->start_timestamp);
b58b4116
LP
1812}
1813
34cf6c43 1814void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status) {
b58b4116
LP
1815 assert(s);
1816
d46b79bb 1817 if (s->pid != pid)
2ed26ed0
LP
1818 *s = (ExecStatus) {
1819 .pid = pid,
1820 };
b58b4116 1821
fa5a0251 1822 dual_timestamp_now(&s->exit_timestamp);
9fb86720 1823
034c6ed7
LP
1824 s->code = code;
1825 s->status = status;
169c1bda 1826
6f765baf
LP
1827 if (context && context->utmp_id)
1828 (void) utmp_put_dead_process(context->utmp_id, pid, code, status);
9fb86720
LP
1829}
1830
6a1d4d9f
LP
1831void exec_status_reset(ExecStatus *s) {
1832 assert(s);
1833
1834 *s = (ExecStatus) {};
1835}
1836
34cf6c43 1837void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
9fb86720
LP
1838 assert(s);
1839 assert(f);
1840
9fb86720
LP
1841 if (s->pid <= 0)
1842 return;
1843
4c940960
LP
1844 prefix = strempty(prefix);
1845
9fb86720 1846 fprintf(f,
ccd06097
ZJS
1847 "%sPID: "PID_FMT"\n",
1848 prefix, s->pid);
9fb86720 1849
af9d16e1 1850 if (dual_timestamp_is_set(&s->start_timestamp))
9fb86720
LP
1851 fprintf(f,
1852 "%sStart Timestamp: %s\n",
04f5c018 1853 prefix, FORMAT_TIMESTAMP(s->start_timestamp.realtime));
9fb86720 1854
af9d16e1 1855 if (dual_timestamp_is_set(&s->exit_timestamp))
9fb86720
LP
1856 fprintf(f,
1857 "%sExit Timestamp: %s\n"
1858 "%sExit Code: %s\n"
1859 "%sExit Status: %i\n",
04f5c018 1860 prefix, FORMAT_TIMESTAMP(s->exit_timestamp.realtime),
9fb86720
LP
1861 prefix, sigchld_code_to_string(s->code),
1862 prefix, s->status);
5cb5a6ff 1863}
44d8db9e 1864
34cf6c43 1865static void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
e1d75803 1866 _cleanup_free_ char *cmd = NULL;
4c940960 1867 const char *prefix2;
44d8db9e
LP
1868
1869 assert(c);
1870 assert(f);
1871
4c940960 1872 prefix = strempty(prefix);
63c372cb 1873 prefix2 = strjoina(prefix, "\t");
44d8db9e 1874
4ef15008 1875 cmd = quote_command_line(c->argv, SHELL_ESCAPE_EMPTY);
38553034 1876
44d8db9e
LP
1877 fprintf(f,
1878 "%sCommand Line: %s\n",
38553034 1879 prefix, strnull(cmd));
44d8db9e 1880
9fb86720 1881 exec_status_dump(&c->exec_status, f, prefix2);
44d8db9e
LP
1882}
1883
1884void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
1885 assert(f);
1886
4c940960 1887 prefix = strempty(prefix);
44d8db9e 1888
03677889
YW
1889 LIST_FOREACH(command, i, c)
1890 exec_command_dump(i, f, prefix);
44d8db9e 1891}
94f04347 1892
a6a80b4f
LP
1893void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
1894 ExecCommand *end;
1895
1896 assert(l);
1897 assert(e);
1898
1899 if (*l) {
35b8ca3a 1900 /* It's kind of important, that we keep the order here */
cc232fa0 1901 end = LIST_FIND_TAIL(command, *l);
71fda00f 1902 LIST_INSERT_AFTER(command, *l, end, e);
a6a80b4f 1903 } else
3ff67ec4 1904 *l = e;
a6a80b4f
LP
1905}
1906
26fd040d
LP
1907int exec_command_set(ExecCommand *c, const char *path, ...) {
1908 va_list ap;
1909 char **l, *p;
1910
1911 assert(c);
1912 assert(path);
1913
1914 va_start(ap, path);
1915 l = strv_new_ap(path, ap);
1916 va_end(ap);
1917
1918 if (!l)
1919 return -ENOMEM;
1920
250a918d
LP
1921 p = strdup(path);
1922 if (!p) {
26fd040d
LP
1923 strv_free(l);
1924 return -ENOMEM;
1925 }
1926
6897dfe8 1927 free_and_replace(c->path, p);
26fd040d 1928
130d3d22 1929 return strv_free_and_replace(c->argv, l);
26fd040d
LP
1930}
1931
86b23b07 1932int exec_command_append(ExecCommand *c, const char *path, ...) {
e63ff941 1933 _cleanup_strv_free_ char **l = NULL;
86b23b07 1934 va_list ap;
86b23b07
JS
1935 int r;
1936
1937 assert(c);
1938 assert(path);
1939
1940 va_start(ap, path);
1941 l = strv_new_ap(path, ap);
1942 va_end(ap);
1943
1944 if (!l)
1945 return -ENOMEM;
1946
e287086b 1947 r = strv_extend_strv(&c->argv, l, false);
e63ff941 1948 if (r < 0)
86b23b07 1949 return r;
86b23b07
JS
1950
1951 return 0;
1952}
1953
437f3e35
LP
1954static char *destroy_tree(char *path) {
1955 if (!path)
1956 return NULL;
9c0c6701 1957
437f3e35
LP
1958 if (!path_equal(path, RUN_SYSTEMD_EMPTY)) {
1959 log_debug("Spawning process to nuke '%s'", path);
9c0c6701 1960
437f3e35
LP
1961 (void) asynchronous_rm_rf(path, REMOVE_ROOT|REMOVE_SUBVOLUME|REMOVE_PHYSICAL);
1962 }
9c0c6701 1963
437f3e35 1964 return mfree(path);
9c0c6701
DDM
1965}
1966
bb5232b6 1967void exec_shared_runtime_done(ExecSharedRuntime *rt) {
e03975b9 1968 assert(rt);
e8a565cb
YW
1969
1970 if (rt->manager)
e76506b7 1971 (void) hashmap_remove(rt->manager->exec_shared_runtime_by_id, rt->id);
e8a565cb 1972
e52a696a
DDM
1973 rt->id = mfree(rt->id);
1974 rt->tmp_dir = mfree(rt->tmp_dir);
1975 rt->var_tmp_dir = mfree(rt->var_tmp_dir);
1976 safe_close_pair(rt->netns_storage_socket);
1977 safe_close_pair(rt->ipcns_storage_socket);
bb5232b6
LB
1978}
1979
1980static ExecSharedRuntime* exec_shared_runtime_free(ExecSharedRuntime *rt) {
e03975b9
MY
1981 if (!rt)
1982 return NULL;
bb5232b6 1983
e03975b9 1984 exec_shared_runtime_done(rt);
e52a696a
DDM
1985 return mfree(rt);
1986}
1987
1988DEFINE_TRIVIAL_UNREF_FUNC(ExecSharedRuntime, exec_shared_runtime, exec_shared_runtime_free);
1989DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSharedRuntime*, exec_shared_runtime_free);
1990
1991ExecSharedRuntime* exec_shared_runtime_destroy(ExecSharedRuntime *rt) {
e52a696a
DDM
1992 if (!rt)
1993 return NULL;
1994
1995 assert(rt->n_ref > 0);
1996 rt->n_ref--;
1997
1998 if (rt->n_ref > 0)
1999 return NULL;
56a13a49 2000
437f3e35
LP
2001 rt->tmp_dir = destroy_tree(rt->tmp_dir);
2002 rt->var_tmp_dir = destroy_tree(rt->var_tmp_dir);
e8a565cb 2003
e52a696a 2004 return exec_shared_runtime_free(rt);
e8a565cb
YW
2005}
2006
e76506b7 2007static int exec_shared_runtime_allocate(ExecSharedRuntime **ret, const char *id) {
56a13a49 2008 _cleanup_free_ char *id_copy = NULL;
e76506b7 2009 ExecSharedRuntime *n;
613b411c 2010
8e8009dc 2011 assert(ret);
613b411c 2012
56a13a49
ZJS
2013 id_copy = strdup(id);
2014 if (!id_copy)
2015 return -ENOMEM;
2016
e76506b7 2017 n = new(ExecSharedRuntime, 1);
8e8009dc 2018 if (!n)
613b411c
LP
2019 return -ENOMEM;
2020
e76506b7 2021 *n = (ExecSharedRuntime) {
56a13a49 2022 .id = TAKE_PTR(id_copy),
71136404
LP
2023 .netns_storage_socket = EBADF_PAIR,
2024 .ipcns_storage_socket = EBADF_PAIR,
8e8009dc
LP
2025 };
2026
2027 *ret = n;
613b411c
LP
2028 return 0;
2029}
2030
e76506b7 2031static int exec_shared_runtime_add(
e8a565cb
YW
2032 Manager *m,
2033 const char *id,
56a13a49
ZJS
2034 char **tmp_dir,
2035 char **var_tmp_dir,
2036 int netns_storage_socket[2],
a70581ff 2037 int ipcns_storage_socket[2],
e76506b7 2038 ExecSharedRuntime **ret) {
e8a565cb 2039
e76506b7 2040 _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt = NULL;
613b411c
LP
2041 int r;
2042
e8a565cb 2043 assert(m);
613b411c
LP
2044 assert(id);
2045
a70581ff 2046 /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
56a13a49 2047
e76506b7 2048 r = exec_shared_runtime_allocate(&rt, id);
613b411c
LP
2049 if (r < 0)
2050 return r;
2051
e76506b7 2052 r = hashmap_ensure_put(&m->exec_shared_runtime_by_id, &string_hash_ops, rt->id, rt);
56a13a49
ZJS
2053 if (r < 0)
2054 return r;
e8a565cb 2055
56a13a49
ZJS
2056 assert(!!rt->tmp_dir == !!rt->var_tmp_dir); /* We require both to be set together */
2057 rt->tmp_dir = TAKE_PTR(*tmp_dir);
2058 rt->var_tmp_dir = TAKE_PTR(*var_tmp_dir);
e8a565cb
YW
2059
2060 if (netns_storage_socket) {
56a13a49
ZJS
2061 rt->netns_storage_socket[0] = TAKE_FD(netns_storage_socket[0]);
2062 rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
613b411c
LP
2063 }
2064
a70581ff
XR
2065 if (ipcns_storage_socket) {
2066 rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
2067 rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
2068 }
2069
e8a565cb
YW
2070 rt->manager = m;
2071
2072 if (ret)
2073 *ret = rt;
e76506b7 2074 /* do not remove created ExecSharedRuntime object when the operation succeeds. */
56a13a49 2075 TAKE_PTR(rt);
e8a565cb
YW
2076 return 0;
2077}
2078
e76506b7 2079static int exec_shared_runtime_make(
74aaf59b
LP
2080 Manager *m,
2081 const ExecContext *c,
2082 const char *id,
e76506b7 2083 ExecSharedRuntime **ret) {
74aaf59b 2084
56a13a49 2085 _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
71136404 2086 _cleanup_close_pair_ int netns_storage_socket[2] = EBADF_PAIR, ipcns_storage_socket[2] = EBADF_PAIR;
e8a565cb
YW
2087 int r;
2088
2089 assert(m);
2090 assert(c);
2091 assert(id);
2092
e76506b7 2093 /* It is not necessary to create ExecSharedRuntime object. */
fde36d25 2094 if (!exec_needs_network_namespace(c) && !exec_needs_ipc_namespace(c) && !c->private_tmp) {
74aaf59b 2095 *ret = NULL;
e8a565cb 2096 return 0;
74aaf59b 2097 }
e8a565cb 2098
efa2f3a1
TM
2099 if (c->private_tmp &&
2100 !(prefixed_path_strv_contains(c->inaccessible_paths, "/tmp") &&
2101 (prefixed_path_strv_contains(c->inaccessible_paths, "/var/tmp") ||
2102 prefixed_path_strv_contains(c->inaccessible_paths, "/var")))) {
e8a565cb 2103 r = setup_tmp_dirs(id, &tmp_dir, &var_tmp_dir);
613b411c
LP
2104 if (r < 0)
2105 return r;
2106 }
2107
a7774a8c 2108 if (exec_needs_network_namespace(c))
e8a565cb
YW
2109 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, netns_storage_socket) < 0)
2110 return -errno;
e8a565cb 2111
a7774a8c 2112 if (exec_needs_ipc_namespace(c))
a70581ff
XR
2113 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
2114 return -errno;
a70581ff 2115
e76506b7 2116 r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
e8a565cb
YW
2117 if (r < 0)
2118 return r;
2119
613b411c
LP
2120 return 1;
2121}
2122
e76506b7
DDM
2123int exec_shared_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecSharedRuntime **ret) {
2124 ExecSharedRuntime *rt;
e8a565cb 2125 int r;
613b411c 2126
e8a565cb
YW
2127 assert(m);
2128 assert(id);
2129 assert(ret);
2130
e76506b7 2131 rt = hashmap_get(m->exec_shared_runtime_by_id, id);
e8a565cb 2132 if (rt)
e76506b7 2133 /* We already have an ExecSharedRuntime object, let's increase the ref count and reuse it */
e8a565cb
YW
2134 goto ref;
2135
74aaf59b
LP
2136 if (!create) {
2137 *ret = NULL;
e8a565cb 2138 return 0;
74aaf59b 2139 }
e8a565cb
YW
2140
2141 /* If not found, then create a new object. */
e76506b7 2142 r = exec_shared_runtime_make(m, c, id, &rt);
74aaf59b 2143 if (r < 0)
e8a565cb 2144 return r;
74aaf59b 2145 if (r == 0) {
e76506b7 2146 /* When r == 0, it is not necessary to create ExecSharedRuntime object. */
74aaf59b
LP
2147 *ret = NULL;
2148 return 0;
2149 }
613b411c 2150
e8a565cb
YW
2151ref:
2152 /* increment reference counter. */
2153 rt->n_ref++;
2154 *ret = rt;
2155 return 1;
2156}
613b411c 2157
e76506b7
DDM
2158int exec_shared_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
2159 ExecSharedRuntime *rt;
e8a565cb
YW
2160
2161 assert(m);
613b411c
LP
2162 assert(f);
2163 assert(fds);
2164
e76506b7 2165 HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
e8a565cb 2166 fprintf(f, "exec-runtime=%s", rt->id);
613b411c 2167
e8a565cb
YW
2168 if (rt->tmp_dir)
2169 fprintf(f, " tmp-dir=%s", rt->tmp_dir);
613b411c 2170
e8a565cb
YW
2171 if (rt->var_tmp_dir)
2172 fprintf(f, " var-tmp-dir=%s", rt->var_tmp_dir);
613b411c 2173
e8a565cb
YW
2174 if (rt->netns_storage_socket[0] >= 0) {
2175 int copy;
613b411c 2176
e8a565cb
YW
2177 copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
2178 if (copy < 0)
2179 return copy;
613b411c 2180
e8a565cb
YW
2181 fprintf(f, " netns-socket-0=%i", copy);
2182 }
613b411c 2183
e8a565cb
YW
2184 if (rt->netns_storage_socket[1] >= 0) {
2185 int copy;
613b411c 2186
e8a565cb
YW
2187 copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
2188 if (copy < 0)
2189 return copy;
613b411c 2190
e8a565cb
YW
2191 fprintf(f, " netns-socket-1=%i", copy);
2192 }
2193
a70581ff
XR
2194 if (rt->ipcns_storage_socket[0] >= 0) {
2195 int copy;
2196
2197 copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
2198 if (copy < 0)
2199 return copy;
2200
2201 fprintf(f, " ipcns-socket-0=%i", copy);
2202 }
2203
2204 if (rt->ipcns_storage_socket[1] >= 0) {
2205 int copy;
2206
2207 copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
2208 if (copy < 0)
2209 return copy;
2210
2211 fprintf(f, " ipcns-socket-1=%i", copy);
2212 }
2213
e8a565cb 2214 fputc('\n', f);
613b411c
LP
2215 }
2216
2217 return 0;
2218}
2219
e76506b7
DDM
2220int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
2221 _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt_create = NULL;
154eb43f 2222 ExecSharedRuntime *rt = NULL;
613b411c
LP
2223 int r;
2224
e8a565cb
YW
2225 /* This is for the migration from old (v237 or earlier) deserialization text.
2226 * Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
e76506b7 2227 * Even if the ExecSharedRuntime object originally created by the other unit, we cannot judge
e8a565cb
YW
2228 * so or not from the serialized text, then we always creates a new object owned by this. */
2229
2230 assert(u);
613b411c
LP
2231 assert(key);
2232 assert(value);
2233
e76506b7 2234 /* Manager manages ExecSharedRuntime objects by the unit id.
e8a565cb
YW
2235 * So, we omit the serialized text when the unit does not have id (yet?)... */
2236 if (isempty(u->id)) {
2237 log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.");
2238 return 0;
2239 }
613b411c 2240
154eb43f
LB
2241 if (u->manager) {
2242 if (hashmap_ensure_allocated(&u->manager->exec_shared_runtime_by_id, &string_hash_ops) < 0)
2243 return log_oom();
e8a565cb 2244
154eb43f
LB
2245 rt = hashmap_get(u->manager->exec_shared_runtime_by_id, u->id);
2246 }
e8a565cb 2247 if (!rt) {
e76506b7 2248 if (exec_shared_runtime_allocate(&rt_create, u->id) < 0)
f2341e0a 2249 return log_oom();
613b411c 2250
e8a565cb
YW
2251 rt = rt_create;
2252 }
2253
2254 if (streq(key, "tmp-dir")) {
cbc165d1
ZJS
2255 if (free_and_strdup_warn(&rt->tmp_dir, value) < 0)
2256 return -ENOMEM;
613b411c
LP
2257
2258 } else if (streq(key, "var-tmp-dir")) {
cbc165d1
ZJS
2259 if (free_and_strdup_warn(&rt->var_tmp_dir, value) < 0)
2260 return -ENOMEM;
613b411c
LP
2261
2262 } else if (streq(key, "netns-socket-0")) {
e8a565cb
YW
2263
2264 safe_close(rt->netns_storage_socket[0]);
dff9808a
LP
2265 rt->netns_storage_socket[0] = deserialize_fd(fds, value);
2266 if (rt->netns_storage_socket[0] < 0)
2267 return 0;
e8a565cb 2268
613b411c 2269 } else if (streq(key, "netns-socket-1")) {
e8a565cb
YW
2270
2271 safe_close(rt->netns_storage_socket[1]);
dff9808a
LP
2272 rt->netns_storage_socket[1] = deserialize_fd(fds, value);
2273 if (rt->netns_storage_socket[1] < 0)
2274 return 0;
613b411c
LP
2275 } else
2276 return 0;
2277
e76506b7 2278 /* If the object is newly created, then put it to the hashmap which manages ExecSharedRuntime objects. */
154eb43f 2279 if (rt_create && u->manager) {
e76506b7 2280 r = hashmap_put(u->manager->exec_shared_runtime_by_id, rt_create->id, rt_create);
e8a565cb 2281 if (r < 0) {
3fe91079 2282 log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m");
e8a565cb
YW
2283 return 0;
2284 }
613b411c 2285
e8a565cb 2286 rt_create->manager = u->manager;
613b411c 2287
e8a565cb 2288 /* Avoid cleanup */
56a13a49 2289 TAKE_PTR(rt_create);
e8a565cb 2290 }
98b47d54 2291
e8a565cb
YW
2292 return 1;
2293}
613b411c 2294
e76506b7 2295int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
56a13a49
ZJS
2296 _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
2297 char *id = NULL;
a70581ff 2298 int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
99534007 2299 const char *p, *v = ASSERT_PTR(value);
e8a565cb 2300 size_t n;
613b411c 2301
e8a565cb 2302 assert(m);
e8a565cb 2303 assert(fds);
98b47d54 2304
e8a565cb 2305 n = strcspn(v, " ");
2f82562b 2306 id = strndupa_safe(v, n);
e8a565cb
YW
2307 if (v[n] != ' ')
2308 goto finalize;
2309 p = v + n + 1;
2310
2311 v = startswith(p, "tmp-dir=");
2312 if (v) {
2313 n = strcspn(v, " ");
56a13a49
ZJS
2314 tmp_dir = strndup(v, n);
2315 if (!tmp_dir)
2316 return log_oom();
e8a565cb
YW
2317 if (v[n] != ' ')
2318 goto finalize;
2319 p = v + n + 1;
2320 }
2321
2322 v = startswith(p, "var-tmp-dir=");
2323 if (v) {
2324 n = strcspn(v, " ");
56a13a49
ZJS
2325 var_tmp_dir = strndup(v, n);
2326 if (!var_tmp_dir)
2327 return log_oom();
e8a565cb
YW
2328 if (v[n] != ' ')
2329 goto finalize;
2330 p = v + n + 1;
2331 }
2332
2333 v = startswith(p, "netns-socket-0=");
2334 if (v) {
2335 char *buf;
2336
2337 n = strcspn(v, " ");
2f82562b 2338 buf = strndupa_safe(v, n);
c413bb28 2339
dff9808a 2340 netns_fdpair[0] = deserialize_fd(fds, buf);
e652663a 2341 if (netns_fdpair[0] < 0)
dff9808a 2342 return netns_fdpair[0];
e8a565cb
YW
2343 if (v[n] != ' ')
2344 goto finalize;
2345 p = v + n + 1;
613b411c
LP
2346 }
2347
e8a565cb
YW
2348 v = startswith(p, "netns-socket-1=");
2349 if (v) {
2350 char *buf;
98b47d54 2351
e8a565cb 2352 n = strcspn(v, " ");
2f82562b 2353 buf = strndupa_safe(v, n);
a70581ff 2354
dff9808a 2355 netns_fdpair[1] = deserialize_fd(fds, buf);
e652663a 2356 if (netns_fdpair[1] < 0)
dff9808a 2357 return netns_fdpair[1];
a70581ff
XR
2358 if (v[n] != ' ')
2359 goto finalize;
2360 p = v + n + 1;
2361 }
2362
2363 v = startswith(p, "ipcns-socket-0=");
2364 if (v) {
2365 char *buf;
2366
2367 n = strcspn(v, " ");
2f82562b 2368 buf = strndupa_safe(v, n);
a70581ff 2369
dff9808a 2370 ipcns_fdpair[0] = deserialize_fd(fds, buf);
e652663a 2371 if (ipcns_fdpair[0] < 0)
dff9808a 2372 return ipcns_fdpair[0];
a70581ff
XR
2373 if (v[n] != ' ')
2374 goto finalize;
2375 p = v + n + 1;
2376 }
2377
2378 v = startswith(p, "ipcns-socket-1=");
2379 if (v) {
2380 char *buf;
2381
2382 n = strcspn(v, " ");
2f82562b 2383 buf = strndupa_safe(v, n);
a70581ff 2384
dff9808a 2385 ipcns_fdpair[1] = deserialize_fd(fds, buf);
e652663a 2386 if (ipcns_fdpair[1] < 0)
dff9808a 2387 return ipcns_fdpair[1];
e8a565cb 2388 }
98b47d54 2389
e8a565cb 2390finalize:
e76506b7 2391 r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
7d853ca6 2392 if (r < 0)
56a13a49
ZJS
2393 return log_debug_errno(r, "Failed to add exec-runtime: %m");
2394 return 0;
e8a565cb 2395}
613b411c 2396
e76506b7
DDM
2397void exec_shared_runtime_vacuum(Manager *m) {
2398 ExecSharedRuntime *rt;
e8a565cb
YW
2399
2400 assert(m);
2401
e76506b7 2402 /* Free unreferenced ExecSharedRuntime objects. This is used after manager deserialization process. */
e8a565cb 2403
e76506b7 2404 HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
e8a565cb
YW
2405 if (rt->n_ref > 0)
2406 continue;
2407
e52a696a 2408 (void) exec_shared_runtime_free(rt);
e8a565cb 2409 }
613b411c
LP
2410}
2411
9c0c6701
DDM
2412int exec_runtime_make(
2413 const Unit *unit,
2414 const ExecContext *context,
2415 ExecSharedRuntime *shared,
2416 DynamicCreds *creds,
2417 ExecRuntime **ret) {
71136404 2418 _cleanup_close_pair_ int ephemeral_storage_socket[2] = EBADF_PAIR;
9c0c6701 2419 _cleanup_free_ char *ephemeral = NULL;
28135da3 2420 _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
9c0c6701 2421 int r;
28135da3 2422
9c0c6701
DDM
2423 assert(unit);
2424 assert(context);
28135da3
DDM
2425 assert(ret);
2426
9c0c6701 2427 if (!shared && !creds && !exec_needs_ephemeral(context)) {
28135da3
DDM
2428 *ret = NULL;
2429 return 0;
2430 }
2431
9c0c6701
DDM
2432 if (exec_needs_ephemeral(context)) {
2433 r = mkdir_p("/var/lib/systemd/ephemeral-trees", 0755);
2434 if (r < 0)
2435 return r;
2436
2437 r = tempfn_random_child("/var/lib/systemd/ephemeral-trees", unit->id, &ephemeral);
2438 if (r < 0)
2439 return r;
2440
2441 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ephemeral_storage_socket) < 0)
2442 return -errno;
2443 }
2444
28135da3
DDM
2445 rt = new(ExecRuntime, 1);
2446 if (!rt)
2447 return -ENOMEM;
2448
2449 *rt = (ExecRuntime) {
2450 .shared = shared,
15220772 2451 .dynamic_creds = creds,
9c0c6701
DDM
2452 .ephemeral_copy = TAKE_PTR(ephemeral),
2453 .ephemeral_storage_socket[0] = TAKE_FD(ephemeral_storage_socket[0]),
2454 .ephemeral_storage_socket[1] = TAKE_FD(ephemeral_storage_socket[1]),
28135da3
DDM
2455 };
2456
2457 *ret = TAKE_PTR(rt);
2458 return 1;
2459}
2460
2461ExecRuntime* exec_runtime_free(ExecRuntime *rt) {
2462 if (!rt)
2463 return NULL;
2464
2465 exec_shared_runtime_unref(rt->shared);
15220772 2466 dynamic_creds_unref(rt->dynamic_creds);
9c0c6701 2467
437f3e35 2468 rt->ephemeral_copy = destroy_tree(rt->ephemeral_copy);
9c0c6701 2469
9c0c6701 2470 safe_close_pair(rt->ephemeral_storage_socket);
28135da3
DDM
2471 return mfree(rt);
2472}
2473
2474ExecRuntime* exec_runtime_destroy(ExecRuntime *rt) {
2475 if (!rt)
2476 return NULL;
2477
2478 rt->shared = exec_shared_runtime_destroy(rt->shared);
15220772 2479 rt->dynamic_creds = dynamic_creds_destroy(rt->dynamic_creds);
28135da3
DDM
2480 return exec_runtime_free(rt);
2481}
2482
bb5232b6
LB
2483void exec_runtime_clear(ExecRuntime *rt) {
2484 if (!rt)
2485 return;
2486
2487 safe_close_pair(rt->ephemeral_storage_socket);
2488 rt->ephemeral_copy = mfree(rt->ephemeral_copy);
2489}
2490
fba173ff 2491void exec_params_shallow_clear(ExecParameters *p) {
b9c04eaf
YW
2492 if (!p)
2493 return;
2494
fba173ff
LB
2495 /* This is called on the PID1 side, as many of the struct's FDs are only borrowed, and actually
2496 * owned by the manager or other objects, and reused across multiple units. */
2497
c3f8a065
LP
2498 p->environment = strv_free(p->environment);
2499 p->fd_names = strv_free(p->fd_names);
154eb43f 2500 p->files_env = strv_free(p->files_env);
c3f8a065
LP
2501 p->fds = mfree(p->fds);
2502 p->exec_fd = safe_close(p->exec_fd);
b646fc32 2503 p->user_lookup_fd = -EBADF;
352ec23c 2504 p->bpf_restrict_fs_map_fd = -EBADF;
b646fc32
LB
2505 p->unit_id = mfree(p->unit_id);
2506 p->invocation_id = SD_ID128_NULL;
2507 p->invocation_id_string[0] = '\0';
bb5232b6
LB
2508 p->confirm_spawn = mfree(p->confirm_spawn);
2509}
2510
fba173ff 2511void exec_params_deep_clear(ExecParameters *p) {
bb5232b6
LB
2512 if (!p)
2513 return;
2514
fba173ff
LB
2515 /* This is called on the sd-executor side, where everything received is owned by the process and has
2516 * to be fully cleaned up to make sanitizers and analyzers happy, as opposed as the shallow clean
2517 * function above. */
2518
d3eb74f8 2519 close_many_unset(p->fds, p->n_socket_fds + p->n_storage_fds);
bb5232b6
LB
2520
2521 p->cgroup_path = mfree(p->cgroup_path);
2522
d31330c1 2523 if (p->prefix) {
fc932ed4 2524 free_many_charp(p->prefix, _EXEC_DIRECTORY_TYPE_MAX);
d31330c1
FS
2525 p->prefix = mfree(p->prefix);
2526 }
2527
bb5232b6
LB
2528 p->received_credentials_directory = mfree(p->received_credentials_directory);
2529 p->received_encrypted_credentials_directory = mfree(p->received_encrypted_credentials_directory);
2530
26f937e5
LP
2531 if (p->idle_pipe) {
2532 close_many_and_free(p->idle_pipe, 4);
2533 p->idle_pipe = NULL;
2534 }
bb5232b6
LB
2535
2536 p->stdin_fd = safe_close(p->stdin_fd);
2537 p->stdout_fd = safe_close(p->stdout_fd);
2538 p->stderr_fd = safe_close(p->stderr_fd);
2539
2540 p->notify_socket = mfree(p->notify_socket);
2541
2542 open_file_free_many(&p->open_files);
2543
2544 p->fallback_smack_process_label = mfree(p->fallback_smack_process_label);
2545
fba173ff 2546 exec_params_shallow_clear(p);
b9c04eaf
YW
2547}
2548
211a3d87
LB
2549void exec_directory_done(ExecDirectory *d) {
2550 if (!d)
2551 return;
2552
f7df8adb
MY
2553 FOREACH_ARRAY(i, d->items, d->n_items) {
2554 free(i->path);
2555 strv_free(i->symlinks);
211a3d87
LB
2556 }
2557
2558 d->items = mfree(d->items);
2559 d->n_items = 0;
2560 d->mode = 0755;
2561}
2562
564e5c98
YW
2563static ExecDirectoryItem *exec_directory_find(ExecDirectory *d, const char *path) {
2564 assert(d);
2565 assert(path);
2566
f7df8adb
MY
2567 FOREACH_ARRAY(i, d->items, d->n_items)
2568 if (path_equal(i->path, path))
2569 return i;
564e5c98
YW
2570
2571 return NULL;
2572}
2573
2574int exec_directory_add(ExecDirectory *d, const char *path, const char *symlink) {
211a3d87
LB
2575 _cleanup_strv_free_ char **s = NULL;
2576 _cleanup_free_ char *p = NULL;
564e5c98
YW
2577 ExecDirectoryItem *existing;
2578 int r;
211a3d87
LB
2579
2580 assert(d);
211a3d87
LB
2581 assert(path);
2582
564e5c98
YW
2583 existing = exec_directory_find(d, path);
2584 if (existing) {
2585 r = strv_extend(&existing->symlinks, symlink);
2586 if (r < 0)
2587 return r;
2588
2589 return 0; /* existing item is updated */
2590 }
2591
211a3d87
LB
2592 p = strdup(path);
2593 if (!p)
2594 return -ENOMEM;
2595
564e5c98
YW
2596 if (symlink) {
2597 s = strv_new(symlink);
211a3d87
LB
2598 if (!s)
2599 return -ENOMEM;
2600 }
2601
564e5c98 2602 if (!GREEDY_REALLOC(d->items, d->n_items + 1))
211a3d87
LB
2603 return -ENOMEM;
2604
564e5c98 2605 d->items[d->n_items++] = (ExecDirectoryItem) {
211a3d87
LB
2606 .path = TAKE_PTR(p),
2607 .symlinks = TAKE_PTR(s),
2608 };
2609
564e5c98 2610 return 1; /* new item is added */
211a3d87
LB
2611}
2612
a2ab603c
YW
2613static int exec_directory_item_compare_func(const ExecDirectoryItem *a, const ExecDirectoryItem *b) {
2614 assert(a);
2615 assert(b);
2616
2617 return path_compare(a->path, b->path);
2618}
2619
2620void exec_directory_sort(ExecDirectory *d) {
2621 assert(d);
2622
2623 /* Sort the exec directories to make always parent directories processed at first in
2624 * setup_exec_directory(), e.g., even if StateDirectory=foo/bar foo, we need to create foo at first,
2625 * then foo/bar. Also, set .only_create flag if one of the parent directories is contained in the
2626 * list. See also comments in setup_exec_directory() and issue #24783. */
2627
2628 if (d->n_items <= 1)
2629 return;
2630
2631 typesafe_qsort(d->items, d->n_items, exec_directory_item_compare_func);
2632
2633 for (size_t i = 1; i < d->n_items; i++)
2634 for (size_t j = 0; j < i; j++)
2635 if (path_startswith(d->items[i].path, d->items[j].path)) {
2636 d->items[i].only_create = true;
2637 break;
2638 }
211a3d87
LB
2639}
2640
4fb8f1e8
LP
2641ExecCleanMask exec_clean_mask_from_string(const char *s) {
2642 ExecDirectoryType t;
2643
2644 assert(s);
2645
2646 if (streq(s, "all"))
2647 return EXEC_CLEAN_ALL;
2648 if (streq(s, "fdstore"))
2649 return EXEC_CLEAN_FDSTORE;
2650
2651 t = exec_resource_type_from_string(s);
2652 if (t < 0)
2653 return (ExecCleanMask) t;
2654
2655 return 1U << t;
2656}
2657
80876c20
LP
2658static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
2659 [EXEC_INPUT_NULL] = "null",
2660 [EXEC_INPUT_TTY] = "tty",
2661 [EXEC_INPUT_TTY_FORCE] = "tty-force",
4f2d528d 2662 [EXEC_INPUT_TTY_FAIL] = "tty-fail",
52c239d7
LB
2663 [EXEC_INPUT_SOCKET] = "socket",
2664 [EXEC_INPUT_NAMED_FD] = "fd",
08f3be7a 2665 [EXEC_INPUT_DATA] = "data",
2038c3f5 2666 [EXEC_INPUT_FILE] = "file",
80876c20
LP
2667};
2668
8a0867d6
LP
2669DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
2670
94f04347 2671static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
80876c20 2672 [EXEC_OUTPUT_INHERIT] = "inherit",
94f04347 2673 [EXEC_OUTPUT_NULL] = "null",
80876c20 2674 [EXEC_OUTPUT_TTY] = "tty",
9a6bca7a 2675 [EXEC_OUTPUT_KMSG] = "kmsg",
28dbc1e8 2676 [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
706343f4
LP
2677 [EXEC_OUTPUT_JOURNAL] = "journal",
2678 [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
52c239d7
LB
2679 [EXEC_OUTPUT_SOCKET] = "socket",
2680 [EXEC_OUTPUT_NAMED_FD] = "fd",
2038c3f5 2681 [EXEC_OUTPUT_FILE] = "file",
566b7d23 2682 [EXEC_OUTPUT_FILE_APPEND] = "append",
8d7dab1f 2683 [EXEC_OUTPUT_FILE_TRUNCATE] = "truncate",
94f04347
LP
2684};
2685
2686DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
023a4f67
LP
2687
2688static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
2689 [EXEC_UTMP_INIT] = "init",
2690 [EXEC_UTMP_LOGIN] = "login",
2691 [EXEC_UTMP_USER] = "user",
2692};
2693
2694DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode);
53f47dfc
YW
2695
2696static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
2697 [EXEC_PRESERVE_NO] = "no",
2698 [EXEC_PRESERVE_YES] = "yes",
2699 [EXEC_PRESERVE_RESTART] = "restart",
2700};
2701
2702DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
3536f49e 2703
6b7b2ed9 2704/* This table maps ExecDirectoryType to the setting it is configured with in the unit */
72fd1768 2705static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
3536f49e
YW
2706 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory",
2707 [EXEC_DIRECTORY_STATE] = "StateDirectory",
2708 [EXEC_DIRECTORY_CACHE] = "CacheDirectory",
2709 [EXEC_DIRECTORY_LOGS] = "LogsDirectory",
2710 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
2711};
2712
2713DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
b1edf445 2714
211a3d87
LB
2715/* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
2716static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2717 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectorySymlink",
2718 [EXEC_DIRECTORY_STATE] = "StateDirectorySymlink",
2719 [EXEC_DIRECTORY_CACHE] = "CacheDirectorySymlink",
2720 [EXEC_DIRECTORY_LOGS] = "LogsDirectorySymlink",
2721 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectorySymlink",
2722};
2723
2724DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink, ExecDirectoryType);
2725
ef44aa83
DDM
2726static const char* const exec_directory_type_mode_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2727 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectoryMode",
2728 [EXEC_DIRECTORY_STATE] = "StateDirectoryMode",
2729 [EXEC_DIRECTORY_CACHE] = "CacheDirectoryMode",
2730 [EXEC_DIRECTORY_LOGS] = "LogsDirectoryMode",
2731 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectoryMode",
2732};
2733
2734DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_mode, ExecDirectoryType);
2735
6b7b2ed9
LP
2736/* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This
2737 * one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit
2738 * directories, specifically .timer units with their timestamp touch file. */
2739static const char* const exec_resource_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2740 [EXEC_DIRECTORY_RUNTIME] = "runtime",
2741 [EXEC_DIRECTORY_STATE] = "state",
2742 [EXEC_DIRECTORY_CACHE] = "cache",
2743 [EXEC_DIRECTORY_LOGS] = "logs",
2744 [EXEC_DIRECTORY_CONFIGURATION] = "configuration",
2745};
2746
2747DEFINE_STRING_TABLE_LOOKUP(exec_resource_type, ExecDirectoryType);
2748
b1edf445
LP
2749static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
2750 [EXEC_KEYRING_INHERIT] = "inherit",
2751 [EXEC_KEYRING_PRIVATE] = "private",
2752 [EXEC_KEYRING_SHARED] = "shared",
2753};
2754
2755DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode, ExecKeyringMode);