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