]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/execute.c
execute: use right fd to fix tty size
[thirdparty/systemd.git] / src / core / execute.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <poll.h>
6 #include <sys/file.h>
7 #include <sys/mman.h>
8 #include <sys/personality.h>
9 #include <sys/prctl.h>
10 #include <sys/shm.h>
11 #include <sys/types.h>
12 #include <sys/un.h>
13 #include <unistd.h>
14 #include <utmpx.h>
15
16 #include <linux/fs.h> /* Must be included after <sys/mount.h> */
17
18 #include "sd-messages.h"
19
20 #include "af-list.h"
21 #include "alloc-util.h"
22 #include "async.h"
23 #include "cap-list.h"
24 #include "capability-util.h"
25 #include "cgroup-setup.h"
26 #include "constants.h"
27 #include "cpu-set-util.h"
28 #include "dev-setup.h"
29 #include "env-file.h"
30 #include "env-util.h"
31 #include "errno-list.h"
32 #include "escape.h"
33 #include "exec-credential.h"
34 #include "execute.h"
35 #include "execute-serialize.h"
36 #include "exit-status.h"
37 #include "fd-util.h"
38 #include "fileio.h"
39 #include "format-util.h"
40 #include "glob-util.h"
41 #include "hexdecoct.h"
42 #include "ioprio-util.h"
43 #include "lock-util.h"
44 #include "log.h"
45 #include "macro.h"
46 #include "manager.h"
47 #include "manager-dump.h"
48 #include "memory-util.h"
49 #include "missing_fs.h"
50 #include "missing_prctl.h"
51 #include "mkdir-label.h"
52 #include "namespace.h"
53 #include "parse-util.h"
54 #include "path-util.h"
55 #include "process-util.h"
56 #include "rlimit-util.h"
57 #include "rm-rf.h"
58 #include "seccomp-util.h"
59 #include "securebits-util.h"
60 #include "selinux-util.h"
61 #include "serialize.h"
62 #include "sort-util.h"
63 #include "special.h"
64 #include "stat-util.h"
65 #include "string-table.h"
66 #include "string-util.h"
67 #include "strv.h"
68 #include "syslog-util.h"
69 #include "terminal-util.h"
70 #include "tmpfile-util.h"
71 #include "umask-util.h"
72 #include "unit-serialize.h"
73 #include "user-util.h"
74 #include "utmp-wtmp.h"
75
76 static 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
83 static 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
90 const char *exec_context_tty_path(const ExecContext *context) {
91 assert(context);
92
93 if (context->stdio_as_fds)
94 return NULL;
95
96 if (context->tty_path)
97 return context->tty_path;
98
99 return "/dev/console";
100 }
101
102 static void exec_context_determine_tty_size(
103 const ExecContext *context,
104 const char *tty_path,
105 unsigned *ret_rows,
106 unsigned *ret_cols) {
107
108 unsigned rows, cols;
109
110 assert(context);
111 assert(ret_rows);
112 assert(ret_cols);
113
114 if (!tty_path)
115 tty_path = exec_context_tty_path(context);
116
117 rows = context->tty_rows;
118 cols = context->tty_cols;
119
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);
125
126 *ret_rows = rows;
127 *ret_cols = cols;
128 }
129
130 int 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
142 void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p) {
143 _cleanup_close_ int _fd = -EBADF, lock_fd = -EBADF;
144 int fd;
145
146 assert(context);
147
148 const char *path = exec_context_tty_path(context);
149
150 if (p && p->stdin_fd >= 0 && isatty(p->stdin_fd))
151 fd = p->stdin_fd;
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))) {
154 fd = _fd = open_terminal(path, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
155 if (fd < 0)
156 return (void) log_debug_errno(fd, "Failed to open terminal '%s', ignoring: %m", path);
157 } else
158 return; /* nothing to do */
159
160 /* Take a synchronization lock for the duration of the setup that we do here.
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. */
163 lock_fd = lock_dev_console();
164 if (lock_fd < 0)
165 return (void) log_debug_errno(lock_fd,
166 "Failed to lock /dev/console: %m");
167
168 if (context->tty_vhangup)
169 (void) terminal_vhangup_fd(fd);
170
171 if (context->tty_reset)
172 (void) reset_terminal_fd(fd, /* switch_to_text= */ true);
173
174 (void) exec_context_apply_tty_size(context, fd, path);
175
176 if (context->tty_vt_disallocate && path)
177 (void) vt_disallocate(path);
178 }
179
180 bool exec_needs_network_namespace(const ExecContext *context) {
181 assert(context);
182
183 return context->private_network || context->network_namespace_path;
184 }
185
186 static bool exec_needs_ephemeral(const ExecContext *context) {
187 return (context->root_image || context->root_directory) && context->root_ephemeral;
188 }
189
190 bool exec_needs_ipc_namespace(const ExecContext *context) {
191 assert(context);
192
193 return context->private_ipc || context->ipc_namespace_path;
194 }
195
196 bool exec_needs_mount_namespace(
197 const ExecContext *context,
198 const ExecParameters *params,
199 const ExecRuntime *runtime) {
200
201 assert(context);
202
203 if (context->root_image)
204 return true;
205
206 if (!strv_isempty(context->read_write_paths) ||
207 !strv_isempty(context->read_only_paths) ||
208 !strv_isempty(context->inaccessible_paths) ||
209 !strv_isempty(context->exec_paths) ||
210 !strv_isempty(context->no_exec_paths))
211 return true;
212
213 if (context->n_bind_mounts > 0)
214 return true;
215
216 if (context->n_temporary_filesystems > 0)
217 return true;
218
219 if (context->n_mount_images > 0)
220 return true;
221
222 if (context->n_extension_images > 0)
223 return true;
224
225 if (!strv_isempty(context->extension_directories))
226 return true;
227
228 if (!IN_SET(context->mount_propagation_flag, 0, MS_SHARED))
229 return true;
230
231 if (context->private_tmp && runtime && runtime->shared && (runtime->shared->tmp_dir || runtime->shared->var_tmp_dir))
232 return true;
233
234 if (context->private_devices ||
235 context->private_mounts > 0 ||
236 (context->private_mounts < 0 && exec_needs_network_namespace(context)) ||
237 context->protect_system != PROTECT_SYSTEM_NO ||
238 context->protect_home != PROTECT_HOME_NO ||
239 context->protect_kernel_tunables ||
240 context->protect_kernel_modules ||
241 context->protect_kernel_logs ||
242 context->protect_control_groups ||
243 context->protect_proc != PROTECT_PROC_DEFAULT ||
244 context->proc_subset != PROC_SUBSET_ALL ||
245 exec_needs_ipc_namespace(context))
246 return true;
247
248 if (context->root_directory) {
249 if (exec_context_get_effective_mount_apivfs(context))
250 return true;
251
252 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
253 if (params && !params->prefix[t])
254 continue;
255
256 if (context->directories[t].n_items > 0)
257 return true;
258 }
259 }
260
261 if (context->dynamic_user &&
262 (context->directories[EXEC_DIRECTORY_STATE].n_items > 0 ||
263 context->directories[EXEC_DIRECTORY_CACHE].n_items > 0 ||
264 context->directories[EXEC_DIRECTORY_LOGS].n_items > 0))
265 return true;
266
267 if (context->log_namespace)
268 return true;
269
270 return false;
271 }
272
273 bool exec_directory_is_private(const ExecContext *context, ExecDirectoryType type) {
274 assert(context);
275
276 if (!context->dynamic_user)
277 return false;
278
279 if (type == EXEC_DIRECTORY_CONFIGURATION)
280 return false;
281
282 if (type == EXEC_DIRECTORY_RUNTIME && context->runtime_directory_preserve_mode == EXEC_PRESERVE_NO)
283 return false;
284
285 return true;
286 }
287
288 int exec_params_get_cgroup_path(
289 const ExecParameters *params,
290 const CGroupContext *c,
291 char **ret) {
292
293 const char *subgroup = NULL;
294 char *p;
295
296 assert(params);
297 assert(ret);
298
299 if (!params->cgroup_path)
300 return -EINVAL;
301
302 /* If we are called for a unit where cgroup delegation is on, and the payload created its own populated
303 * subcgroup (which we expect it to do, after all it asked for delegation), then we cannot place the control
304 * processes started after the main unit's process in the unit's main cgroup because it is now an inner one,
305 * and inner cgroups may not contain processes. Hence, if delegation is on, and this is a control process,
306 * let's use ".control" as subcgroup instead. Note that we do so only for ExecStartPost=, ExecReload=,
307 * ExecStop=, ExecStopPost=, i.e. for the commands where the main process is already forked. For ExecStartPre=
308 * this is not necessary, the cgroup is still empty. We distinguish these cases with the EXEC_CONTROL_CGROUP
309 * flag, which is only passed for the former statements, not for the latter. */
310
311 if (FLAGS_SET(params->flags, EXEC_CGROUP_DELEGATE) && (FLAGS_SET(params->flags, EXEC_CONTROL_CGROUP) || c->delegate_subgroup)) {
312 if (FLAGS_SET(params->flags, EXEC_IS_CONTROL))
313 subgroup = ".control";
314 else
315 subgroup = c->delegate_subgroup;
316 }
317
318 if (subgroup)
319 p = path_join(params->cgroup_path, subgroup);
320 else
321 p = strdup(params->cgroup_path);
322 if (!p)
323 return -ENOMEM;
324
325 *ret = p;
326 return !!subgroup;
327 }
328
329 bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
330 assert(c);
331
332 return c->cpu_affinity_from_numa;
333 }
334
335 static void log_command_line(Unit *unit, const char *msg, const char *executable, char **argv) {
336 assert(unit);
337 assert(msg);
338 assert(executable);
339
340 if (!DEBUG_LOGGING)
341 return;
342
343 _cleanup_free_ char *cmdline = quote_command_line(argv, SHELL_ESCAPE_EMPTY);
344
345 log_unit_struct(unit, LOG_DEBUG,
346 "EXECUTABLE=%s", executable,
347 LOG_UNIT_MESSAGE(unit, "%s: %s", msg, strnull(cmdline)),
348 LOG_UNIT_INVOCATION_ID(unit));
349 }
350
351 static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
352
353 int exec_spawn(Unit *unit,
354 ExecCommand *command,
355 const ExecContext *context,
356 ExecParameters *params,
357 ExecRuntime *runtime,
358 const CGroupContext *cgroup_context,
359 pid_t *ret) {
360
361 char serialization_fd_number[DECIMAL_STR_MAX(int) + 1];
362 _cleanup_free_ char *subcgroup_path = NULL, *log_level = NULL, *executor_path = NULL;
363 _cleanup_fdset_free_ FDSet *fdset = NULL;
364 _cleanup_fclose_ FILE *f = NULL;
365 pid_t pid;
366 int r;
367
368 assert(unit);
369 assert(unit->manager);
370 assert(unit->manager->executor_fd >= 0);
371 assert(command);
372 assert(context);
373 assert(ret);
374 assert(params);
375 assert(params->fds || (params->n_socket_fds + params->n_storage_fds <= 0));
376 assert(!params->files_env); /* We fill this field, ensure it comes NULL-initialized to us */
377
378 LOG_CONTEXT_PUSH_UNIT(unit);
379
380 r = exec_context_load_environment(unit, context, &params->files_env);
381 if (r < 0)
382 return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
383
384 /* Fork with up-to-date SELinux label database, so the child inherits the up-to-date db
385 and, until the next SELinux policy changes, we save further reloads in future children. */
386 mac_selinux_maybe_reload();
387
388 /* We won't know the real executable path until we create the mount namespace in the child, but we
389 want to log from the parent, so we use the possibly inaccurate path here. */
390 log_command_line(unit, "About to execute", command->path, command->argv);
391
392 if (params->cgroup_path) {
393 r = exec_params_get_cgroup_path(params, cgroup_context, &subcgroup_path);
394 if (r < 0)
395 return log_unit_error_errno(unit, r, "Failed to acquire subcgroup path: %m");
396 if (r > 0) {
397 /* If there's a subcgroup, then let's create it here now (the main cgroup was already
398 * realized by the unit logic) */
399
400 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path);
401 if (r < 0)
402 return log_unit_error_errno(unit, r, "Failed to create subcgroup '%s': %m", subcgroup_path);
403 }
404 }
405
406 /* In order to avoid copy-on-write traps and OOM-kills when pid1's memory.current is above the
407 * child's memory.max, serialize all the state needed to start the unit, and pass it to the
408 * systemd-executor binary. clone() with CLONE_VM + CLONE_VFORK will pause the parent until the exec
409 * and ensure all memory is shared. The child immediately execs the new binary so the delay should
410 * be minimal. Once glibc provides a clone3 wrapper we can switch to that, and clone directly in the
411 * target cgroup. */
412
413 r = open_serialization_file("sd-executor-state", &f);
414 if (r < 0)
415 return log_unit_error_errno(unit, r, "Failed to open serialization stream: %m");
416
417 fdset = fdset_new();
418 if (!fdset)
419 return log_oom();
420
421 r = exec_serialize_invocation(f, fdset, context, command, params, runtime, cgroup_context);
422 if (r < 0)
423 return log_unit_error_errno(unit, r, "Failed to serialize parameters: %m");
424
425 if (fseeko(f, 0, SEEK_SET) < 0)
426 return log_unit_error_errno(unit, errno, "Failed to reseek on serialization stream: %m");
427
428 r = fd_cloexec(fileno(f), false);
429 if (r < 0)
430 return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialization fd: %m");
431
432 r = fdset_cloexec(fdset, false);
433 if (r < 0)
434 return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialized fds: %m");
435
436 r = log_level_to_string_alloc(log_get_max_level(), &log_level);
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. */
447 r = posix_spawn_wrapper(
448 FORMAT_PROC_FD_PATH(unit->manager->executor_fd),
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");
457
458 log_unit_debug(unit, "Forked %s as "PID_FMT, command->path, pid);
459
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);
465
466 exec_status_start(&command->exec_status, pid);
467
468 *ret = pid;
469 return 0;
470 }
471
472 void exec_context_init(ExecContext *c) {
473 assert(c);
474
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
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,
491 #if HAVE_SECCOMP
492 .syscall_errno = SECCOMP_ERROR_NUMBER_KILL,
493 #endif
494 .tty_rows = UINT_MAX,
495 .tty_cols = UINT_MAX,
496 .private_mounts = -1,
497 .memory_ksm = -1,
498 .set_login_environment = -1,
499 };
500
501 FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
502 d->mode = 0755;
503
504 numa_policy_reset(&c->numa_policy);
505
506 assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
507 }
508
509 void exec_context_done(ExecContext *c) {
510 assert(c);
511
512 c->environment = strv_free(c->environment);
513 c->environment_files = strv_free(c->environment_files);
514 c->pass_environment = strv_free(c->pass_environment);
515 c->unset_environment = strv_free(c->unset_environment);
516
517 rlimit_free_all(c->rlimit);
518
519 for (size_t l = 0; l < 3; l++) {
520 c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
521 c->stdio_file[l] = mfree(c->stdio_file[l]);
522 }
523
524 c->working_directory = mfree(c->working_directory);
525 c->root_directory = mfree(c->root_directory);
526 c->root_image = mfree(c->root_image);
527 c->root_image_options = mount_options_free_all(c->root_image_options);
528 c->root_hash = mfree(c->root_hash);
529 c->root_hash_size = 0;
530 c->root_hash_path = mfree(c->root_hash_path);
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);
534 c->root_verity = mfree(c->root_verity);
535 c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
536 c->extension_directories = strv_free(c->extension_directories);
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);
541
542 c->supplementary_groups = strv_free(c->supplementary_groups);
543
544 c->pam_name = mfree(c->pam_name);
545
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);
549 c->exec_paths = strv_free(c->exec_paths);
550 c->no_exec_paths = strv_free(c->no_exec_paths);
551 c->exec_search_path = strv_free(c->exec_search_path);
552
553 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
554 c->bind_mounts = NULL;
555 c->n_bind_mounts = 0;
556 temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
557 c->temporary_filesystems = NULL;
558 c->n_temporary_filesystems = 0;
559 c->mount_images = mount_image_free_many(c->mount_images, &c->n_mount_images);
560
561 cpu_set_reset(&c->cpu_set);
562 numa_policy_reset(&c->numa_policy);
563
564 c->utmp_id = mfree(c->utmp_id);
565 c->selinux_context = mfree(c->selinux_context);
566 c->apparmor_profile = mfree(c->apparmor_profile);
567 c->smack_process_label = mfree(c->smack_process_label);
568
569 c->restrict_filesystems = set_free_free(c->restrict_filesystems);
570
571 c->syscall_filter = hashmap_free(c->syscall_filter);
572 c->syscall_archs = set_free(c->syscall_archs);
573 c->address_families = set_free(c->address_families);
574
575 FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
576 exec_directory_done(d);
577
578 c->log_level_max = -1;
579
580 exec_context_free_log_extra_fields(c);
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);
583
584 c->log_ratelimit_interval_usec = 0;
585 c->log_ratelimit_burst = 0;
586
587 c->stdin_data = mfree(c->stdin_data);
588 c->stdin_data_size = 0;
589
590 c->network_namespace_path = mfree(c->network_namespace_path);
591 c->ipc_namespace_path = mfree(c->ipc_namespace_path);
592
593 c->log_namespace = mfree(c->log_namespace);
594
595 c->load_credentials = hashmap_free(c->load_credentials);
596 c->set_credentials = hashmap_free(c->set_credentials);
597 c->import_credentials = set_free_free(c->import_credentials);
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);
602 }
603
604 int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
605 assert(c);
606
607 if (!runtime_prefix)
608 return 0;
609
610 FOREACH_ARRAY(i, c->directories[EXEC_DIRECTORY_RUNTIME].items, c->directories[EXEC_DIRECTORY_RUNTIME].n_items) {
611 _cleanup_free_ char *p = NULL;
612
613 if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
614 p = path_join(runtime_prefix, "private", i->path);
615 else
616 p = path_join(runtime_prefix, i->path);
617 if (!p)
618 return -ENOMEM;
619
620 /* We execute this synchronously, since we need to be sure this is gone when we start the
621 * service next. */
622 (void) rm_rf(p, REMOVE_ROOT);
623
624 STRV_FOREACH(symlink, i->symlinks) {
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 }
636 }
637
638 return 0;
639 }
640
641 int 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
658 void exec_command_done(ExecCommand *c) {
659 assert(c);
660
661 c->path = mfree(c->path);
662 c->argv = strv_free(c->argv);
663 }
664
665 void exec_command_done_array(ExecCommand *c, size_t n) {
666 FOREACH_ARRAY(i, c, n)
667 exec_command_done(i);
668 }
669
670 ExecCommand* exec_command_free_list(ExecCommand *c) {
671 ExecCommand *i;
672
673 while ((i = LIST_POP(command, c))) {
674 exec_command_done(i);
675 free(i);
676 }
677
678 return NULL;
679 }
680
681 void exec_command_free_array(ExecCommand **c, size_t n) {
682 FOREACH_ARRAY(i, c, n)
683 *i = exec_command_free_list(*i);
684 }
685
686 void exec_command_reset_status_array(ExecCommand *c, size_t n) {
687 FOREACH_ARRAY(i, c, n)
688 exec_status_reset(&i->exec_status);
689 }
690
691 void exec_command_reset_status_list_array(ExecCommand **c, size_t n) {
692 FOREACH_ARRAY(i, c, n)
693 LIST_FOREACH(command, z, *i)
694 exec_status_reset(&z->exec_status);
695 }
696
697 typedef struct InvalidEnvInfo {
698 const Unit *unit;
699 const char *path;
700 } InvalidEnvInfo;
701
702 static void invalid_env(const char *p, void *userdata) {
703 InvalidEnvInfo *info = userdata;
704
705 log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path);
706 }
707
708 const char* exec_context_fdname(const ExecContext *c, int fd_index) {
709 assert(c);
710
711 switch (fd_index) {
712
713 case STDIN_FILENO:
714 if (c->std_input != EXEC_INPUT_NAMED_FD)
715 return NULL;
716
717 return c->stdio_fdname[STDIN_FILENO] ?: "stdin";
718
719 case STDOUT_FILENO:
720 if (c->std_output != EXEC_OUTPUT_NAMED_FD)
721 return NULL;
722
723 return c->stdio_fdname[STDOUT_FILENO] ?: "stdout";
724
725 case STDERR_FILENO:
726 if (c->std_error != EXEC_OUTPUT_NAMED_FD)
727 return NULL;
728
729 return c->stdio_fdname[STDERR_FILENO] ?: "stderr";
730
731 default:
732 return NULL;
733 }
734 }
735
736 static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***ret) {
737 _cleanup_strv_free_ char **v = NULL;
738 int r;
739
740 assert(c);
741 assert(ret);
742
743 STRV_FOREACH(i, c->environment_files) {
744 _cleanup_globfree_ glob_t pglob = {};
745 bool ignore = false;
746 char *fn = *i;
747
748 if (fn[0] == '-') {
749 ignore = true;
750 fn++;
751 }
752
753 if (!path_is_absolute(fn)) {
754 if (ignore)
755 continue;
756 return -EINVAL;
757 }
758
759 /* Filename supports globbing, take all matching files */
760 r = safe_glob(fn, 0, &pglob);
761 if (r < 0) {
762 if (ignore)
763 continue;
764 return r;
765 }
766
767 /* When we don't match anything, -ENOENT should be returned */
768 assert(pglob.gl_pathc > 0);
769
770 FOREACH_ARRAY(path, pglob.gl_pathv, pglob.gl_pathc) {
771 _cleanup_strv_free_ char **p = NULL;
772
773 r = load_env_file(NULL, *path, &p);
774 if (r < 0) {
775 if (ignore)
776 continue;
777 return r;
778 }
779
780 /* Log invalid environment variables with filename */
781 if (p) {
782 InvalidEnvInfo info = {
783 .unit = unit,
784 .path = *path,
785 };
786
787 p = strv_env_clean_with_callback(p, invalid_env, &info);
788 }
789
790 if (!v)
791 v = TAKE_PTR(p);
792 else {
793 char **m = strv_env_merge(v, p);
794 if (!m)
795 return -ENOMEM;
796
797 strv_free_and_replace(v, m);
798 }
799 }
800 }
801
802 *ret = TAKE_PTR(v);
803
804 return 0;
805 }
806
807 static bool tty_may_match_dev_console(const char *tty) {
808 _cleanup_free_ char *resolved = NULL;
809
810 if (!tty)
811 return true;
812
813 tty = skip_dev_prefix(tty);
814
815 /* trivial identity? */
816 if (streq(tty, "console"))
817 return true;
818
819 if (resolve_dev_console(&resolved) < 0)
820 return true; /* if we could not resolve, assume it may */
821
822 /* "tty0" means the active VC, so it may be the same sometimes */
823 return path_equal(resolved, tty) || (streq(resolved, "tty0") && tty_is_vc(tty));
824 }
825
826 static bool exec_context_may_touch_tty(const ExecContext *ec) {
827 assert(ec);
828
829 return ec->tty_reset ||
830 ec->tty_vhangup ||
831 ec->tty_vt_disallocate ||
832 is_terminal_input(ec->std_input) ||
833 is_terminal_output(ec->std_output) ||
834 is_terminal_output(ec->std_error);
835 }
836
837 bool exec_context_may_touch_console(const ExecContext *ec) {
838
839 return exec_context_may_touch_tty(ec) &&
840 tty_may_match_dev_console(exec_context_tty_path(ec));
841 }
842
843 static void strv_fprintf(FILE *f, char **l) {
844 assert(f);
845
846 STRV_FOREACH(g, l)
847 fprintf(f, " %s", *g);
848 }
849
850 static 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)) {
856 fprintf(f, "%s%s:", prefix, name);
857 strv_fprintf(f, strv);
858 fputs("\n", f);
859 }
860 }
861
862 void 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
904 void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
905 int r;
906
907 assert(c);
908 assert(f);
909
910 prefix = strempty(prefix);
911
912 fprintf(f,
913 "%sUMask: %04o\n"
914 "%sWorkingDirectory: %s\n"
915 "%sRootDirectory: %s\n"
916 "%sRootEphemeral: %s\n"
917 "%sNonBlocking: %s\n"
918 "%sPrivateTmp: %s\n"
919 "%sPrivateDevices: %s\n"
920 "%sProtectKernelTunables: %s\n"
921 "%sProtectKernelModules: %s\n"
922 "%sProtectKernelLogs: %s\n"
923 "%sProtectClock: %s\n"
924 "%sProtectControlGroups: %s\n"
925 "%sPrivateNetwork: %s\n"
926 "%sPrivateUsers: %s\n"
927 "%sProtectHome: %s\n"
928 "%sProtectSystem: %s\n"
929 "%sMountAPIVFS: %s\n"
930 "%sIgnoreSIGPIPE: %s\n"
931 "%sMemoryDenyWriteExecute: %s\n"
932 "%sRestrictRealtime: %s\n"
933 "%sRestrictSUIDSGID: %s\n"
934 "%sKeyringMode: %s\n"
935 "%sProtectHostname: %s\n"
936 "%sProtectProc: %s\n"
937 "%sProcSubset: %s\n",
938 prefix, c->umask,
939 prefix, empty_to_root(c->working_directory),
940 prefix, empty_to_root(c->root_directory),
941 prefix, yes_no(c->root_ephemeral),
942 prefix, yes_no(c->non_blocking),
943 prefix, yes_no(c->private_tmp),
944 prefix, yes_no(c->private_devices),
945 prefix, yes_no(c->protect_kernel_tunables),
946 prefix, yes_no(c->protect_kernel_modules),
947 prefix, yes_no(c->protect_kernel_logs),
948 prefix, yes_no(c->protect_clock),
949 prefix, yes_no(c->protect_control_groups),
950 prefix, yes_no(c->private_network),
951 prefix, yes_no(c->private_users),
952 prefix, protect_home_to_string(c->protect_home),
953 prefix, protect_system_to_string(c->protect_system),
954 prefix, yes_no(exec_context_get_effective_mount_apivfs(c)),
955 prefix, yes_no(c->ignore_sigpipe),
956 prefix, yes_no(c->memory_deny_write_execute),
957 prefix, yes_no(c->restrict_realtime),
958 prefix, yes_no(c->restrict_suid_sgid),
959 prefix, exec_keyring_mode_to_string(c->keyring_mode),
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));
963
964 if (c->set_login_environment >= 0)
965 fprintf(f, "%sSetLoginEnvironment: %s\n", prefix, yes_no(c->set_login_environment > 0));
966
967 if (c->root_image)
968 fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
969
970 if (c->root_image_options) {
971 fprintf(f, "%sRootImageOptions:", prefix);
972 LIST_FOREACH(mount_options, o, c->root_image_options)
973 if (!isempty(o->options))
974 fprintf(f, " %s:%s",
975 partition_designator_to_string(o->partition_designator),
976 o->options);
977 fprintf(f, "\n");
978 }
979
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
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
1001 if (c->root_verity)
1002 fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
1003
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);
1009
1010 STRV_FOREACH(e, c->pass_environment)
1011 fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
1012
1013 STRV_FOREACH(e, c->unset_environment)
1014 fprintf(f, "%sUnsetEnvironment: %s\n", prefix, *e);
1015
1016 fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
1017
1018 for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
1019 fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode);
1020
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 }
1027 }
1028
1029 fprintf(f, "%sTimeoutCleanSec: %s\n", prefix, FORMAT_TIMESPAN(c->timeout_clean_usec, USEC_PER_SEC));
1030
1031 if (c->memory_ksm >= 0)
1032 fprintf(f, "%sMemoryKSM: %s\n", prefix, yes_no(c->memory_ksm > 0));
1033
1034 if (c->nice_set)
1035 fprintf(f, "%sNice: %i\n", prefix, c->nice);
1036
1037 if (c->oom_score_adjust_set)
1038 fprintf(f, "%sOOMScoreAdjust: %i\n", prefix, c->oom_score_adjust);
1039
1040 if (c->coredump_filter_set)
1041 fprintf(f, "%sCoredumpFilter: 0x%"PRIx64"\n", prefix, c->coredump_filter);
1042
1043 for (unsigned i = 0; i < RLIM_NLIMITS; i++)
1044 if (c->rlimit[i]) {
1045 fprintf(f, "%sLimit%s: " RLIM_FMT "\n",
1046 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
1047 fprintf(f, "%sLimit%sSoft: " RLIM_FMT "\n",
1048 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
1049 }
1050
1051 if (c->ioprio_set) {
1052 _cleanup_free_ char *class_str = NULL;
1053
1054 r = ioprio_class_to_string_alloc(ioprio_prio_class(c->ioprio), &class_str);
1055 if (r >= 0)
1056 fprintf(f, "%sIOSchedulingClass: %s\n", prefix, class_str);
1057
1058 fprintf(f, "%sIOPriority: %d\n", prefix, ioprio_prio_data(c->ioprio));
1059 }
1060
1061 if (c->cpu_sched_set) {
1062 _cleanup_free_ char *policy_str = NULL;
1063
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
1068 fprintf(f,
1069 "%sCPUSchedulingPriority: %i\n"
1070 "%sCPUSchedulingResetOnFork: %s\n",
1071 prefix, c->cpu_sched_priority,
1072 prefix, yes_no(c->cpu_sched_reset_on_fork));
1073 }
1074
1075 if (c->cpu_set.set) {
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);
1080 }
1081
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
1090 if (c->timer_slack_nsec != NSEC_INFINITY)
1091 fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec);
1092
1093 fprintf(f,
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
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]);
1112 if (c->std_output == EXEC_OUTPUT_FILE_APPEND)
1113 fprintf(f, "%sStandardOutputFileToAppend: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
1114 if (c->std_output == EXEC_OUTPUT_FILE_TRUNCATE)
1115 fprintf(f, "%sStandardOutputFileToTruncate: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
1116 if (c->std_error == EXEC_OUTPUT_FILE)
1117 fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
1118 if (c->std_error == EXEC_OUTPUT_FILE_APPEND)
1119 fprintf(f, "%sStandardErrorFileToAppend: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
1120 if (c->std_error == EXEC_OUTPUT_FILE_TRUNCATE)
1121 fprintf(f, "%sStandardErrorFileToTruncate: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
1122
1123 if (c->tty_path)
1124 fprintf(f,
1125 "%sTTYPath: %s\n"
1126 "%sTTYReset: %s\n"
1127 "%sTTYVHangup: %s\n"
1128 "%sTTYVTDisallocate: %s\n"
1129 "%sTTYRows: %u\n"
1130 "%sTTYColumns: %u\n",
1131 prefix, c->tty_path,
1132 prefix, yes_no(c->tty_reset),
1133 prefix, yes_no(c->tty_vhangup),
1134 prefix, yes_no(c->tty_vt_disallocate),
1135 prefix, c->tty_rows,
1136 prefix, c->tty_cols);
1137
1138 if (IN_SET(c->std_output,
1139 EXEC_OUTPUT_KMSG,
1140 EXEC_OUTPUT_JOURNAL,
1141 EXEC_OUTPUT_KMSG_AND_CONSOLE,
1142 EXEC_OUTPUT_JOURNAL_AND_CONSOLE) ||
1143 IN_SET(c->std_error,
1144 EXEC_OUTPUT_KMSG,
1145 EXEC_OUTPUT_JOURNAL,
1146 EXEC_OUTPUT_KMSG_AND_CONSOLE,
1147 EXEC_OUTPUT_JOURNAL_AND_CONSOLE)) {
1148
1149 _cleanup_free_ char *fac_str = NULL, *lvl_str = NULL;
1150
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);
1154
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);
1158 }
1159
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
1168 if (c->log_ratelimit_interval_usec > 0)
1169 fprintf(f,
1170 "%sLogRateLimitIntervalSec: %s\n",
1171 prefix, FORMAT_TIMESPAN(c->log_ratelimit_interval_usec, USEC_PER_SEC));
1172
1173 if (c->log_ratelimit_burst > 0)
1174 fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_ratelimit_burst);
1175
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
1187 FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields) {
1188 fprintf(f, "%sLogExtraFields: ", prefix);
1189 fwrite(field->iov_base, 1, field->iov_len, f);
1190 fputc('\n', f);
1191 }
1192
1193 if (c->log_namespace)
1194 fprintf(f, "%sLogNamespace: %s\n", prefix, c->log_namespace);
1195
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 }
1203
1204 if (c->capability_bounding_set != CAP_MASK_UNSET) {
1205 _cleanup_free_ char *str = NULL;
1206
1207 r = capability_set_to_string(c->capability_bounding_set, &str);
1208 if (r >= 0)
1209 fprintf(f, "%sCapabilityBoundingSet: %s\n", prefix, str);
1210 }
1211
1212 if (c->capability_ambient_set != 0) {
1213 _cleanup_free_ char *str = NULL;
1214
1215 r = capability_set_to_string(c->capability_ambient_set, &str);
1216 if (r >= 0)
1217 fprintf(f, "%sAmbientCapabilities: %s\n", prefix, str);
1218 }
1219
1220 if (c->user)
1221 fprintf(f, "%sUser: %s\n", prefix, c->user);
1222 if (c->group)
1223 fprintf(f, "%sGroup: %s\n", prefix, c->group);
1224
1225 fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
1226
1227 strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups);
1228
1229 if (c->pam_name)
1230 fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
1231
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);
1237 strv_dump(f, prefix, "ExecSearchPath", c->exec_search_path);
1238
1239 FOREACH_ARRAY(mount, c->bind_mounts, c->n_bind_mounts)
1240 fprintf(f, "%s%s: %s%s:%s:%s\n", prefix,
1241 mount->read_only ? "BindReadOnlyPaths" : "BindPaths",
1242 mount->ignore_enoent ? "-": "",
1243 mount->source,
1244 mount->destination,
1245 mount->recursive ? "rbind" : "norbind");
1246
1247 FOREACH_ARRAY(tmpfs, c->temporary_filesystems, c->n_temporary_filesystems)
1248 fprintf(f, "%sTemporaryFileSystem: %s%s%s\n", prefix,
1249 tmpfs->path,
1250 isempty(tmpfs->options) ? "" : ":",
1251 strempty(tmpfs->options));
1252
1253 if (c->utmp_id)
1254 fprintf(f,
1255 "%sUtmpIdentifier: %s\n",
1256 prefix, c->utmp_id);
1257
1258 if (c->selinux_context)
1259 fprintf(f,
1260 "%sSELinuxContext: %s%s\n",
1261 prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
1262
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
1273 if (c->personality != PERSONALITY_INVALID)
1274 fprintf(f,
1275 "%sPersonality: %s\n",
1276 prefix, strna(personality_to_string(c->personality)));
1277
1278 fprintf(f,
1279 "%sLockPersonality: %s\n",
1280 prefix, yes_no(c->lock_personality));
1281
1282 if (c->syscall_filter) {
1283 fprintf(f,
1284 "%sSystemCallFilter: ",
1285 prefix);
1286
1287 if (!c->syscall_allow_list)
1288 fputc('~', f);
1289
1290 #if HAVE_SECCOMP
1291 void *id, *val;
1292 bool first = true;
1293 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
1294 _cleanup_free_ char *name = NULL;
1295 const char *errno_name = NULL;
1296 int num = PTR_TO_INT(val);
1297
1298 if (first)
1299 first = false;
1300 else
1301 fputc(' ', f);
1302
1303 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1304 fputs(strna(name), f);
1305
1306 if (num >= 0) {
1307 errno_name = seccomp_errno_or_action_to_string(num);
1308 if (errno_name)
1309 fprintf(f, ":%s", errno_name);
1310 else
1311 fprintf(f, ":%d", num);
1312 }
1313 }
1314 #endif
1315
1316 fputc('\n', f);
1317 }
1318
1319 if (c->syscall_archs) {
1320 fprintf(f,
1321 "%sSystemCallArchitectures:",
1322 prefix);
1323
1324 #if HAVE_SECCOMP
1325 void *id;
1326 SET_FOREACH(id, c->syscall_archs)
1327 fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1)));
1328 #endif
1329 fputc('\n', f);
1330 }
1331
1332 if (exec_context_restrict_namespaces_set(c)) {
1333 _cleanup_free_ char *s = NULL;
1334
1335 r = namespace_flags_to_string(c->restrict_namespaces, &s);
1336 if (r >= 0)
1337 fprintf(f, "%sRestrictNamespaces: %s\n",
1338 prefix, strna(s));
1339 }
1340
1341 #if HAVE_LIBBPF
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 }
1347 #endif
1348
1349 if (c->network_namespace_path)
1350 fprintf(f,
1351 "%sNetworkNamespacePath: %s\n",
1352 prefix, c->network_namespace_path);
1353
1354 if (c->syscall_errno > 0) {
1355 fprintf(f, "%sSystemCallErrorNumber: ", prefix);
1356
1357 #if HAVE_SECCOMP
1358 const char *errno_name = seccomp_errno_or_action_to_string(c->syscall_errno);
1359 if (errno_name)
1360 fputs(errno_name, f);
1361 else
1362 fprintf(f, "%d", c->syscall_errno);
1363 #endif
1364 fputc('\n', f);
1365 }
1366
1367 FOREACH_ARRAY(mount, c->mount_images, c->n_mount_images) {
1368 fprintf(f, "%sMountImages: %s%s:%s", prefix,
1369 mount->ignore_enoent ? "-": "",
1370 mount->source,
1371 mount->destination);
1372 LIST_FOREACH(mount_options, o, mount->mount_options)
1373 fprintf(f, ":%s:%s",
1374 partition_designator_to_string(o->partition_designator),
1375 strempty(o->options));
1376 fprintf(f, "\n");
1377 }
1378
1379 FOREACH_ARRAY(mount, c->extension_images, c->n_extension_images) {
1380 fprintf(f, "%sExtensionImages: %s%s", prefix,
1381 mount->ignore_enoent ? "-": "",
1382 mount->source);
1383 LIST_FOREACH(mount_options, o, mount->mount_options)
1384 fprintf(f, ":%s:%s",
1385 partition_designator_to_string(o->partition_designator),
1386 strempty(o->options));
1387 fprintf(f, "\n");
1388 }
1389
1390 strv_dump(f, prefix, "ExtensionDirectories", c->extension_directories);
1391 }
1392
1393 bool exec_context_maintains_privileges(const ExecContext *c) {
1394 assert(c);
1395
1396 /* Returns true if the process forked off would run under
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
1408 int exec_context_get_effective_ioprio(const ExecContext *c) {
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)
1418 return IOPRIO_DEFAULT_CLASS_AND_PRIO;
1419
1420 return ioprio_normalize(p);
1421 }
1422
1423 bool exec_context_get_effective_mount_apivfs(const ExecContext *c) {
1424 assert(c);
1425
1426 /* Explicit setting wins */
1427 if (c->mount_apivfs_set)
1428 return c->mount_apivfs;
1429
1430 /* Default to "yes" if root directory or image are specified */
1431 if (exec_context_with_rootfs(c))
1432 return true;
1433
1434 return false;
1435 }
1436
1437 void exec_context_free_log_extra_fields(ExecContext *c) {
1438 assert(c);
1439
1440 FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields)
1441 free(field->iov_base);
1442
1443 c->log_extra_fields = mfree(c->log_extra_fields);
1444 c->n_log_extra_fields = 0;
1445 }
1446
1447 void exec_context_revert_tty(ExecContext *c) {
1448 _cleanup_close_ int fd = -EBADF;
1449 const char *path;
1450 struct stat st;
1451 int r;
1452
1453 assert(c);
1454
1455 /* First, reset the TTY (possibly kicking everybody else from the TTY) */
1456 exec_context_tty_reset(c, NULL);
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. */
1461 if (!exec_context_may_touch_tty(c))
1462 return;
1463
1464 path = exec_context_tty_path(c);
1465 if (!path)
1466 return;
1467
1468 fd = open(path, O_PATH|O_CLOEXEC);
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)
1487 log_warning_errno(r, "Failed to reset TTY ownership/access mode of %s, ignoring: %m", path);
1488 }
1489
1490 int 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;
1497 int r;
1498
1499 assert(c);
1500 assert(prefix);
1501 assert(ret);
1502
1503 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
1504 if (!FLAGS_SET(mask, 1U << t))
1505 continue;
1506
1507 if (!prefix[t])
1508 continue;
1509
1510 FOREACH_ARRAY(i, c->directories[t].items, c->directories[t].n_items) {
1511 char *j;
1512
1513 j = path_join(prefix[t], i->path);
1514 if (!j)
1515 return -ENOMEM;
1516
1517 r = strv_consume(&l, j);
1518 if (r < 0)
1519 return r;
1520
1521 /* Also remove private directories unconditionally. */
1522 if (t != EXEC_DIRECTORY_CONFIGURATION) {
1523 j = path_join(prefix[t], "private", i->path);
1524 if (!j)
1525 return -ENOMEM;
1526
1527 r = strv_consume(&l, j);
1528 if (r < 0)
1529 return r;
1530 }
1531
1532 STRV_FOREACH(symlink, i->symlinks) {
1533 j = path_join(prefix[t], *symlink);
1534 if (!j)
1535 return -ENOMEM;
1536
1537 r = strv_consume(&l, j);
1538 if (r < 0)
1539 return r;
1540 }
1541 }
1542 }
1543
1544 *ret = TAKE_PTR(l);
1545 return 0;
1546 }
1547
1548 int 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++)
1555 if (c->directories[t].n_items > 0)
1556 mask |= 1U << t;
1557
1558 *ret = mask;
1559 return 0;
1560 }
1561
1562 int 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
1577 uint64_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
1599 int 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
1617 int 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
1632 int 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
1648 uint64_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
1663 char** exec_context_get_syscall_filter(const ExecContext *c) {
1664 _cleanup_strv_free_ char **l = NULL;
1665
1666 assert(c);
1667
1668 #if HAVE_SECCOMP
1669 void *id, *val;
1670 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
1671 _cleanup_free_ char *name = NULL;
1672 const char *e = NULL;
1673 char *s;
1674 int num = PTR_TO_INT(val);
1675
1676 if (c->syscall_allow_list && num >= 0)
1677 /* syscall with num >= 0 in allow-list is denied. */
1678 continue;
1679
1680 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1681 if (!name)
1682 continue;
1683
1684 if (num >= 0) {
1685 e = seccomp_errno_or_action_to_string(num);
1686 if (e) {
1687 s = strjoin(name, ":", e);
1688 if (!s)
1689 return NULL;
1690 } else {
1691 if (asprintf(&s, "%s:%d", name, num) < 0)
1692 return NULL;
1693 }
1694 } else
1695 s = TAKE_PTR(name);
1696
1697 if (strv_consume(&l, s) < 0)
1698 return NULL;
1699 }
1700
1701 strv_sort(l);
1702 #endif
1703
1704 return l ? TAKE_PTR(l) : strv_new(NULL);
1705 }
1706
1707 char** exec_context_get_syscall_archs(const ExecContext *c) {
1708 _cleanup_strv_free_ char **l = NULL;
1709
1710 assert(c);
1711
1712 #if HAVE_SECCOMP
1713 void *id;
1714 SET_FOREACH(id, c->syscall_archs) {
1715 const char *name;
1716
1717 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
1718 if (!name)
1719 continue;
1720
1721 if (strv_extend(&l, name) < 0)
1722 return NULL;
1723 }
1724
1725 strv_sort(l);
1726 #endif
1727
1728 return l ? TAKE_PTR(l) : strv_new(NULL);
1729 }
1730
1731 char** exec_context_get_syscall_log(const ExecContext *c) {
1732 _cleanup_strv_free_ char **l = NULL;
1733
1734 assert(c);
1735
1736 #if HAVE_SECCOMP
1737 void *id, *val;
1738 HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
1739 char *name = NULL;
1740
1741 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1742 if (!name)
1743 continue;
1744
1745 if (strv_consume(&l, name) < 0)
1746 return NULL;
1747 }
1748
1749 strv_sort(l);
1750 #endif
1751
1752 return l ? TAKE_PTR(l) : strv_new(NULL);
1753 }
1754
1755 char** exec_context_get_address_families(const ExecContext *c) {
1756 _cleanup_strv_free_ char **l = NULL;
1757 void *af;
1758
1759 assert(c);
1760
1761 SET_FOREACH(af, c->address_families) {
1762 const char *name;
1763
1764 name = af_to_name(PTR_TO_INT(af));
1765 if (!name)
1766 continue;
1767
1768 if (strv_extend(&l, name) < 0)
1769 return NULL;
1770 }
1771
1772 strv_sort(l);
1773
1774 return l ? TAKE_PTR(l) : strv_new(NULL);
1775 }
1776
1777 char** exec_context_get_restrict_filesystems(const ExecContext *c) {
1778 _cleanup_strv_free_ char **l = NULL;
1779
1780 assert(c);
1781
1782 #if HAVE_LIBBPF
1783 l = set_get_strv(c->restrict_filesystems);
1784 if (!l)
1785 return NULL;
1786
1787 strv_sort(l);
1788 #endif
1789
1790 return l ? TAKE_PTR(l) : strv_new(NULL);
1791 }
1792
1793 void exec_status_start(ExecStatus *s, pid_t pid) {
1794 assert(s);
1795
1796 *s = (ExecStatus) {
1797 .pid = pid,
1798 };
1799
1800 dual_timestamp_get(&s->start_timestamp);
1801 }
1802
1803 void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status) {
1804 assert(s);
1805
1806 if (s->pid != pid)
1807 *s = (ExecStatus) {
1808 .pid = pid,
1809 };
1810
1811 dual_timestamp_get(&s->exit_timestamp);
1812
1813 s->code = code;
1814 s->status = status;
1815
1816 if (context && context->utmp_id)
1817 (void) utmp_put_dead_process(context->utmp_id, pid, code, status);
1818 }
1819
1820 void exec_status_reset(ExecStatus *s) {
1821 assert(s);
1822
1823 *s = (ExecStatus) {};
1824 }
1825
1826 void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
1827 assert(s);
1828 assert(f);
1829
1830 if (s->pid <= 0)
1831 return;
1832
1833 prefix = strempty(prefix);
1834
1835 fprintf(f,
1836 "%sPID: "PID_FMT"\n",
1837 prefix, s->pid);
1838
1839 if (dual_timestamp_is_set(&s->start_timestamp))
1840 fprintf(f,
1841 "%sStart Timestamp: %s\n",
1842 prefix, FORMAT_TIMESTAMP(s->start_timestamp.realtime));
1843
1844 if (dual_timestamp_is_set(&s->exit_timestamp))
1845 fprintf(f,
1846 "%sExit Timestamp: %s\n"
1847 "%sExit Code: %s\n"
1848 "%sExit Status: %i\n",
1849 prefix, FORMAT_TIMESTAMP(s->exit_timestamp.realtime),
1850 prefix, sigchld_code_to_string(s->code),
1851 prefix, s->status);
1852 }
1853
1854 static void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
1855 _cleanup_free_ char *cmd = NULL;
1856 const char *prefix2;
1857
1858 assert(c);
1859 assert(f);
1860
1861 prefix = strempty(prefix);
1862 prefix2 = strjoina(prefix, "\t");
1863
1864 cmd = quote_command_line(c->argv, SHELL_ESCAPE_EMPTY);
1865
1866 fprintf(f,
1867 "%sCommand Line: %s\n",
1868 prefix, strnull(cmd));
1869
1870 exec_status_dump(&c->exec_status, f, prefix2);
1871 }
1872
1873 void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
1874 assert(f);
1875
1876 prefix = strempty(prefix);
1877
1878 LIST_FOREACH(command, i, c)
1879 exec_command_dump(i, f, prefix);
1880 }
1881
1882 void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
1883 ExecCommand *end;
1884
1885 assert(l);
1886 assert(e);
1887
1888 if (*l) {
1889 /* It's kind of important, that we keep the order here */
1890 end = LIST_FIND_TAIL(command, *l);
1891 LIST_INSERT_AFTER(command, *l, end, e);
1892 } else
1893 *l = e;
1894 }
1895
1896 int exec_command_set(ExecCommand *c, const char *path, ...) {
1897 va_list ap;
1898 char **l, *p;
1899
1900 assert(c);
1901 assert(path);
1902
1903 va_start(ap, path);
1904 l = strv_new_ap(path, ap);
1905 va_end(ap);
1906
1907 if (!l)
1908 return -ENOMEM;
1909
1910 p = strdup(path);
1911 if (!p) {
1912 strv_free(l);
1913 return -ENOMEM;
1914 }
1915
1916 free_and_replace(c->path, p);
1917
1918 return strv_free_and_replace(c->argv, l);
1919 }
1920
1921 int exec_command_append(ExecCommand *c, const char *path, ...) {
1922 _cleanup_strv_free_ char **l = NULL;
1923 va_list ap;
1924 int r;
1925
1926 assert(c);
1927 assert(path);
1928
1929 va_start(ap, path);
1930 l = strv_new_ap(path, ap);
1931 va_end(ap);
1932
1933 if (!l)
1934 return -ENOMEM;
1935
1936 r = strv_extend_strv(&c->argv, l, false);
1937 if (r < 0)
1938 return r;
1939
1940 return 0;
1941 }
1942
1943 static char *destroy_tree(char *path) {
1944 if (!path)
1945 return NULL;
1946
1947 if (!path_equal(path, RUN_SYSTEMD_EMPTY)) {
1948 log_debug("Spawning process to nuke '%s'", path);
1949
1950 (void) asynchronous_rm_rf(path, REMOVE_ROOT|REMOVE_SUBVOLUME|REMOVE_PHYSICAL);
1951 }
1952
1953 return mfree(path);
1954 }
1955
1956 void exec_shared_runtime_done(ExecSharedRuntime *rt) {
1957 if (!rt)
1958 return;
1959
1960 if (rt->manager)
1961 (void) hashmap_remove(rt->manager->exec_shared_runtime_by_id, rt->id);
1962
1963 rt->id = mfree(rt->id);
1964 rt->tmp_dir = mfree(rt->tmp_dir);
1965 rt->var_tmp_dir = mfree(rt->var_tmp_dir);
1966 safe_close_pair(rt->netns_storage_socket);
1967 safe_close_pair(rt->ipcns_storage_socket);
1968 }
1969
1970 static ExecSharedRuntime* exec_shared_runtime_free(ExecSharedRuntime *rt) {
1971 exec_shared_runtime_done(rt);
1972
1973 return mfree(rt);
1974 }
1975
1976 DEFINE_TRIVIAL_UNREF_FUNC(ExecSharedRuntime, exec_shared_runtime, exec_shared_runtime_free);
1977 DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSharedRuntime*, exec_shared_runtime_free);
1978
1979 ExecSharedRuntime* exec_shared_runtime_destroy(ExecSharedRuntime *rt) {
1980 if (!rt)
1981 return NULL;
1982
1983 assert(rt->n_ref > 0);
1984 rt->n_ref--;
1985
1986 if (rt->n_ref > 0)
1987 return NULL;
1988
1989 rt->tmp_dir = destroy_tree(rt->tmp_dir);
1990 rt->var_tmp_dir = destroy_tree(rt->var_tmp_dir);
1991
1992 return exec_shared_runtime_free(rt);
1993 }
1994
1995 static int exec_shared_runtime_allocate(ExecSharedRuntime **ret, const char *id) {
1996 _cleanup_free_ char *id_copy = NULL;
1997 ExecSharedRuntime *n;
1998
1999 assert(ret);
2000
2001 id_copy = strdup(id);
2002 if (!id_copy)
2003 return -ENOMEM;
2004
2005 n = new(ExecSharedRuntime, 1);
2006 if (!n)
2007 return -ENOMEM;
2008
2009 *n = (ExecSharedRuntime) {
2010 .id = TAKE_PTR(id_copy),
2011 .netns_storage_socket = EBADF_PAIR,
2012 .ipcns_storage_socket = EBADF_PAIR,
2013 };
2014
2015 *ret = n;
2016 return 0;
2017 }
2018
2019 static int exec_shared_runtime_add(
2020 Manager *m,
2021 const char *id,
2022 char **tmp_dir,
2023 char **var_tmp_dir,
2024 int netns_storage_socket[2],
2025 int ipcns_storage_socket[2],
2026 ExecSharedRuntime **ret) {
2027
2028 _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt = NULL;
2029 int r;
2030
2031 assert(m);
2032 assert(id);
2033
2034 /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
2035
2036 r = exec_shared_runtime_allocate(&rt, id);
2037 if (r < 0)
2038 return r;
2039
2040 r = hashmap_ensure_put(&m->exec_shared_runtime_by_id, &string_hash_ops, rt->id, rt);
2041 if (r < 0)
2042 return r;
2043
2044 assert(!!rt->tmp_dir == !!rt->var_tmp_dir); /* We require both to be set together */
2045 rt->tmp_dir = TAKE_PTR(*tmp_dir);
2046 rt->var_tmp_dir = TAKE_PTR(*var_tmp_dir);
2047
2048 if (netns_storage_socket) {
2049 rt->netns_storage_socket[0] = TAKE_FD(netns_storage_socket[0]);
2050 rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
2051 }
2052
2053 if (ipcns_storage_socket) {
2054 rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
2055 rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
2056 }
2057
2058 rt->manager = m;
2059
2060 if (ret)
2061 *ret = rt;
2062 /* do not remove created ExecSharedRuntime object when the operation succeeds. */
2063 TAKE_PTR(rt);
2064 return 0;
2065 }
2066
2067 static int exec_shared_runtime_make(
2068 Manager *m,
2069 const ExecContext *c,
2070 const char *id,
2071 ExecSharedRuntime **ret) {
2072
2073 _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
2074 _cleanup_close_pair_ int netns_storage_socket[2] = EBADF_PAIR, ipcns_storage_socket[2] = EBADF_PAIR;
2075 int r;
2076
2077 assert(m);
2078 assert(c);
2079 assert(id);
2080
2081 /* It is not necessary to create ExecSharedRuntime object. */
2082 if (!exec_needs_network_namespace(c) && !exec_needs_ipc_namespace(c) && !c->private_tmp) {
2083 *ret = NULL;
2084 return 0;
2085 }
2086
2087 if (c->private_tmp &&
2088 !(prefixed_path_strv_contains(c->inaccessible_paths, "/tmp") &&
2089 (prefixed_path_strv_contains(c->inaccessible_paths, "/var/tmp") ||
2090 prefixed_path_strv_contains(c->inaccessible_paths, "/var")))) {
2091 r = setup_tmp_dirs(id, &tmp_dir, &var_tmp_dir);
2092 if (r < 0)
2093 return r;
2094 }
2095
2096 if (exec_needs_network_namespace(c)) {
2097 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, netns_storage_socket) < 0)
2098 return -errno;
2099 }
2100
2101 if (exec_needs_ipc_namespace(c)) {
2102 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
2103 return -errno;
2104 }
2105
2106 r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
2107 if (r < 0)
2108 return r;
2109
2110 return 1;
2111 }
2112
2113 int exec_shared_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecSharedRuntime **ret) {
2114 ExecSharedRuntime *rt;
2115 int r;
2116
2117 assert(m);
2118 assert(id);
2119 assert(ret);
2120
2121 rt = hashmap_get(m->exec_shared_runtime_by_id, id);
2122 if (rt)
2123 /* We already have an ExecSharedRuntime object, let's increase the ref count and reuse it */
2124 goto ref;
2125
2126 if (!create) {
2127 *ret = NULL;
2128 return 0;
2129 }
2130
2131 /* If not found, then create a new object. */
2132 r = exec_shared_runtime_make(m, c, id, &rt);
2133 if (r < 0)
2134 return r;
2135 if (r == 0) {
2136 /* When r == 0, it is not necessary to create ExecSharedRuntime object. */
2137 *ret = NULL;
2138 return 0;
2139 }
2140
2141 ref:
2142 /* increment reference counter. */
2143 rt->n_ref++;
2144 *ret = rt;
2145 return 1;
2146 }
2147
2148 int exec_shared_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
2149 ExecSharedRuntime *rt;
2150
2151 assert(m);
2152 assert(f);
2153 assert(fds);
2154
2155 HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
2156 fprintf(f, "exec-runtime=%s", rt->id);
2157
2158 if (rt->tmp_dir)
2159 fprintf(f, " tmp-dir=%s", rt->tmp_dir);
2160
2161 if (rt->var_tmp_dir)
2162 fprintf(f, " var-tmp-dir=%s", rt->var_tmp_dir);
2163
2164 if (rt->netns_storage_socket[0] >= 0) {
2165 int copy;
2166
2167 copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
2168 if (copy < 0)
2169 return copy;
2170
2171 fprintf(f, " netns-socket-0=%i", copy);
2172 }
2173
2174 if (rt->netns_storage_socket[1] >= 0) {
2175 int copy;
2176
2177 copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
2178 if (copy < 0)
2179 return copy;
2180
2181 fprintf(f, " netns-socket-1=%i", copy);
2182 }
2183
2184 if (rt->ipcns_storage_socket[0] >= 0) {
2185 int copy;
2186
2187 copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
2188 if (copy < 0)
2189 return copy;
2190
2191 fprintf(f, " ipcns-socket-0=%i", copy);
2192 }
2193
2194 if (rt->ipcns_storage_socket[1] >= 0) {
2195 int copy;
2196
2197 copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
2198 if (copy < 0)
2199 return copy;
2200
2201 fprintf(f, " ipcns-socket-1=%i", copy);
2202 }
2203
2204 fputc('\n', f);
2205 }
2206
2207 return 0;
2208 }
2209
2210 int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
2211 _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt_create = NULL;
2212 ExecSharedRuntime *rt = NULL;
2213 int r;
2214
2215 /* This is for the migration from old (v237 or earlier) deserialization text.
2216 * Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
2217 * Even if the ExecSharedRuntime object originally created by the other unit, we cannot judge
2218 * so or not from the serialized text, then we always creates a new object owned by this. */
2219
2220 assert(u);
2221 assert(key);
2222 assert(value);
2223
2224 /* Manager manages ExecSharedRuntime objects by the unit id.
2225 * So, we omit the serialized text when the unit does not have id (yet?)... */
2226 if (isempty(u->id)) {
2227 log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.");
2228 return 0;
2229 }
2230
2231 if (u->manager) {
2232 if (hashmap_ensure_allocated(&u->manager->exec_shared_runtime_by_id, &string_hash_ops) < 0)
2233 return log_oom();
2234
2235 rt = hashmap_get(u->manager->exec_shared_runtime_by_id, u->id);
2236 }
2237 if (!rt) {
2238 if (exec_shared_runtime_allocate(&rt_create, u->id) < 0)
2239 return log_oom();
2240
2241 rt = rt_create;
2242 }
2243
2244 if (streq(key, "tmp-dir")) {
2245 if (free_and_strdup_warn(&rt->tmp_dir, value) < 0)
2246 return -ENOMEM;
2247
2248 } else if (streq(key, "var-tmp-dir")) {
2249 if (free_and_strdup_warn(&rt->var_tmp_dir, value) < 0)
2250 return -ENOMEM;
2251
2252 } else if (streq(key, "netns-socket-0")) {
2253
2254 safe_close(rt->netns_storage_socket[0]);
2255 rt->netns_storage_socket[0] = deserialize_fd(fds, value);
2256 if (rt->netns_storage_socket[0] < 0)
2257 return 0;
2258
2259 } else if (streq(key, "netns-socket-1")) {
2260
2261 safe_close(rt->netns_storage_socket[1]);
2262 rt->netns_storage_socket[1] = deserialize_fd(fds, value);
2263 if (rt->netns_storage_socket[1] < 0)
2264 return 0;
2265 } else
2266 return 0;
2267
2268 /* If the object is newly created, then put it to the hashmap which manages ExecSharedRuntime objects. */
2269 if (rt_create && u->manager) {
2270 r = hashmap_put(u->manager->exec_shared_runtime_by_id, rt_create->id, rt_create);
2271 if (r < 0) {
2272 log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m");
2273 return 0;
2274 }
2275
2276 rt_create->manager = u->manager;
2277
2278 /* Avoid cleanup */
2279 TAKE_PTR(rt_create);
2280 }
2281
2282 return 1;
2283 }
2284
2285 int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
2286 _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
2287 char *id = NULL;
2288 int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
2289 const char *p, *v = ASSERT_PTR(value);
2290 size_t n;
2291
2292 assert(m);
2293 assert(fds);
2294
2295 n = strcspn(v, " ");
2296 id = strndupa_safe(v, n);
2297 if (v[n] != ' ')
2298 goto finalize;
2299 p = v + n + 1;
2300
2301 v = startswith(p, "tmp-dir=");
2302 if (v) {
2303 n = strcspn(v, " ");
2304 tmp_dir = strndup(v, n);
2305 if (!tmp_dir)
2306 return log_oom();
2307 if (v[n] != ' ')
2308 goto finalize;
2309 p = v + n + 1;
2310 }
2311
2312 v = startswith(p, "var-tmp-dir=");
2313 if (v) {
2314 n = strcspn(v, " ");
2315 var_tmp_dir = strndup(v, n);
2316 if (!var_tmp_dir)
2317 return log_oom();
2318 if (v[n] != ' ')
2319 goto finalize;
2320 p = v + n + 1;
2321 }
2322
2323 v = startswith(p, "netns-socket-0=");
2324 if (v) {
2325 char *buf;
2326
2327 n = strcspn(v, " ");
2328 buf = strndupa_safe(v, n);
2329
2330 netns_fdpair[0] = deserialize_fd(fds, buf);
2331 if (netns_fdpair[0] < 0)
2332 return netns_fdpair[0];
2333 if (v[n] != ' ')
2334 goto finalize;
2335 p = v + n + 1;
2336 }
2337
2338 v = startswith(p, "netns-socket-1=");
2339 if (v) {
2340 char *buf;
2341
2342 n = strcspn(v, " ");
2343 buf = strndupa_safe(v, n);
2344
2345 netns_fdpair[1] = deserialize_fd(fds, buf);
2346 if (netns_fdpair[1] < 0)
2347 return netns_fdpair[1];
2348 if (v[n] != ' ')
2349 goto finalize;
2350 p = v + n + 1;
2351 }
2352
2353 v = startswith(p, "ipcns-socket-0=");
2354 if (v) {
2355 char *buf;
2356
2357 n = strcspn(v, " ");
2358 buf = strndupa_safe(v, n);
2359
2360 ipcns_fdpair[0] = deserialize_fd(fds, buf);
2361 if (ipcns_fdpair[0] < 0)
2362 return ipcns_fdpair[0];
2363 if (v[n] != ' ')
2364 goto finalize;
2365 p = v + n + 1;
2366 }
2367
2368 v = startswith(p, "ipcns-socket-1=");
2369 if (v) {
2370 char *buf;
2371
2372 n = strcspn(v, " ");
2373 buf = strndupa_safe(v, n);
2374
2375 ipcns_fdpair[1] = deserialize_fd(fds, buf);
2376 if (ipcns_fdpair[1] < 0)
2377 return ipcns_fdpair[1];
2378 }
2379
2380 finalize:
2381 r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
2382 if (r < 0)
2383 return log_debug_errno(r, "Failed to add exec-runtime: %m");
2384 return 0;
2385 }
2386
2387 void exec_shared_runtime_vacuum(Manager *m) {
2388 ExecSharedRuntime *rt;
2389
2390 assert(m);
2391
2392 /* Free unreferenced ExecSharedRuntime objects. This is used after manager deserialization process. */
2393
2394 HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
2395 if (rt->n_ref > 0)
2396 continue;
2397
2398 (void) exec_shared_runtime_free(rt);
2399 }
2400 }
2401
2402 int exec_runtime_make(
2403 const Unit *unit,
2404 const ExecContext *context,
2405 ExecSharedRuntime *shared,
2406 DynamicCreds *creds,
2407 ExecRuntime **ret) {
2408 _cleanup_close_pair_ int ephemeral_storage_socket[2] = EBADF_PAIR;
2409 _cleanup_free_ char *ephemeral = NULL;
2410 _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
2411 int r;
2412
2413 assert(unit);
2414 assert(context);
2415 assert(ret);
2416
2417 if (!shared && !creds && !exec_needs_ephemeral(context)) {
2418 *ret = NULL;
2419 return 0;
2420 }
2421
2422 if (exec_needs_ephemeral(context)) {
2423 r = mkdir_p("/var/lib/systemd/ephemeral-trees", 0755);
2424 if (r < 0)
2425 return r;
2426
2427 r = tempfn_random_child("/var/lib/systemd/ephemeral-trees", unit->id, &ephemeral);
2428 if (r < 0)
2429 return r;
2430
2431 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ephemeral_storage_socket) < 0)
2432 return -errno;
2433 }
2434
2435 rt = new(ExecRuntime, 1);
2436 if (!rt)
2437 return -ENOMEM;
2438
2439 *rt = (ExecRuntime) {
2440 .shared = shared,
2441 .dynamic_creds = creds,
2442 .ephemeral_copy = TAKE_PTR(ephemeral),
2443 .ephemeral_storage_socket[0] = TAKE_FD(ephemeral_storage_socket[0]),
2444 .ephemeral_storage_socket[1] = TAKE_FD(ephemeral_storage_socket[1]),
2445 };
2446
2447 *ret = TAKE_PTR(rt);
2448 return 1;
2449 }
2450
2451 ExecRuntime* exec_runtime_free(ExecRuntime *rt) {
2452 if (!rt)
2453 return NULL;
2454
2455 exec_shared_runtime_unref(rt->shared);
2456 dynamic_creds_unref(rt->dynamic_creds);
2457
2458 rt->ephemeral_copy = destroy_tree(rt->ephemeral_copy);
2459
2460 safe_close_pair(rt->ephemeral_storage_socket);
2461 return mfree(rt);
2462 }
2463
2464 ExecRuntime* exec_runtime_destroy(ExecRuntime *rt) {
2465 if (!rt)
2466 return NULL;
2467
2468 rt->shared = exec_shared_runtime_destroy(rt->shared);
2469 rt->dynamic_creds = dynamic_creds_destroy(rt->dynamic_creds);
2470 return exec_runtime_free(rt);
2471 }
2472
2473 void exec_runtime_clear(ExecRuntime *rt) {
2474 if (!rt)
2475 return;
2476
2477 safe_close_pair(rt->ephemeral_storage_socket);
2478 rt->ephemeral_copy = mfree(rt->ephemeral_copy);
2479 }
2480
2481 void exec_params_shallow_clear(ExecParameters *p) {
2482 if (!p)
2483 return;
2484
2485 /* This is called on the PID1 side, as many of the struct's FDs are only borrowed, and actually
2486 * owned by the manager or other objects, and reused across multiple units. */
2487
2488 p->environment = strv_free(p->environment);
2489 p->fd_names = strv_free(p->fd_names);
2490 p->files_env = strv_free(p->files_env);
2491 p->fds = mfree(p->fds);
2492 p->exec_fd = safe_close(p->exec_fd);
2493 p->user_lookup_fd = -EBADF;
2494 p->bpf_outer_map_fd = -EBADF;
2495 p->unit_id = mfree(p->unit_id);
2496 p->invocation_id = SD_ID128_NULL;
2497 p->invocation_id_string[0] = '\0';
2498 p->confirm_spawn = mfree(p->confirm_spawn);
2499 }
2500
2501 void exec_params_deep_clear(ExecParameters *p) {
2502 if (!p)
2503 return;
2504
2505 /* This is called on the sd-executor side, where everything received is owned by the process and has
2506 * to be fully cleaned up to make sanitizers and analyzers happy, as opposed as the shallow clean
2507 * function above. */
2508
2509 close_many_unset(p->fds, p->n_socket_fds + p->n_storage_fds);
2510
2511 p->cgroup_path = mfree(p->cgroup_path);
2512
2513 if (p->prefix) {
2514 free_many_charp(p->prefix, _EXEC_DIRECTORY_TYPE_MAX);
2515 p->prefix = mfree(p->prefix);
2516 }
2517
2518 p->received_credentials_directory = mfree(p->received_credentials_directory);
2519 p->received_encrypted_credentials_directory = mfree(p->received_encrypted_credentials_directory);
2520
2521 if (p->idle_pipe) {
2522 close_many_and_free(p->idle_pipe, 4);
2523 p->idle_pipe = NULL;
2524 }
2525
2526 p->stdin_fd = safe_close(p->stdin_fd);
2527 p->stdout_fd = safe_close(p->stdout_fd);
2528 p->stderr_fd = safe_close(p->stderr_fd);
2529
2530 p->notify_socket = mfree(p->notify_socket);
2531
2532 open_file_free_many(&p->open_files);
2533
2534 p->fallback_smack_process_label = mfree(p->fallback_smack_process_label);
2535
2536 exec_params_shallow_clear(p);
2537 }
2538
2539 void exec_directory_done(ExecDirectory *d) {
2540 if (!d)
2541 return;
2542
2543 FOREACH_ARRAY(i, d->items, d->n_items) {
2544 free(i->path);
2545 strv_free(i->symlinks);
2546 }
2547
2548 d->items = mfree(d->items);
2549 d->n_items = 0;
2550 d->mode = 0755;
2551 }
2552
2553 static ExecDirectoryItem *exec_directory_find(ExecDirectory *d, const char *path) {
2554 assert(d);
2555 assert(path);
2556
2557 FOREACH_ARRAY(i, d->items, d->n_items)
2558 if (path_equal(i->path, path))
2559 return i;
2560
2561 return NULL;
2562 }
2563
2564 int exec_directory_add(ExecDirectory *d, const char *path, const char *symlink) {
2565 _cleanup_strv_free_ char **s = NULL;
2566 _cleanup_free_ char *p = NULL;
2567 ExecDirectoryItem *existing;
2568 int r;
2569
2570 assert(d);
2571 assert(path);
2572
2573 existing = exec_directory_find(d, path);
2574 if (existing) {
2575 r = strv_extend(&existing->symlinks, symlink);
2576 if (r < 0)
2577 return r;
2578
2579 return 0; /* existing item is updated */
2580 }
2581
2582 p = strdup(path);
2583 if (!p)
2584 return -ENOMEM;
2585
2586 if (symlink) {
2587 s = strv_new(symlink);
2588 if (!s)
2589 return -ENOMEM;
2590 }
2591
2592 if (!GREEDY_REALLOC(d->items, d->n_items + 1))
2593 return -ENOMEM;
2594
2595 d->items[d->n_items++] = (ExecDirectoryItem) {
2596 .path = TAKE_PTR(p),
2597 .symlinks = TAKE_PTR(s),
2598 };
2599
2600 return 1; /* new item is added */
2601 }
2602
2603 static int exec_directory_item_compare_func(const ExecDirectoryItem *a, const ExecDirectoryItem *b) {
2604 assert(a);
2605 assert(b);
2606
2607 return path_compare(a->path, b->path);
2608 }
2609
2610 void exec_directory_sort(ExecDirectory *d) {
2611 assert(d);
2612
2613 /* Sort the exec directories to make always parent directories processed at first in
2614 * setup_exec_directory(), e.g., even if StateDirectory=foo/bar foo, we need to create foo at first,
2615 * then foo/bar. Also, set .only_create flag if one of the parent directories is contained in the
2616 * list. See also comments in setup_exec_directory() and issue #24783. */
2617
2618 if (d->n_items <= 1)
2619 return;
2620
2621 typesafe_qsort(d->items, d->n_items, exec_directory_item_compare_func);
2622
2623 for (size_t i = 1; i < d->n_items; i++)
2624 for (size_t j = 0; j < i; j++)
2625 if (path_startswith(d->items[i].path, d->items[j].path)) {
2626 d->items[i].only_create = true;
2627 break;
2628 }
2629 }
2630
2631 ExecCleanMask exec_clean_mask_from_string(const char *s) {
2632 ExecDirectoryType t;
2633
2634 assert(s);
2635
2636 if (streq(s, "all"))
2637 return EXEC_CLEAN_ALL;
2638 if (streq(s, "fdstore"))
2639 return EXEC_CLEAN_FDSTORE;
2640
2641 t = exec_resource_type_from_string(s);
2642 if (t < 0)
2643 return (ExecCleanMask) t;
2644
2645 return 1U << t;
2646 }
2647
2648 static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
2649 [EXEC_INPUT_NULL] = "null",
2650 [EXEC_INPUT_TTY] = "tty",
2651 [EXEC_INPUT_TTY_FORCE] = "tty-force",
2652 [EXEC_INPUT_TTY_FAIL] = "tty-fail",
2653 [EXEC_INPUT_SOCKET] = "socket",
2654 [EXEC_INPUT_NAMED_FD] = "fd",
2655 [EXEC_INPUT_DATA] = "data",
2656 [EXEC_INPUT_FILE] = "file",
2657 };
2658
2659 DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
2660
2661 static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
2662 [EXEC_OUTPUT_INHERIT] = "inherit",
2663 [EXEC_OUTPUT_NULL] = "null",
2664 [EXEC_OUTPUT_TTY] = "tty",
2665 [EXEC_OUTPUT_KMSG] = "kmsg",
2666 [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
2667 [EXEC_OUTPUT_JOURNAL] = "journal",
2668 [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
2669 [EXEC_OUTPUT_SOCKET] = "socket",
2670 [EXEC_OUTPUT_NAMED_FD] = "fd",
2671 [EXEC_OUTPUT_FILE] = "file",
2672 [EXEC_OUTPUT_FILE_APPEND] = "append",
2673 [EXEC_OUTPUT_FILE_TRUNCATE] = "truncate",
2674 };
2675
2676 DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
2677
2678 static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
2679 [EXEC_UTMP_INIT] = "init",
2680 [EXEC_UTMP_LOGIN] = "login",
2681 [EXEC_UTMP_USER] = "user",
2682 };
2683
2684 DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode);
2685
2686 static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
2687 [EXEC_PRESERVE_NO] = "no",
2688 [EXEC_PRESERVE_YES] = "yes",
2689 [EXEC_PRESERVE_RESTART] = "restart",
2690 };
2691
2692 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
2693
2694 /* This table maps ExecDirectoryType to the setting it is configured with in the unit */
2695 static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2696 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory",
2697 [EXEC_DIRECTORY_STATE] = "StateDirectory",
2698 [EXEC_DIRECTORY_CACHE] = "CacheDirectory",
2699 [EXEC_DIRECTORY_LOGS] = "LogsDirectory",
2700 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
2701 };
2702
2703 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
2704
2705 /* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
2706 static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2707 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectorySymlink",
2708 [EXEC_DIRECTORY_STATE] = "StateDirectorySymlink",
2709 [EXEC_DIRECTORY_CACHE] = "CacheDirectorySymlink",
2710 [EXEC_DIRECTORY_LOGS] = "LogsDirectorySymlink",
2711 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectorySymlink",
2712 };
2713
2714 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink, ExecDirectoryType);
2715
2716 static const char* const exec_directory_type_mode_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2717 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectoryMode",
2718 [EXEC_DIRECTORY_STATE] = "StateDirectoryMode",
2719 [EXEC_DIRECTORY_CACHE] = "CacheDirectoryMode",
2720 [EXEC_DIRECTORY_LOGS] = "LogsDirectoryMode",
2721 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectoryMode",
2722 };
2723
2724 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_mode, ExecDirectoryType);
2725
2726 /* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This
2727 * one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit
2728 * directories, specifically .timer units with their timestamp touch file. */
2729 static const char* const exec_resource_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2730 [EXEC_DIRECTORY_RUNTIME] = "runtime",
2731 [EXEC_DIRECTORY_STATE] = "state",
2732 [EXEC_DIRECTORY_CACHE] = "cache",
2733 [EXEC_DIRECTORY_LOGS] = "logs",
2734 [EXEC_DIRECTORY_CONFIGURATION] = "configuration",
2735 };
2736
2737 DEFINE_STRING_TABLE_LOOKUP(exec_resource_type, ExecDirectoryType);
2738
2739 static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
2740 [EXEC_KEYRING_INHERIT] = "inherit",
2741 [EXEC_KEYRING_PRIVATE] = "private",
2742 [EXEC_KEYRING_SHARED] = "shared",
2743 };
2744
2745 DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode, ExecKeyringMode);