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