1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include <sys/personality.h>
11 #include <sys/types.h>
16 #include <linux/fs.h> /* Must be included after <sys/mount.h> */
18 #include "sd-messages.h"
21 #include "alloc-util.h"
24 #include "capability-util.h"
25 #include "cgroup-setup.h"
26 #include "constants.h"
27 #include "cpu-set-util.h"
30 #include "errno-list.h"
32 #include "exec-credential.h"
34 #include "execute-serialize.h"
35 #include "exit-status.h"
38 #include "format-util.h"
39 #include "glob-util.h"
40 #include "hexdecoct.h"
41 #include "ioprio-util.h"
42 #include "lock-util.h"
46 #include "manager-dump.h"
47 #include "memory-util.h"
48 #include "missing_fs.h"
49 #include "missing_prctl.h"
50 #include "mkdir-label.h"
51 #include "namespace.h"
52 #include "parse-util.h"
53 #include "path-util.h"
54 #include "process-util.h"
55 #include "rlimit-util.h"
57 #include "seccomp-util.h"
58 #include "securebits-util.h"
59 #include "selinux-util.h"
60 #include "serialize.h"
61 #include "sort-util.h"
63 #include "stat-util.h"
64 #include "string-table.h"
65 #include "string-util.h"
67 #include "syslog-util.h"
68 #include "terminal-util.h"
69 #include "tmpfile-util.h"
70 #include "umask-util.h"
71 #include "unit-serialize.h"
72 #include "user-util.h"
73 #include "utmp-wtmp.h"
75 const char *exec_context_tty_path(const ExecContext
*context
) {
78 if (context
->stdio_as_fds
)
81 if (context
->tty_path
)
82 return context
->tty_path
;
84 return "/dev/console";
87 int exec_context_tty_size(const ExecContext
*context
, unsigned *ret_rows
, unsigned *ret_cols
) {
95 rows
= context
->tty_rows
;
96 cols
= context
->tty_cols
;
98 tty
= exec_context_tty_path(context
);
100 (void) proc_cmdline_tty_size(tty
, rows
== UINT_MAX
? &rows
: NULL
, cols
== UINT_MAX
? &cols
: NULL
);
108 void exec_context_tty_reset(const ExecContext
*context
, const ExecParameters
*p
) {
109 _cleanup_close_
int fd
= -EBADF
;
110 const char *path
= exec_context_tty_path(ASSERT_PTR(context
));
112 /* Take a lock around the device for the duration of the setup that we do here.
113 * systemd-vconsole-setup.service also takes the lock to avoid being interrupted.
114 * We open a new fd that will be closed automatically, and operate on it for convenience.
117 if (p
&& p
->stdin_fd
>= 0) {
118 fd
= xopenat_lock(p
->stdin_fd
, NULL
,
119 O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
, 0, 0, LOCK_BSD
, LOCK_EX
);
123 fd
= open_terminal(path
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
127 if (lock_generic(fd
, LOCK_BSD
, LOCK_EX
) < 0)
130 return; /* nothing to do */
132 if (context
->tty_vhangup
)
133 (void) terminal_vhangup_fd(fd
);
135 if (context
->tty_reset
)
136 (void) reset_terminal_fd(fd
, true);
138 if (p
&& p
->stdin_fd
>= 0) {
139 unsigned rows
= context
->tty_rows
, cols
= context
->tty_cols
;
141 (void) exec_context_tty_size(context
, &rows
, &cols
);
142 (void) terminal_set_size_fd(p
->stdin_fd
, path
, rows
, cols
);
145 if (context
->tty_vt_disallocate
&& path
)
146 (void) vt_disallocate(path
);
149 static bool is_terminal_input(ExecInput i
) {
152 EXEC_INPUT_TTY_FORCE
,
153 EXEC_INPUT_TTY_FAIL
);
156 static bool is_terminal_output(ExecOutput o
) {
159 EXEC_OUTPUT_KMSG_AND_CONSOLE
,
160 EXEC_OUTPUT_JOURNAL_AND_CONSOLE
);
163 bool exec_needs_network_namespace(const ExecContext
*context
) {
166 return context
->private_network
|| context
->network_namespace_path
;
169 static bool exec_needs_ephemeral(const ExecContext
*context
) {
170 return (context
->root_image
|| context
->root_directory
) && context
->root_ephemeral
;
173 bool exec_needs_ipc_namespace(const ExecContext
*context
) {
176 return context
->private_ipc
|| context
->ipc_namespace_path
;
179 bool exec_needs_mount_namespace(
180 const ExecContext
*context
,
181 const ExecParameters
*params
,
182 const ExecRuntime
*runtime
) {
186 if (context
->root_image
)
189 if (!strv_isempty(context
->read_write_paths
) ||
190 !strv_isempty(context
->read_only_paths
) ||
191 !strv_isempty(context
->inaccessible_paths
) ||
192 !strv_isempty(context
->exec_paths
) ||
193 !strv_isempty(context
->no_exec_paths
))
196 if (context
->n_bind_mounts
> 0)
199 if (context
->n_temporary_filesystems
> 0)
202 if (context
->n_mount_images
> 0)
205 if (context
->n_extension_images
> 0)
208 if (!strv_isempty(context
->extension_directories
))
211 if (!IN_SET(context
->mount_propagation_flag
, 0, MS_SHARED
))
214 if (context
->private_tmp
&& runtime
&& runtime
->shared
&& (runtime
->shared
->tmp_dir
|| runtime
->shared
->var_tmp_dir
))
217 if (context
->private_devices
||
218 context
->private_mounts
> 0 ||
219 (context
->private_mounts
< 0 && exec_needs_network_namespace(context
)) ||
220 context
->protect_system
!= PROTECT_SYSTEM_NO
||
221 context
->protect_home
!= PROTECT_HOME_NO
||
222 context
->protect_kernel_tunables
||
223 context
->protect_kernel_modules
||
224 context
->protect_kernel_logs
||
225 context
->protect_control_groups
||
226 context
->protect_proc
!= PROTECT_PROC_DEFAULT
||
227 context
->proc_subset
!= PROC_SUBSET_ALL
||
228 exec_needs_ipc_namespace(context
))
231 if (context
->root_directory
) {
232 if (exec_context_get_effective_mount_apivfs(context
))
235 for (ExecDirectoryType t
= 0; t
< _EXEC_DIRECTORY_TYPE_MAX
; t
++) {
236 if (params
&& !params
->prefix
[t
])
239 if (context
->directories
[t
].n_items
> 0)
244 if (context
->dynamic_user
&&
245 (context
->directories
[EXEC_DIRECTORY_STATE
].n_items
> 0 ||
246 context
->directories
[EXEC_DIRECTORY_CACHE
].n_items
> 0 ||
247 context
->directories
[EXEC_DIRECTORY_LOGS
].n_items
> 0))
250 if (context
->log_namespace
)
256 bool exec_directory_is_private(const ExecContext
*context
, ExecDirectoryType type
) {
259 if (!context
->dynamic_user
)
262 if (type
== EXEC_DIRECTORY_CONFIGURATION
)
265 if (type
== EXEC_DIRECTORY_RUNTIME
&& context
->runtime_directory_preserve_mode
== EXEC_PRESERVE_NO
)
271 int exec_params_get_cgroup_path(
272 const ExecParameters
*params
,
273 const CGroupContext
*c
,
276 const char *subgroup
= NULL
;
282 if (!params
->cgroup_path
)
285 /* If we are called for a unit where cgroup delegation is on, and the payload created its own populated
286 * subcgroup (which we expect it to do, after all it asked for delegation), then we cannot place the control
287 * processes started after the main unit's process in the unit's main cgroup because it is now an inner one,
288 * and inner cgroups may not contain processes. Hence, if delegation is on, and this is a control process,
289 * let's use ".control" as subcgroup instead. Note that we do so only for ExecStartPost=, ExecReload=,
290 * ExecStop=, ExecStopPost=, i.e. for the commands where the main process is already forked. For ExecStartPre=
291 * this is not necessary, the cgroup is still empty. We distinguish these cases with the EXEC_CONTROL_CGROUP
292 * flag, which is only passed for the former statements, not for the latter. */
294 if (FLAGS_SET(params
->flags
, EXEC_CGROUP_DELEGATE
) && (FLAGS_SET(params
->flags
, EXEC_CONTROL_CGROUP
) || c
->delegate_subgroup
)) {
295 if (FLAGS_SET(params
->flags
, EXEC_IS_CONTROL
))
296 subgroup
= ".control";
298 subgroup
= c
->delegate_subgroup
;
302 p
= path_join(params
->cgroup_path
, subgroup
);
304 p
= strdup(params
->cgroup_path
);
312 bool exec_context_get_cpu_affinity_from_numa(const ExecContext
*c
) {
315 return c
->cpu_affinity_from_numa
;
318 static void log_command_line(Unit
*unit
, const char *msg
, const char *executable
, char **argv
) {
326 _cleanup_free_
char *cmdline
= quote_command_line(argv
, SHELL_ESCAPE_EMPTY
);
328 log_unit_struct(unit
, LOG_DEBUG
,
329 "EXECUTABLE=%s", executable
,
330 LOG_UNIT_MESSAGE(unit
, "%s: %s", msg
, strnull(cmdline
)),
331 LOG_UNIT_INVOCATION_ID(unit
));
334 static int exec_context_load_environment(const Unit
*unit
, const ExecContext
*c
, char ***l
);
336 int exec_spawn(Unit
*unit
,
337 ExecCommand
*command
,
338 const ExecContext
*context
,
339 ExecParameters
*params
,
340 ExecRuntime
*runtime
,
341 const CGroupContext
*cgroup_context
,
344 char serialization_fd_number
[DECIMAL_STR_MAX(int) + 1];
345 _cleanup_free_
char *subcgroup_path
= NULL
, *log_level
= NULL
, *executor_path
= NULL
;
346 _cleanup_fdset_free_ FDSet
*fdset
= NULL
;
347 _cleanup_fclose_
FILE *f
= NULL
;
352 assert(unit
->manager
);
353 assert(unit
->manager
->executor_fd
>= 0);
358 assert(params
->fds
|| (params
->n_socket_fds
+ params
->n_storage_fds
<= 0));
359 assert(!params
->files_env
); /* We fill this field, ensure it comes NULL-initialized to us */
361 LOG_CONTEXT_PUSH_UNIT(unit
);
363 r
= exec_context_load_environment(unit
, context
, ¶ms
->files_env
);
365 return log_unit_error_errno(unit
, r
, "Failed to load environment files: %m");
367 /* Fork with up-to-date SELinux label database, so the child inherits the up-to-date db
368 and, until the next SELinux policy changes, we save further reloads in future children. */
369 mac_selinux_maybe_reload();
371 /* We won't know the real executable path until we create the mount namespace in the child, but we
372 want to log from the parent, so we use the possibly inaccurate path here. */
373 log_command_line(unit
, "About to execute", command
->path
, command
->argv
);
375 if (params
->cgroup_path
) {
376 r
= exec_params_get_cgroup_path(params
, cgroup_context
, &subcgroup_path
);
378 return log_unit_error_errno(unit
, r
, "Failed to acquire subcgroup path: %m");
380 /* If there's a subcgroup, then let's create it here now (the main cgroup was already
381 * realized by the unit logic) */
383 r
= cg_create(SYSTEMD_CGROUP_CONTROLLER
, subcgroup_path
);
385 return log_unit_error_errno(unit
, r
, "Failed to create subcgroup '%s': %m", subcgroup_path
);
389 /* In order to avoid copy-on-write traps and OOM-kills when pid1's memory.current is above the
390 * child's memory.max, serialize all the state needed to start the unit, and pass it to the
391 * systemd-executor binary. clone() with CLONE_VM + CLONE_VFORK will pause the parent until the exec
392 * and ensure all memory is shared. The child immediately execs the new binary so the delay should
393 * be minimal. Once glibc provides a clone3 wrapper we can switch to that, and clone directly in the
396 r
= open_serialization_file("sd-executor-state", &f
);
398 return log_unit_error_errno(unit
, r
, "Failed to open serialization stream: %m");
404 r
= exec_serialize_invocation(f
, fdset
, context
, command
, params
, runtime
, cgroup_context
);
406 return log_unit_error_errno(unit
, r
, "Failed to serialize parameters: %m");
408 if (fseeko(f
, 0, SEEK_SET
) < 0)
409 return log_unit_error_errno(unit
, errno
, "Failed to reseek on serialization stream: %m");
411 r
= fd_cloexec(fileno(f
), false);
413 return log_unit_error_errno(unit
, r
, "Failed to set O_CLOEXEC on serialization fd: %m");
415 r
= fdset_cloexec(fdset
, false);
417 return log_unit_error_errno(unit
, r
, "Failed to set O_CLOEXEC on serialized fds: %m");
419 r
= log_level_to_string_alloc(log_get_max_level(), &log_level
);
421 return log_unit_error_errno(unit
, r
, "Failed to convert log level to string: %m");
423 r
= fd_get_path(unit
->manager
->executor_fd
, &executor_path
);
425 return log_unit_error_errno(unit
, r
, "Failed to get executor path from fd: %m");
427 xsprintf(serialization_fd_number
, "%i", fileno(f
));
429 /* The executor binary is pinned, to avoid compatibility problems during upgrades. */
430 r
= posix_spawn_wrapper(
431 FORMAT_PROC_FD_PATH(unit
->manager
->executor_fd
),
432 STRV_MAKE(executor_path
,
433 "--deserialize", serialization_fd_number
,
434 "--log-level", log_level
,
435 "--log-target", log_target_to_string(manager_get_executor_log_target(unit
->manager
))),
439 return log_unit_error_errno(unit
, r
, "Failed to spawn executor: %m");
441 log_unit_debug(unit
, "Forked %s as "PID_FMT
, command
->path
, pid
);
443 /* We add the new process to the cgroup both in the child (so that we can be sure that no user code is ever
444 * executed outside of the cgroup) and in the parent (so that we can be sure that when we kill the cgroup the
445 * process will be killed too). */
447 (void) cg_attach(SYSTEMD_CGROUP_CONTROLLER
, subcgroup_path
, pid
);
449 exec_status_start(&command
->exec_status
, pid
);
455 void exec_context_init(ExecContext
*c
) {
458 /* When initializing a bool member to 'true', make sure to serialize in execute-serialize.c using
459 * serialize_bool() instead of serialize_bool_elide(). */
463 .ioprio
= IOPRIO_DEFAULT_CLASS_AND_PRIO
,
464 .cpu_sched_policy
= SCHED_OTHER
,
465 .syslog_priority
= LOG_DAEMON
|LOG_INFO
,
466 .syslog_level_prefix
= true,
467 .ignore_sigpipe
= true,
468 .timer_slack_nsec
= NSEC_INFINITY
,
469 .personality
= PERSONALITY_INVALID
,
470 .timeout_clean_usec
= USEC_INFINITY
,
471 .capability_bounding_set
= CAP_MASK_UNSET
,
472 .restrict_namespaces
= NAMESPACE_FLAGS_INITIAL
,
475 .syscall_errno
= SECCOMP_ERROR_NUMBER_KILL
,
477 .tty_rows
= UINT_MAX
,
478 .tty_cols
= UINT_MAX
,
479 .private_mounts
= -1,
481 .set_login_environment
= -1,
484 FOREACH_ARRAY(d
, c
->directories
, _EXEC_DIRECTORY_TYPE_MAX
)
487 numa_policy_reset(&c
->numa_policy
);
489 assert_cc(NAMESPACE_FLAGS_INITIAL
!= NAMESPACE_FLAGS_ALL
);
492 void exec_context_done(ExecContext
*c
) {
495 c
->environment
= strv_free(c
->environment
);
496 c
->environment_files
= strv_free(c
->environment_files
);
497 c
->pass_environment
= strv_free(c
->pass_environment
);
498 c
->unset_environment
= strv_free(c
->unset_environment
);
500 rlimit_free_all(c
->rlimit
);
502 for (size_t l
= 0; l
< 3; l
++) {
503 c
->stdio_fdname
[l
] = mfree(c
->stdio_fdname
[l
]);
504 c
->stdio_file
[l
] = mfree(c
->stdio_file
[l
]);
507 c
->working_directory
= mfree(c
->working_directory
);
508 c
->root_directory
= mfree(c
->root_directory
);
509 c
->root_image
= mfree(c
->root_image
);
510 c
->root_image_options
= mount_options_free_all(c
->root_image_options
);
511 c
->root_hash
= mfree(c
->root_hash
);
512 c
->root_hash_size
= 0;
513 c
->root_hash_path
= mfree(c
->root_hash_path
);
514 c
->root_hash_sig
= mfree(c
->root_hash_sig
);
515 c
->root_hash_sig_size
= 0;
516 c
->root_hash_sig_path
= mfree(c
->root_hash_sig_path
);
517 c
->root_verity
= mfree(c
->root_verity
);
518 c
->extension_images
= mount_image_free_many(c
->extension_images
, &c
->n_extension_images
);
519 c
->extension_directories
= strv_free(c
->extension_directories
);
520 c
->tty_path
= mfree(c
->tty_path
);
521 c
->syslog_identifier
= mfree(c
->syslog_identifier
);
522 c
->user
= mfree(c
->user
);
523 c
->group
= mfree(c
->group
);
525 c
->supplementary_groups
= strv_free(c
->supplementary_groups
);
527 c
->pam_name
= mfree(c
->pam_name
);
529 c
->read_only_paths
= strv_free(c
->read_only_paths
);
530 c
->read_write_paths
= strv_free(c
->read_write_paths
);
531 c
->inaccessible_paths
= strv_free(c
->inaccessible_paths
);
532 c
->exec_paths
= strv_free(c
->exec_paths
);
533 c
->no_exec_paths
= strv_free(c
->no_exec_paths
);
534 c
->exec_search_path
= strv_free(c
->exec_search_path
);
536 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
537 c
->bind_mounts
= NULL
;
538 c
->n_bind_mounts
= 0;
539 temporary_filesystem_free_many(c
->temporary_filesystems
, c
->n_temporary_filesystems
);
540 c
->temporary_filesystems
= NULL
;
541 c
->n_temporary_filesystems
= 0;
542 c
->mount_images
= mount_image_free_many(c
->mount_images
, &c
->n_mount_images
);
544 cpu_set_reset(&c
->cpu_set
);
545 numa_policy_reset(&c
->numa_policy
);
547 c
->utmp_id
= mfree(c
->utmp_id
);
548 c
->selinux_context
= mfree(c
->selinux_context
);
549 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
550 c
->smack_process_label
= mfree(c
->smack_process_label
);
552 c
->restrict_filesystems
= set_free_free(c
->restrict_filesystems
);
554 c
->syscall_filter
= hashmap_free(c
->syscall_filter
);
555 c
->syscall_archs
= set_free(c
->syscall_archs
);
556 c
->address_families
= set_free(c
->address_families
);
558 for (ExecDirectoryType t
= 0; t
< _EXEC_DIRECTORY_TYPE_MAX
; t
++)
559 exec_directory_done(&c
->directories
[t
]);
561 c
->log_level_max
= -1;
563 exec_context_free_log_extra_fields(c
);
564 c
->log_filter_allowed_patterns
= set_free_free(c
->log_filter_allowed_patterns
);
565 c
->log_filter_denied_patterns
= set_free_free(c
->log_filter_denied_patterns
);
567 c
->log_ratelimit_interval_usec
= 0;
568 c
->log_ratelimit_burst
= 0;
570 c
->stdin_data
= mfree(c
->stdin_data
);
571 c
->stdin_data_size
= 0;
573 c
->network_namespace_path
= mfree(c
->network_namespace_path
);
574 c
->ipc_namespace_path
= mfree(c
->ipc_namespace_path
);
576 c
->log_namespace
= mfree(c
->log_namespace
);
578 c
->load_credentials
= hashmap_free(c
->load_credentials
);
579 c
->set_credentials
= hashmap_free(c
->set_credentials
);
580 c
->import_credentials
= set_free_free(c
->import_credentials
);
582 c
->root_image_policy
= image_policy_free(c
->root_image_policy
);
583 c
->mount_image_policy
= image_policy_free(c
->mount_image_policy
);
584 c
->extension_image_policy
= image_policy_free(c
->extension_image_policy
);
587 int exec_context_destroy_runtime_directory(const ExecContext
*c
, const char *runtime_prefix
) {
593 FOREACH_ARRAY(i
, c
->directories
[EXEC_DIRECTORY_RUNTIME
].items
, c
->directories
[EXEC_DIRECTORY_RUNTIME
].n_items
) {
594 _cleanup_free_
char *p
= NULL
;
596 if (exec_directory_is_private(c
, EXEC_DIRECTORY_RUNTIME
))
597 p
= path_join(runtime_prefix
, "private", i
->path
);
599 p
= path_join(runtime_prefix
, i
->path
);
603 /* We execute this synchronously, since we need to be sure this is gone when we start the
605 (void) rm_rf(p
, REMOVE_ROOT
);
607 STRV_FOREACH(symlink
, i
->symlinks
) {
608 _cleanup_free_
char *symlink_abs
= NULL
;
610 if (exec_directory_is_private(c
, EXEC_DIRECTORY_RUNTIME
))
611 symlink_abs
= path_join(runtime_prefix
, "private", *symlink
);
613 symlink_abs
= path_join(runtime_prefix
, *symlink
);
617 (void) unlink(symlink_abs
);
624 int exec_context_destroy_mount_ns_dir(Unit
*u
) {
625 _cleanup_free_
char *p
= NULL
;
627 if (!u
|| !MANAGER_IS_SYSTEM(u
->manager
))
630 p
= path_join("/run/systemd/propagate/", u
->id
);
634 /* This is only filled transiently (see mount_in_namespace()), should be empty or even non-existent*/
635 if (rmdir(p
) < 0 && errno
!= ENOENT
)
636 log_unit_debug_errno(u
, errno
, "Unable to remove propagation dir '%s', ignoring: %m", p
);
641 void exec_command_done(ExecCommand
*c
) {
644 c
->path
= mfree(c
->path
);
645 c
->argv
= strv_free(c
->argv
);
648 void exec_command_done_array(ExecCommand
*c
, size_t n
) {
649 FOREACH_ARRAY(i
, c
, n
)
650 exec_command_done(i
);
653 ExecCommand
* exec_command_free_list(ExecCommand
*c
) {
656 while ((i
= LIST_POP(command
, c
))) {
657 exec_command_done(i
);
664 void exec_command_free_array(ExecCommand
**c
, size_t n
) {
665 FOREACH_ARRAY(i
, c
, n
)
666 *i
= exec_command_free_list(*i
);
669 void exec_command_reset_status_array(ExecCommand
*c
, size_t n
) {
670 FOREACH_ARRAY(i
, c
, n
)
671 exec_status_reset(&i
->exec_status
);
674 void exec_command_reset_status_list_array(ExecCommand
**c
, size_t n
) {
675 FOREACH_ARRAY(i
, c
, n
)
676 LIST_FOREACH(command
, z
, *i
)
677 exec_status_reset(&z
->exec_status
);
680 typedef struct InvalidEnvInfo
{
685 static void invalid_env(const char *p
, void *userdata
) {
686 InvalidEnvInfo
*info
= userdata
;
688 log_unit_error(info
->unit
, "Ignoring invalid environment assignment '%s': %s", p
, info
->path
);
691 const char* exec_context_fdname(const ExecContext
*c
, int fd_index
) {
697 if (c
->std_input
!= EXEC_INPUT_NAMED_FD
)
700 return c
->stdio_fdname
[STDIN_FILENO
] ?: "stdin";
703 if (c
->std_output
!= EXEC_OUTPUT_NAMED_FD
)
706 return c
->stdio_fdname
[STDOUT_FILENO
] ?: "stdout";
709 if (c
->std_error
!= EXEC_OUTPUT_NAMED_FD
)
712 return c
->stdio_fdname
[STDERR_FILENO
] ?: "stderr";
719 static int exec_context_load_environment(const Unit
*unit
, const ExecContext
*c
, char ***ret
) {
720 _cleanup_strv_free_
char **v
= NULL
;
726 STRV_FOREACH(i
, c
->environment_files
) {
727 _cleanup_globfree_ glob_t pglob
= {};
736 if (!path_is_absolute(fn
)) {
742 /* Filename supports globbing, take all matching files */
743 r
= safe_glob(fn
, 0, &pglob
);
750 /* When we don't match anything, -ENOENT should be returned */
751 assert(pglob
.gl_pathc
> 0);
753 FOREACH_ARRAY(path
, pglob
.gl_pathv
, pglob
.gl_pathc
) {
754 _cleanup_strv_free_
char **p
= NULL
;
756 r
= load_env_file(NULL
, *path
, &p
);
763 /* Log invalid environment variables with filename */
765 InvalidEnvInfo info
= {
770 p
= strv_env_clean_with_callback(p
, invalid_env
, &info
);
776 char **m
= strv_env_merge(v
, p
);
780 strv_free_and_replace(v
, m
);
790 static bool tty_may_match_dev_console(const char *tty
) {
791 _cleanup_free_
char *resolved
= NULL
;
796 tty
= skip_dev_prefix(tty
);
798 /* trivial identity? */
799 if (streq(tty
, "console"))
802 if (resolve_dev_console(&resolved
) < 0)
803 return true; /* if we could not resolve, assume it may */
805 /* "tty0" means the active VC, so it may be the same sometimes */
806 return path_equal(resolved
, tty
) || (streq(resolved
, "tty0") && tty_is_vc(tty
));
809 static bool exec_context_may_touch_tty(const ExecContext
*ec
) {
812 return ec
->tty_reset
||
814 ec
->tty_vt_disallocate
||
815 is_terminal_input(ec
->std_input
) ||
816 is_terminal_output(ec
->std_output
) ||
817 is_terminal_output(ec
->std_error
);
820 bool exec_context_may_touch_console(const ExecContext
*ec
) {
822 return exec_context_may_touch_tty(ec
) &&
823 tty_may_match_dev_console(exec_context_tty_path(ec
));
826 static void strv_fprintf(FILE *f
, char **l
) {
830 fprintf(f
, " %s", *g
);
833 static void strv_dump(FILE* f
, const char *prefix
, const char *name
, char **strv
) {
838 if (!strv_isempty(strv
)) {
839 fprintf(f
, "%s%s:", prefix
, name
);
840 strv_fprintf(f
, strv
);
845 void exec_params_dump(const ExecParameters
*p
, FILE* f
, const char *prefix
) {
849 prefix
= strempty(prefix
);
852 "%sRuntimeScope: %s\n"
854 "%sSELinuxContextNetwork: %s\n"
855 "%sCgroupSupportedMask: %u\n"
857 "%sCrededentialsDirectory: %s\n"
858 "%sEncryptedCredentialsDirectory: %s\n"
859 "%sConfirmSpawn: %s\n"
860 "%sShallConfirmSpawn: %s\n"
861 "%sWatchdogUSec: " USEC_FMT
"\n"
862 "%sNotifySocket: %s\n"
863 "%sFallbackSmackProcessLabel: %s\n",
864 prefix
, runtime_scope_to_string(p
->runtime_scope
),
866 prefix
, yes_no(p
->selinux_context_net
),
867 prefix
, p
->cgroup_supported
,
868 prefix
, p
->cgroup_path
,
869 prefix
, strempty(p
->received_credentials_directory
),
870 prefix
, strempty(p
->received_encrypted_credentials_directory
),
871 prefix
, strempty(p
->confirm_spawn
),
872 prefix
, yes_no(p
->shall_confirm_spawn
),
873 prefix
, p
->watchdog_usec
,
874 prefix
, strempty(p
->notify_socket
),
875 prefix
, strempty(p
->fallback_smack_process_label
));
877 strv_dump(f
, prefix
, "FdNames", p
->fd_names
);
878 strv_dump(f
, prefix
, "Environment", p
->environment
);
879 strv_dump(f
, prefix
, "Prefix", p
->prefix
);
881 LIST_FOREACH(open_files
, file
, p
->open_files
)
882 fprintf(f
, "%sOpenFile: %s %s", prefix
, file
->path
, open_file_flags_to_string(file
->flags
));
884 strv_dump(f
, prefix
, "FilesEnv", p
->files_env
);
887 void exec_context_dump(const ExecContext
*c
, FILE* f
, const char *prefix
) {
893 prefix
= strempty(prefix
);
897 "%sWorkingDirectory: %s\n"
898 "%sRootDirectory: %s\n"
899 "%sRootEphemeral: %s\n"
900 "%sNonBlocking: %s\n"
902 "%sPrivateDevices: %s\n"
903 "%sProtectKernelTunables: %s\n"
904 "%sProtectKernelModules: %s\n"
905 "%sProtectKernelLogs: %s\n"
906 "%sProtectClock: %s\n"
907 "%sProtectControlGroups: %s\n"
908 "%sPrivateNetwork: %s\n"
909 "%sPrivateUsers: %s\n"
910 "%sProtectHome: %s\n"
911 "%sProtectSystem: %s\n"
912 "%sMountAPIVFS: %s\n"
913 "%sIgnoreSIGPIPE: %s\n"
914 "%sMemoryDenyWriteExecute: %s\n"
915 "%sRestrictRealtime: %s\n"
916 "%sRestrictSUIDSGID: %s\n"
917 "%sKeyringMode: %s\n"
918 "%sProtectHostname: %s\n"
919 "%sProtectProc: %s\n"
920 "%sProcSubset: %s\n",
922 prefix
, empty_to_root(c
->working_directory
),
923 prefix
, empty_to_root(c
->root_directory
),
924 prefix
, yes_no(c
->root_ephemeral
),
925 prefix
, yes_no(c
->non_blocking
),
926 prefix
, yes_no(c
->private_tmp
),
927 prefix
, yes_no(c
->private_devices
),
928 prefix
, yes_no(c
->protect_kernel_tunables
),
929 prefix
, yes_no(c
->protect_kernel_modules
),
930 prefix
, yes_no(c
->protect_kernel_logs
),
931 prefix
, yes_no(c
->protect_clock
),
932 prefix
, yes_no(c
->protect_control_groups
),
933 prefix
, yes_no(c
->private_network
),
934 prefix
, yes_no(c
->private_users
),
935 prefix
, protect_home_to_string(c
->protect_home
),
936 prefix
, protect_system_to_string(c
->protect_system
),
937 prefix
, yes_no(exec_context_get_effective_mount_apivfs(c
)),
938 prefix
, yes_no(c
->ignore_sigpipe
),
939 prefix
, yes_no(c
->memory_deny_write_execute
),
940 prefix
, yes_no(c
->restrict_realtime
),
941 prefix
, yes_no(c
->restrict_suid_sgid
),
942 prefix
, exec_keyring_mode_to_string(c
->keyring_mode
),
943 prefix
, yes_no(c
->protect_hostname
),
944 prefix
, protect_proc_to_string(c
->protect_proc
),
945 prefix
, proc_subset_to_string(c
->proc_subset
));
947 if (c
->set_login_environment
>= 0)
948 fprintf(f
, "%sSetLoginEnvironment: %s\n", prefix
, yes_no(c
->set_login_environment
> 0));
951 fprintf(f
, "%sRootImage: %s\n", prefix
, c
->root_image
);
953 if (c
->root_image_options
) {
954 fprintf(f
, "%sRootImageOptions:", prefix
);
955 LIST_FOREACH(mount_options
, o
, c
->root_image_options
)
956 if (!isempty(o
->options
))
958 partition_designator_to_string(o
->partition_designator
),
964 _cleanup_free_
char *encoded
= NULL
;
965 encoded
= hexmem(c
->root_hash
, c
->root_hash_size
);
967 fprintf(f
, "%sRootHash: %s\n", prefix
, encoded
);
970 if (c
->root_hash_path
)
971 fprintf(f
, "%sRootHash: %s\n", prefix
, c
->root_hash_path
);
973 if (c
->root_hash_sig
) {
974 _cleanup_free_
char *encoded
= NULL
;
976 len
= base64mem(c
->root_hash_sig
, c
->root_hash_sig_size
, &encoded
);
978 fprintf(f
, "%sRootHashSignature: base64:%s\n", prefix
, encoded
);
981 if (c
->root_hash_sig_path
)
982 fprintf(f
, "%sRootHashSignature: %s\n", prefix
, c
->root_hash_sig_path
);
985 fprintf(f
, "%sRootVerity: %s\n", prefix
, c
->root_verity
);
987 STRV_FOREACH(e
, c
->environment
)
988 fprintf(f
, "%sEnvironment: %s\n", prefix
, *e
);
990 STRV_FOREACH(e
, c
->environment_files
)
991 fprintf(f
, "%sEnvironmentFile: %s\n", prefix
, *e
);
993 STRV_FOREACH(e
, c
->pass_environment
)
994 fprintf(f
, "%sPassEnvironment: %s\n", prefix
, *e
);
996 STRV_FOREACH(e
, c
->unset_environment
)
997 fprintf(f
, "%sUnsetEnvironment: %s\n", prefix
, *e
);
999 fprintf(f
, "%sRuntimeDirectoryPreserve: %s\n", prefix
, exec_preserve_mode_to_string(c
->runtime_directory_preserve_mode
));
1001 for (ExecDirectoryType dt
= 0; dt
< _EXEC_DIRECTORY_TYPE_MAX
; dt
++) {
1002 fprintf(f
, "%s%sMode: %04o\n", prefix
, exec_directory_type_to_string(dt
), c
->directories
[dt
].mode
);
1004 for (size_t i
= 0; i
< c
->directories
[dt
].n_items
; i
++) {
1005 fprintf(f
, "%s%s: %s\n", prefix
, exec_directory_type_to_string(dt
), c
->directories
[dt
].items
[i
].path
);
1007 STRV_FOREACH(d
, c
->directories
[dt
].items
[i
].symlinks
)
1008 fprintf(f
, "%s%s: %s:%s\n", prefix
, exec_directory_type_symlink_to_string(dt
), c
->directories
[dt
].items
[i
].path
, *d
);
1012 fprintf(f
, "%sTimeoutCleanSec: %s\n", prefix
, FORMAT_TIMESPAN(c
->timeout_clean_usec
, USEC_PER_SEC
));
1014 if (c
->memory_ksm
>= 0)
1015 fprintf(f
, "%sMemoryKSM: %s\n", prefix
, yes_no(c
->memory_ksm
> 0));
1018 fprintf(f
, "%sNice: %i\n", prefix
, c
->nice
);
1020 if (c
->oom_score_adjust_set
)
1021 fprintf(f
, "%sOOMScoreAdjust: %i\n", prefix
, c
->oom_score_adjust
);
1023 if (c
->coredump_filter_set
)
1024 fprintf(f
, "%sCoredumpFilter: 0x%"PRIx64
"\n", prefix
, c
->coredump_filter
);
1026 for (unsigned i
= 0; i
< RLIM_NLIMITS
; i
++)
1028 fprintf(f
, "%sLimit%s: " RLIM_FMT
"\n",
1029 prefix
, rlimit_to_string(i
), c
->rlimit
[i
]->rlim_max
);
1030 fprintf(f
, "%sLimit%sSoft: " RLIM_FMT
"\n",
1031 prefix
, rlimit_to_string(i
), c
->rlimit
[i
]->rlim_cur
);
1034 if (c
->ioprio_set
) {
1035 _cleanup_free_
char *class_str
= NULL
;
1037 r
= ioprio_class_to_string_alloc(ioprio_prio_class(c
->ioprio
), &class_str
);
1039 fprintf(f
, "%sIOSchedulingClass: %s\n", prefix
, class_str
);
1041 fprintf(f
, "%sIOPriority: %d\n", prefix
, ioprio_prio_data(c
->ioprio
));
1044 if (c
->cpu_sched_set
) {
1045 _cleanup_free_
char *policy_str
= NULL
;
1047 r
= sched_policy_to_string_alloc(c
->cpu_sched_policy
, &policy_str
);
1049 fprintf(f
, "%sCPUSchedulingPolicy: %s\n", prefix
, policy_str
);
1052 "%sCPUSchedulingPriority: %i\n"
1053 "%sCPUSchedulingResetOnFork: %s\n",
1054 prefix
, c
->cpu_sched_priority
,
1055 prefix
, yes_no(c
->cpu_sched_reset_on_fork
));
1058 if (c
->cpu_set
.set
) {
1059 _cleanup_free_
char *affinity
= NULL
;
1061 affinity
= cpu_set_to_range_string(&c
->cpu_set
);
1062 fprintf(f
, "%sCPUAffinity: %s\n", prefix
, affinity
);
1065 if (mpol_is_valid(numa_policy_get_type(&c
->numa_policy
))) {
1066 _cleanup_free_
char *nodes
= NULL
;
1068 nodes
= cpu_set_to_range_string(&c
->numa_policy
.nodes
);
1069 fprintf(f
, "%sNUMAPolicy: %s\n", prefix
, mpol_to_string(numa_policy_get_type(&c
->numa_policy
)));
1070 fprintf(f
, "%sNUMAMask: %s\n", prefix
, strnull(nodes
));
1073 if (c
->timer_slack_nsec
!= NSEC_INFINITY
)
1074 fprintf(f
, "%sTimerSlackNSec: "NSEC_FMT
"\n", prefix
, c
->timer_slack_nsec
);
1077 "%sStandardInput: %s\n"
1078 "%sStandardOutput: %s\n"
1079 "%sStandardError: %s\n",
1080 prefix
, exec_input_to_string(c
->std_input
),
1081 prefix
, exec_output_to_string(c
->std_output
),
1082 prefix
, exec_output_to_string(c
->std_error
));
1084 if (c
->std_input
== EXEC_INPUT_NAMED_FD
)
1085 fprintf(f
, "%sStandardInputFileDescriptorName: %s\n", prefix
, c
->stdio_fdname
[STDIN_FILENO
]);
1086 if (c
->std_output
== EXEC_OUTPUT_NAMED_FD
)
1087 fprintf(f
, "%sStandardOutputFileDescriptorName: %s\n", prefix
, c
->stdio_fdname
[STDOUT_FILENO
]);
1088 if (c
->std_error
== EXEC_OUTPUT_NAMED_FD
)
1089 fprintf(f
, "%sStandardErrorFileDescriptorName: %s\n", prefix
, c
->stdio_fdname
[STDERR_FILENO
]);
1091 if (c
->std_input
== EXEC_INPUT_FILE
)
1092 fprintf(f
, "%sStandardInputFile: %s\n", prefix
, c
->stdio_file
[STDIN_FILENO
]);
1093 if (c
->std_output
== EXEC_OUTPUT_FILE
)
1094 fprintf(f
, "%sStandardOutputFile: %s\n", prefix
, c
->stdio_file
[STDOUT_FILENO
]);
1095 if (c
->std_output
== EXEC_OUTPUT_FILE_APPEND
)
1096 fprintf(f
, "%sStandardOutputFileToAppend: %s\n", prefix
, c
->stdio_file
[STDOUT_FILENO
]);
1097 if (c
->std_output
== EXEC_OUTPUT_FILE_TRUNCATE
)
1098 fprintf(f
, "%sStandardOutputFileToTruncate: %s\n", prefix
, c
->stdio_file
[STDOUT_FILENO
]);
1099 if (c
->std_error
== EXEC_OUTPUT_FILE
)
1100 fprintf(f
, "%sStandardErrorFile: %s\n", prefix
, c
->stdio_file
[STDERR_FILENO
]);
1101 if (c
->std_error
== EXEC_OUTPUT_FILE_APPEND
)
1102 fprintf(f
, "%sStandardErrorFileToAppend: %s\n", prefix
, c
->stdio_file
[STDERR_FILENO
]);
1103 if (c
->std_error
== EXEC_OUTPUT_FILE_TRUNCATE
)
1104 fprintf(f
, "%sStandardErrorFileToTruncate: %s\n", prefix
, c
->stdio_file
[STDERR_FILENO
]);
1110 "%sTTYVHangup: %s\n"
1111 "%sTTYVTDisallocate: %s\n"
1113 "%sTTYColumns: %u\n",
1114 prefix
, c
->tty_path
,
1115 prefix
, yes_no(c
->tty_reset
),
1116 prefix
, yes_no(c
->tty_vhangup
),
1117 prefix
, yes_no(c
->tty_vt_disallocate
),
1118 prefix
, c
->tty_rows
,
1119 prefix
, c
->tty_cols
);
1121 if (IN_SET(c
->std_output
,
1123 EXEC_OUTPUT_JOURNAL
,
1124 EXEC_OUTPUT_KMSG_AND_CONSOLE
,
1125 EXEC_OUTPUT_JOURNAL_AND_CONSOLE
) ||
1126 IN_SET(c
->std_error
,
1128 EXEC_OUTPUT_JOURNAL
,
1129 EXEC_OUTPUT_KMSG_AND_CONSOLE
,
1130 EXEC_OUTPUT_JOURNAL_AND_CONSOLE
)) {
1132 _cleanup_free_
char *fac_str
= NULL
, *lvl_str
= NULL
;
1134 r
= log_facility_unshifted_to_string_alloc(c
->syslog_priority
>> 3, &fac_str
);
1136 fprintf(f
, "%sSyslogFacility: %s\n", prefix
, fac_str
);
1138 r
= log_level_to_string_alloc(LOG_PRI(c
->syslog_priority
), &lvl_str
);
1140 fprintf(f
, "%sSyslogLevel: %s\n", prefix
, lvl_str
);
1143 if (c
->log_level_max
>= 0) {
1144 _cleanup_free_
char *t
= NULL
;
1146 (void) log_level_to_string_alloc(c
->log_level_max
, &t
);
1148 fprintf(f
, "%sLogLevelMax: %s\n", prefix
, strna(t
));
1151 if (c
->log_ratelimit_interval_usec
> 0)
1153 "%sLogRateLimitIntervalSec: %s\n",
1154 prefix
, FORMAT_TIMESPAN(c
->log_ratelimit_interval_usec
, USEC_PER_SEC
));
1156 if (c
->log_ratelimit_burst
> 0)
1157 fprintf(f
, "%sLogRateLimitBurst: %u\n", prefix
, c
->log_ratelimit_burst
);
1159 if (!set_isempty(c
->log_filter_allowed_patterns
) || !set_isempty(c
->log_filter_denied_patterns
)) {
1160 fprintf(f
, "%sLogFilterPatterns:", prefix
);
1163 SET_FOREACH(pattern
, c
->log_filter_allowed_patterns
)
1164 fprintf(f
, " %s", pattern
);
1165 SET_FOREACH(pattern
, c
->log_filter_denied_patterns
)
1166 fprintf(f
, " ~%s", pattern
);
1170 FOREACH_ARRAY(field
, c
->log_extra_fields
, c
->n_log_extra_fields
) {
1171 fprintf(f
, "%sLogExtraFields: ", prefix
);
1172 fwrite(field
->iov_base
, 1, field
->iov_len
, f
);
1176 if (c
->log_namespace
)
1177 fprintf(f
, "%sLogNamespace: %s\n", prefix
, c
->log_namespace
);
1179 if (c
->secure_bits
) {
1180 _cleanup_free_
char *str
= NULL
;
1182 r
= secure_bits_to_string_alloc(c
->secure_bits
, &str
);
1184 fprintf(f
, "%sSecure Bits: %s\n", prefix
, str
);
1187 if (c
->capability_bounding_set
!= CAP_MASK_UNSET
) {
1188 _cleanup_free_
char *str
= NULL
;
1190 r
= capability_set_to_string(c
->capability_bounding_set
, &str
);
1192 fprintf(f
, "%sCapabilityBoundingSet: %s\n", prefix
, str
);
1195 if (c
->capability_ambient_set
!= 0) {
1196 _cleanup_free_
char *str
= NULL
;
1198 r
= capability_set_to_string(c
->capability_ambient_set
, &str
);
1200 fprintf(f
, "%sAmbientCapabilities: %s\n", prefix
, str
);
1204 fprintf(f
, "%sUser: %s\n", prefix
, c
->user
);
1206 fprintf(f
, "%sGroup: %s\n", prefix
, c
->group
);
1208 fprintf(f
, "%sDynamicUser: %s\n", prefix
, yes_no(c
->dynamic_user
));
1210 strv_dump(f
, prefix
, "SupplementaryGroups", c
->supplementary_groups
);
1213 fprintf(f
, "%sPAMName: %s\n", prefix
, c
->pam_name
);
1215 strv_dump(f
, prefix
, "ReadWritePaths", c
->read_write_paths
);
1216 strv_dump(f
, prefix
, "ReadOnlyPaths", c
->read_only_paths
);
1217 strv_dump(f
, prefix
, "InaccessiblePaths", c
->inaccessible_paths
);
1218 strv_dump(f
, prefix
, "ExecPaths", c
->exec_paths
);
1219 strv_dump(f
, prefix
, "NoExecPaths", c
->no_exec_paths
);
1220 strv_dump(f
, prefix
, "ExecSearchPath", c
->exec_search_path
);
1222 FOREACH_ARRAY(mount
, c
->bind_mounts
, c
->n_bind_mounts
)
1223 fprintf(f
, "%s%s: %s%s:%s:%s\n", prefix
,
1224 mount
->read_only
? "BindReadOnlyPaths" : "BindPaths",
1225 mount
->ignore_enoent
? "-": "",
1228 mount
->recursive
? "rbind" : "norbind");
1230 FOREACH_ARRAY(tmpfs
, c
->temporary_filesystems
, c
->n_temporary_filesystems
)
1231 fprintf(f
, "%sTemporaryFileSystem: %s%s%s\n", prefix
,
1233 isempty(tmpfs
->options
) ? "" : ":",
1234 strempty(tmpfs
->options
));
1238 "%sUtmpIdentifier: %s\n",
1239 prefix
, c
->utmp_id
);
1241 if (c
->selinux_context
)
1243 "%sSELinuxContext: %s%s\n",
1244 prefix
, c
->selinux_context_ignore
? "-" : "", c
->selinux_context
);
1246 if (c
->apparmor_profile
)
1248 "%sAppArmorProfile: %s%s\n",
1249 prefix
, c
->apparmor_profile_ignore
? "-" : "", c
->apparmor_profile
);
1251 if (c
->smack_process_label
)
1253 "%sSmackProcessLabel: %s%s\n",
1254 prefix
, c
->smack_process_label_ignore
? "-" : "", c
->smack_process_label
);
1256 if (c
->personality
!= PERSONALITY_INVALID
)
1258 "%sPersonality: %s\n",
1259 prefix
, strna(personality_to_string(c
->personality
)));
1262 "%sLockPersonality: %s\n",
1263 prefix
, yes_no(c
->lock_personality
));
1265 if (c
->syscall_filter
) {
1267 "%sSystemCallFilter: ",
1270 if (!c
->syscall_allow_list
)
1276 HASHMAP_FOREACH_KEY(val
, id
, c
->syscall_filter
) {
1277 _cleanup_free_
char *name
= NULL
;
1278 const char *errno_name
= NULL
;
1279 int num
= PTR_TO_INT(val
);
1286 name
= seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE
, PTR_TO_INT(id
) - 1);
1287 fputs(strna(name
), f
);
1290 errno_name
= seccomp_errno_or_action_to_string(num
);
1292 fprintf(f
, ":%s", errno_name
);
1294 fprintf(f
, ":%d", num
);
1302 if (c
->syscall_archs
) {
1304 "%sSystemCallArchitectures:",
1309 SET_FOREACH(id
, c
->syscall_archs
)
1310 fprintf(f
, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id
) - 1)));
1315 if (exec_context_restrict_namespaces_set(c
)) {
1316 _cleanup_free_
char *s
= NULL
;
1318 r
= namespace_flags_to_string(c
->restrict_namespaces
, &s
);
1320 fprintf(f
, "%sRestrictNamespaces: %s\n",
1325 if (exec_context_restrict_filesystems_set(c
)) {
1327 SET_FOREACH(fs
, c
->restrict_filesystems
)
1328 fprintf(f
, "%sRestrictFileSystems: %s\n", prefix
, fs
);
1332 if (c
->network_namespace_path
)
1334 "%sNetworkNamespacePath: %s\n",
1335 prefix
, c
->network_namespace_path
);
1337 if (c
->syscall_errno
> 0) {
1338 fprintf(f
, "%sSystemCallErrorNumber: ", prefix
);
1341 const char *errno_name
= seccomp_errno_or_action_to_string(c
->syscall_errno
);
1343 fputs(errno_name
, f
);
1345 fprintf(f
, "%d", c
->syscall_errno
);
1350 FOREACH_ARRAY(mount
, c
->mount_images
, c
->n_mount_images
) {
1351 fprintf(f
, "%sMountImages: %s%s:%s", prefix
,
1352 mount
->ignore_enoent
? "-": "",
1354 mount
->destination
);
1355 LIST_FOREACH(mount_options
, o
, mount
->mount_options
)
1356 fprintf(f
, ":%s:%s",
1357 partition_designator_to_string(o
->partition_designator
),
1358 strempty(o
->options
));
1362 FOREACH_ARRAY(mount
, c
->extension_images
, c
->n_extension_images
) {
1363 fprintf(f
, "%sExtensionImages: %s%s", prefix
,
1364 mount
->ignore_enoent
? "-": "",
1366 LIST_FOREACH(mount_options
, o
, mount
->mount_options
)
1367 fprintf(f
, ":%s:%s",
1368 partition_designator_to_string(o
->partition_designator
),
1369 strempty(o
->options
));
1373 strv_dump(f
, prefix
, "ExtensionDirectories", c
->extension_directories
);
1376 bool exec_context_maintains_privileges(const ExecContext
*c
) {
1379 /* Returns true if the process forked off would run under
1380 * an unchanged UID or as root. */
1385 if (streq(c
->user
, "root") || streq(c
->user
, "0"))
1391 int exec_context_get_effective_ioprio(const ExecContext
*c
) {
1399 p
= ioprio_get(IOPRIO_WHO_PROCESS
, 0);
1401 return IOPRIO_DEFAULT_CLASS_AND_PRIO
;
1403 return ioprio_normalize(p
);
1406 bool exec_context_get_effective_mount_apivfs(const ExecContext
*c
) {
1409 /* Explicit setting wins */
1410 if (c
->mount_apivfs_set
)
1411 return c
->mount_apivfs
;
1413 /* Default to "yes" if root directory or image are specified */
1414 if (exec_context_with_rootfs(c
))
1420 void exec_context_free_log_extra_fields(ExecContext
*c
) {
1423 FOREACH_ARRAY(field
, c
->log_extra_fields
, c
->n_log_extra_fields
)
1424 free(field
->iov_base
);
1426 c
->log_extra_fields
= mfree(c
->log_extra_fields
);
1427 c
->n_log_extra_fields
= 0;
1430 void exec_context_revert_tty(ExecContext
*c
) {
1431 _cleanup_close_
int fd
= -EBADF
;
1438 /* First, reset the TTY (possibly kicking everybody else from the TTY) */
1439 exec_context_tty_reset(c
, NULL
);
1441 /* And then undo what chown_terminal() did earlier. Note that we only do this if we have a path
1442 * configured. If the TTY was passed to us as file descriptor we assume the TTY is opened and managed
1443 * by whoever passed it to us and thus knows better when and how to chmod()/chown() it back. */
1444 if (!exec_context_may_touch_tty(c
))
1447 path
= exec_context_tty_path(c
);
1451 fd
= open(path
, O_PATH
|O_CLOEXEC
);
1453 return (void) log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_WARNING
, errno
,
1454 "Failed to open TTY inode of '%s' to adjust ownership/access mode, ignoring: %m",
1457 if (fstat(fd
, &st
) < 0)
1458 return (void) log_warning_errno(errno
, "Failed to stat TTY '%s', ignoring: %m", path
);
1460 /* Let's add a superficial check that we only do this for stuff that looks like a TTY. We only check
1461 * if things are a character device, since a proper check either means we'd have to open the TTY and
1462 * use isatty(), but we'd rather not do that since opening TTYs comes with all kinds of side-effects
1463 * and is slow. Or we'd have to hardcode dev_t major information, which we'd rather avoid. Why bother
1464 * with this at all? → https://github.com/systemd/systemd/issues/19213 */
1465 if (!S_ISCHR(st
.st_mode
))
1466 return log_warning("Configured TTY '%s' is not actually a character device, ignoring.", path
);
1468 r
= fchmod_and_chown(fd
, TTY_MODE
, 0, TTY_GID
);
1470 log_warning_errno(r
, "Failed to reset TTY ownership/access mode of %s, ignoring: %m", path
);
1473 int exec_context_get_clean_directories(
1479 _cleanup_strv_free_
char **l
= NULL
;
1486 for (ExecDirectoryType t
= 0; t
< _EXEC_DIRECTORY_TYPE_MAX
; t
++) {
1487 if (!FLAGS_SET(mask
, 1U << t
))
1493 FOREACH_ARRAY(i
, c
->directories
[t
].items
, c
->directories
[t
].n_items
) {
1496 j
= path_join(prefix
[t
], i
->path
);
1500 r
= strv_consume(&l
, j
);
1504 /* Also remove private directories unconditionally. */
1505 if (t
!= EXEC_DIRECTORY_CONFIGURATION
) {
1506 j
= path_join(prefix
[t
], "private", i
->path
);
1510 r
= strv_consume(&l
, j
);
1515 STRV_FOREACH(symlink
, i
->symlinks
) {
1516 j
= path_join(prefix
[t
], *symlink
);
1520 r
= strv_consume(&l
, j
);
1531 int exec_context_get_clean_mask(ExecContext
*c
, ExecCleanMask
*ret
) {
1532 ExecCleanMask mask
= 0;
1537 for (ExecDirectoryType t
= 0; t
< _EXEC_DIRECTORY_TYPE_MAX
; t
++)
1538 if (c
->directories
[t
].n_items
> 0)
1545 void exec_status_start(ExecStatus
*s
, pid_t pid
) {
1552 dual_timestamp_get(&s
->start_timestamp
);
1555 void exec_status_exit(ExecStatus
*s
, const ExecContext
*context
, pid_t pid
, int code
, int status
) {
1563 dual_timestamp_get(&s
->exit_timestamp
);
1568 if (context
&& context
->utmp_id
)
1569 (void) utmp_put_dead_process(context
->utmp_id
, pid
, code
, status
);
1572 void exec_status_reset(ExecStatus
*s
) {
1575 *s
= (ExecStatus
) {};
1578 void exec_status_dump(const ExecStatus
*s
, FILE *f
, const char *prefix
) {
1585 prefix
= strempty(prefix
);
1588 "%sPID: "PID_FMT
"\n",
1591 if (dual_timestamp_is_set(&s
->start_timestamp
))
1593 "%sStart Timestamp: %s\n",
1594 prefix
, FORMAT_TIMESTAMP(s
->start_timestamp
.realtime
));
1596 if (dual_timestamp_is_set(&s
->exit_timestamp
))
1598 "%sExit Timestamp: %s\n"
1600 "%sExit Status: %i\n",
1601 prefix
, FORMAT_TIMESTAMP(s
->exit_timestamp
.realtime
),
1602 prefix
, sigchld_code_to_string(s
->code
),
1606 static void exec_command_dump(ExecCommand
*c
, FILE *f
, const char *prefix
) {
1607 _cleanup_free_
char *cmd
= NULL
;
1608 const char *prefix2
;
1613 prefix
= strempty(prefix
);
1614 prefix2
= strjoina(prefix
, "\t");
1616 cmd
= quote_command_line(c
->argv
, SHELL_ESCAPE_EMPTY
);
1619 "%sCommand Line: %s\n",
1620 prefix
, strnull(cmd
));
1622 exec_status_dump(&c
->exec_status
, f
, prefix2
);
1625 void exec_command_dump_list(ExecCommand
*c
, FILE *f
, const char *prefix
) {
1628 prefix
= strempty(prefix
);
1630 LIST_FOREACH(command
, i
, c
)
1631 exec_command_dump(i
, f
, prefix
);
1634 void exec_command_append_list(ExecCommand
**l
, ExecCommand
*e
) {
1641 /* It's kind of important, that we keep the order here */
1642 end
= LIST_FIND_TAIL(command
, *l
);
1643 LIST_INSERT_AFTER(command
, *l
, end
, e
);
1648 int exec_command_set(ExecCommand
*c
, const char *path
, ...) {
1656 l
= strv_new_ap(path
, ap
);
1668 free_and_replace(c
->path
, p
);
1670 return strv_free_and_replace(c
->argv
, l
);
1673 int exec_command_append(ExecCommand
*c
, const char *path
, ...) {
1674 _cleanup_strv_free_
char **l
= NULL
;
1682 l
= strv_new_ap(path
, ap
);
1688 r
= strv_extend_strv(&c
->argv
, l
, false);
1695 static char *destroy_tree(char *path
) {
1699 if (!path_equal(path
, RUN_SYSTEMD_EMPTY
)) {
1700 log_debug("Spawning process to nuke '%s'", path
);
1702 (void) asynchronous_rm_rf(path
, REMOVE_ROOT
|REMOVE_SUBVOLUME
|REMOVE_PHYSICAL
);
1708 void exec_shared_runtime_done(ExecSharedRuntime
*rt
) {
1713 (void) hashmap_remove(rt
->manager
->exec_shared_runtime_by_id
, rt
->id
);
1715 rt
->id
= mfree(rt
->id
);
1716 rt
->tmp_dir
= mfree(rt
->tmp_dir
);
1717 rt
->var_tmp_dir
= mfree(rt
->var_tmp_dir
);
1718 safe_close_pair(rt
->netns_storage_socket
);
1719 safe_close_pair(rt
->ipcns_storage_socket
);
1722 static ExecSharedRuntime
* exec_shared_runtime_free(ExecSharedRuntime
*rt
) {
1723 exec_shared_runtime_done(rt
);
1728 DEFINE_TRIVIAL_UNREF_FUNC(ExecSharedRuntime
, exec_shared_runtime
, exec_shared_runtime_free
);
1729 DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSharedRuntime
*, exec_shared_runtime_free
);
1731 ExecSharedRuntime
* exec_shared_runtime_destroy(ExecSharedRuntime
*rt
) {
1735 assert(rt
->n_ref
> 0);
1741 rt
->tmp_dir
= destroy_tree(rt
->tmp_dir
);
1742 rt
->var_tmp_dir
= destroy_tree(rt
->var_tmp_dir
);
1744 return exec_shared_runtime_free(rt
);
1747 static int exec_shared_runtime_allocate(ExecSharedRuntime
**ret
, const char *id
) {
1748 _cleanup_free_
char *id_copy
= NULL
;
1749 ExecSharedRuntime
*n
;
1753 id_copy
= strdup(id
);
1757 n
= new(ExecSharedRuntime
, 1);
1761 *n
= (ExecSharedRuntime
) {
1762 .id
= TAKE_PTR(id_copy
),
1763 .netns_storage_socket
= PIPE_EBADF
,
1764 .ipcns_storage_socket
= PIPE_EBADF
,
1771 static int exec_shared_runtime_add(
1776 int netns_storage_socket
[2],
1777 int ipcns_storage_socket
[2],
1778 ExecSharedRuntime
**ret
) {
1780 _cleanup_(exec_shared_runtime_freep
) ExecSharedRuntime
*rt
= NULL
;
1786 /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
1788 r
= exec_shared_runtime_allocate(&rt
, id
);
1792 r
= hashmap_ensure_put(&m
->exec_shared_runtime_by_id
, &string_hash_ops
, rt
->id
, rt
);
1796 assert(!!rt
->tmp_dir
== !!rt
->var_tmp_dir
); /* We require both to be set together */
1797 rt
->tmp_dir
= TAKE_PTR(*tmp_dir
);
1798 rt
->var_tmp_dir
= TAKE_PTR(*var_tmp_dir
);
1800 if (netns_storage_socket
) {
1801 rt
->netns_storage_socket
[0] = TAKE_FD(netns_storage_socket
[0]);
1802 rt
->netns_storage_socket
[1] = TAKE_FD(netns_storage_socket
[1]);
1805 if (ipcns_storage_socket
) {
1806 rt
->ipcns_storage_socket
[0] = TAKE_FD(ipcns_storage_socket
[0]);
1807 rt
->ipcns_storage_socket
[1] = TAKE_FD(ipcns_storage_socket
[1]);
1814 /* do not remove created ExecSharedRuntime object when the operation succeeds. */
1819 static int exec_shared_runtime_make(
1821 const ExecContext
*c
,
1823 ExecSharedRuntime
**ret
) {
1825 _cleanup_(namespace_cleanup_tmpdirp
) char *tmp_dir
= NULL
, *var_tmp_dir
= NULL
;
1826 _cleanup_close_pair_
int netns_storage_socket
[2] = PIPE_EBADF
, ipcns_storage_socket
[2] = PIPE_EBADF
;
1833 /* It is not necessary to create ExecSharedRuntime object. */
1834 if (!exec_needs_network_namespace(c
) && !exec_needs_ipc_namespace(c
) && !c
->private_tmp
) {
1839 if (c
->private_tmp
&&
1840 !(prefixed_path_strv_contains(c
->inaccessible_paths
, "/tmp") &&
1841 (prefixed_path_strv_contains(c
->inaccessible_paths
, "/var/tmp") ||
1842 prefixed_path_strv_contains(c
->inaccessible_paths
, "/var")))) {
1843 r
= setup_tmp_dirs(id
, &tmp_dir
, &var_tmp_dir
);
1848 if (exec_needs_network_namespace(c
)) {
1849 if (socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, netns_storage_socket
) < 0)
1853 if (exec_needs_ipc_namespace(c
)) {
1854 if (socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, ipcns_storage_socket
) < 0)
1858 r
= exec_shared_runtime_add(m
, id
, &tmp_dir
, &var_tmp_dir
, netns_storage_socket
, ipcns_storage_socket
, ret
);
1865 int exec_shared_runtime_acquire(Manager
*m
, const ExecContext
*c
, const char *id
, bool create
, ExecSharedRuntime
**ret
) {
1866 ExecSharedRuntime
*rt
;
1873 rt
= hashmap_get(m
->exec_shared_runtime_by_id
, id
);
1875 /* We already have an ExecSharedRuntime object, let's increase the ref count and reuse it */
1883 /* If not found, then create a new object. */
1884 r
= exec_shared_runtime_make(m
, c
, id
, &rt
);
1888 /* When r == 0, it is not necessary to create ExecSharedRuntime object. */
1894 /* increment reference counter. */
1900 int exec_shared_runtime_serialize(const Manager
*m
, FILE *f
, FDSet
*fds
) {
1901 ExecSharedRuntime
*rt
;
1907 HASHMAP_FOREACH(rt
, m
->exec_shared_runtime_by_id
) {
1908 fprintf(f
, "exec-runtime=%s", rt
->id
);
1911 fprintf(f
, " tmp-dir=%s", rt
->tmp_dir
);
1913 if (rt
->var_tmp_dir
)
1914 fprintf(f
, " var-tmp-dir=%s", rt
->var_tmp_dir
);
1916 if (rt
->netns_storage_socket
[0] >= 0) {
1919 copy
= fdset_put_dup(fds
, rt
->netns_storage_socket
[0]);
1923 fprintf(f
, " netns-socket-0=%i", copy
);
1926 if (rt
->netns_storage_socket
[1] >= 0) {
1929 copy
= fdset_put_dup(fds
, rt
->netns_storage_socket
[1]);
1933 fprintf(f
, " netns-socket-1=%i", copy
);
1936 if (rt
->ipcns_storage_socket
[0] >= 0) {
1939 copy
= fdset_put_dup(fds
, rt
->ipcns_storage_socket
[0]);
1943 fprintf(f
, " ipcns-socket-0=%i", copy
);
1946 if (rt
->ipcns_storage_socket
[1] >= 0) {
1949 copy
= fdset_put_dup(fds
, rt
->ipcns_storage_socket
[1]);
1953 fprintf(f
, " ipcns-socket-1=%i", copy
);
1962 int exec_shared_runtime_deserialize_compat(Unit
*u
, const char *key
, const char *value
, FDSet
*fds
) {
1963 _cleanup_(exec_shared_runtime_freep
) ExecSharedRuntime
*rt_create
= NULL
;
1964 ExecSharedRuntime
*rt
= NULL
;
1967 /* This is for the migration from old (v237 or earlier) deserialization text.
1968 * Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
1969 * Even if the ExecSharedRuntime object originally created by the other unit, we cannot judge
1970 * so or not from the serialized text, then we always creates a new object owned by this. */
1976 /* Manager manages ExecSharedRuntime objects by the unit id.
1977 * So, we omit the serialized text when the unit does not have id (yet?)... */
1978 if (isempty(u
->id
)) {
1979 log_unit_debug(u
, "Invocation ID not found. Dropping runtime parameter.");
1984 if (hashmap_ensure_allocated(&u
->manager
->exec_shared_runtime_by_id
, &string_hash_ops
) < 0)
1987 rt
= hashmap_get(u
->manager
->exec_shared_runtime_by_id
, u
->id
);
1990 if (exec_shared_runtime_allocate(&rt_create
, u
->id
) < 0)
1996 if (streq(key
, "tmp-dir")) {
1997 if (free_and_strdup_warn(&rt
->tmp_dir
, value
) < 0)
2000 } else if (streq(key
, "var-tmp-dir")) {
2001 if (free_and_strdup_warn(&rt
->var_tmp_dir
, value
) < 0)
2004 } else if (streq(key
, "netns-socket-0")) {
2006 safe_close(rt
->netns_storage_socket
[0]);
2007 rt
->netns_storage_socket
[0] = deserialize_fd(fds
, value
);
2008 if (rt
->netns_storage_socket
[0] < 0)
2011 } else if (streq(key
, "netns-socket-1")) {
2013 safe_close(rt
->netns_storage_socket
[1]);
2014 rt
->netns_storage_socket
[1] = deserialize_fd(fds
, value
);
2015 if (rt
->netns_storage_socket
[1] < 0)
2020 /* If the object is newly created, then put it to the hashmap which manages ExecSharedRuntime objects. */
2021 if (rt_create
&& u
->manager
) {
2022 r
= hashmap_put(u
->manager
->exec_shared_runtime_by_id
, rt_create
->id
, rt_create
);
2024 log_unit_debug_errno(u
, r
, "Failed to put runtime parameter to manager's storage: %m");
2028 rt_create
->manager
= u
->manager
;
2031 TAKE_PTR(rt_create
);
2037 int exec_shared_runtime_deserialize_one(Manager
*m
, const char *value
, FDSet
*fds
) {
2038 _cleanup_free_
char *tmp_dir
= NULL
, *var_tmp_dir
= NULL
;
2040 int r
, netns_fdpair
[] = {-1, -1}, ipcns_fdpair
[] = {-1, -1};
2041 const char *p
, *v
= ASSERT_PTR(value
);
2047 n
= strcspn(v
, " ");
2048 id
= strndupa_safe(v
, n
);
2053 v
= startswith(p
, "tmp-dir=");
2055 n
= strcspn(v
, " ");
2056 tmp_dir
= strndup(v
, n
);
2064 v
= startswith(p
, "var-tmp-dir=");
2066 n
= strcspn(v
, " ");
2067 var_tmp_dir
= strndup(v
, n
);
2075 v
= startswith(p
, "netns-socket-0=");
2079 n
= strcspn(v
, " ");
2080 buf
= strndupa_safe(v
, n
);
2082 netns_fdpair
[0] = deserialize_fd(fds
, buf
);
2083 if (netns_fdpair
[0] < 0)
2084 return netns_fdpair
[0];
2090 v
= startswith(p
, "netns-socket-1=");
2094 n
= strcspn(v
, " ");
2095 buf
= strndupa_safe(v
, n
);
2097 netns_fdpair
[1] = deserialize_fd(fds
, buf
);
2098 if (netns_fdpair
[1] < 0)
2099 return netns_fdpair
[1];
2105 v
= startswith(p
, "ipcns-socket-0=");
2109 n
= strcspn(v
, " ");
2110 buf
= strndupa_safe(v
, n
);
2112 ipcns_fdpair
[0] = deserialize_fd(fds
, buf
);
2113 if (ipcns_fdpair
[0] < 0)
2114 return ipcns_fdpair
[0];
2120 v
= startswith(p
, "ipcns-socket-1=");
2124 n
= strcspn(v
, " ");
2125 buf
= strndupa_safe(v
, n
);
2127 ipcns_fdpair
[1] = deserialize_fd(fds
, buf
);
2128 if (ipcns_fdpair
[1] < 0)
2129 return ipcns_fdpair
[1];
2133 r
= exec_shared_runtime_add(m
, id
, &tmp_dir
, &var_tmp_dir
, netns_fdpair
, ipcns_fdpair
, NULL
);
2135 return log_debug_errno(r
, "Failed to add exec-runtime: %m");
2139 void exec_shared_runtime_vacuum(Manager
*m
) {
2140 ExecSharedRuntime
*rt
;
2144 /* Free unreferenced ExecSharedRuntime objects. This is used after manager deserialization process. */
2146 HASHMAP_FOREACH(rt
, m
->exec_shared_runtime_by_id
) {
2150 (void) exec_shared_runtime_free(rt
);
2154 int exec_runtime_make(
2156 const ExecContext
*context
,
2157 ExecSharedRuntime
*shared
,
2158 DynamicCreds
*creds
,
2159 ExecRuntime
**ret
) {
2160 _cleanup_close_pair_
int ephemeral_storage_socket
[2] = PIPE_EBADF
;
2161 _cleanup_free_
char *ephemeral
= NULL
;
2162 _cleanup_(exec_runtime_freep
) ExecRuntime
*rt
= NULL
;
2169 if (!shared
&& !creds
&& !exec_needs_ephemeral(context
)) {
2174 if (exec_needs_ephemeral(context
)) {
2175 r
= mkdir_p("/var/lib/systemd/ephemeral-trees", 0755);
2179 r
= tempfn_random_child("/var/lib/systemd/ephemeral-trees", unit
->id
, &ephemeral
);
2183 if (socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, ephemeral_storage_socket
) < 0)
2187 rt
= new(ExecRuntime
, 1);
2191 *rt
= (ExecRuntime
) {
2193 .dynamic_creds
= creds
,
2194 .ephemeral_copy
= TAKE_PTR(ephemeral
),
2195 .ephemeral_storage_socket
[0] = TAKE_FD(ephemeral_storage_socket
[0]),
2196 .ephemeral_storage_socket
[1] = TAKE_FD(ephemeral_storage_socket
[1]),
2199 *ret
= TAKE_PTR(rt
);
2203 ExecRuntime
* exec_runtime_free(ExecRuntime
*rt
) {
2207 exec_shared_runtime_unref(rt
->shared
);
2208 dynamic_creds_unref(rt
->dynamic_creds
);
2210 rt
->ephemeral_copy
= destroy_tree(rt
->ephemeral_copy
);
2212 safe_close_pair(rt
->ephemeral_storage_socket
);
2216 ExecRuntime
* exec_runtime_destroy(ExecRuntime
*rt
) {
2220 rt
->shared
= exec_shared_runtime_destroy(rt
->shared
);
2221 rt
->dynamic_creds
= dynamic_creds_destroy(rt
->dynamic_creds
);
2222 return exec_runtime_free(rt
);
2225 void exec_runtime_clear(ExecRuntime
*rt
) {
2229 safe_close_pair(rt
->ephemeral_storage_socket
);
2230 rt
->ephemeral_copy
= mfree(rt
->ephemeral_copy
);
2233 void exec_params_clear(ExecParameters
*p
) {
2237 p
->environment
= strv_free(p
->environment
);
2238 p
->fd_names
= strv_free(p
->fd_names
);
2239 p
->files_env
= strv_free(p
->files_env
);
2240 p
->fds
= mfree(p
->fds
);
2241 p
->exec_fd
= safe_close(p
->exec_fd
);
2242 p
->user_lookup_fd
= -EBADF
;
2243 p
->bpf_outer_map_fd
= -EBADF
;
2244 p
->unit_id
= mfree(p
->unit_id
);
2245 p
->invocation_id
= SD_ID128_NULL
;
2246 p
->invocation_id_string
[0] = '\0';
2247 p
->confirm_spawn
= mfree(p
->confirm_spawn
);
2250 void exec_params_serialized_done(ExecParameters
*p
) {
2254 close_many_unset(p
->fds
, p
->n_socket_fds
+ p
->n_storage_fds
);
2256 p
->cgroup_path
= mfree(p
->cgroup_path
);
2258 p
->prefix
= strv_free(p
->prefix
);
2259 p
->received_credentials_directory
= mfree(p
->received_credentials_directory
);
2260 p
->received_encrypted_credentials_directory
= mfree(p
->received_encrypted_credentials_directory
);
2263 close_many_and_free(p
->idle_pipe
, 4);
2264 p
->idle_pipe
= NULL
;
2267 p
->stdin_fd
= safe_close(p
->stdin_fd
);
2268 p
->stdout_fd
= safe_close(p
->stdout_fd
);
2269 p
->stderr_fd
= safe_close(p
->stderr_fd
);
2271 p
->notify_socket
= mfree(p
->notify_socket
);
2273 open_file_free_many(&p
->open_files
);
2275 p
->fallback_smack_process_label
= mfree(p
->fallback_smack_process_label
);
2277 exec_params_clear(p
);
2280 void exec_directory_done(ExecDirectory
*d
) {
2284 FOREACH_ARRAY(i
, d
->items
, d
->n_items
) {
2286 strv_free(i
->symlinks
);
2289 d
->items
= mfree(d
->items
);
2294 static ExecDirectoryItem
*exec_directory_find(ExecDirectory
*d
, const char *path
) {
2298 FOREACH_ARRAY(i
, d
->items
, d
->n_items
)
2299 if (path_equal(i
->path
, path
))
2305 int exec_directory_add(ExecDirectory
*d
, const char *path
, const char *symlink
) {
2306 _cleanup_strv_free_
char **s
= NULL
;
2307 _cleanup_free_
char *p
= NULL
;
2308 ExecDirectoryItem
*existing
;
2314 existing
= exec_directory_find(d
, path
);
2316 r
= strv_extend(&existing
->symlinks
, symlink
);
2320 return 0; /* existing item is updated */
2328 s
= strv_new(symlink
);
2333 if (!GREEDY_REALLOC(d
->items
, d
->n_items
+ 1))
2336 d
->items
[d
->n_items
++] = (ExecDirectoryItem
) {
2337 .path
= TAKE_PTR(p
),
2338 .symlinks
= TAKE_PTR(s
),
2341 return 1; /* new item is added */
2344 static int exec_directory_item_compare_func(const ExecDirectoryItem
*a
, const ExecDirectoryItem
*b
) {
2348 return path_compare(a
->path
, b
->path
);
2351 void exec_directory_sort(ExecDirectory
*d
) {
2354 /* Sort the exec directories to make always parent directories processed at first in
2355 * setup_exec_directory(), e.g., even if StateDirectory=foo/bar foo, we need to create foo at first,
2356 * then foo/bar. Also, set .only_create flag if one of the parent directories is contained in the
2357 * list. See also comments in setup_exec_directory() and issue #24783. */
2359 if (d
->n_items
<= 1)
2362 typesafe_qsort(d
->items
, d
->n_items
, exec_directory_item_compare_func
);
2364 for (size_t i
= 1; i
< d
->n_items
; i
++)
2365 for (size_t j
= 0; j
< i
; j
++)
2366 if (path_startswith(d
->items
[i
].path
, d
->items
[j
].path
)) {
2367 d
->items
[i
].only_create
= true;
2372 ExecCleanMask
exec_clean_mask_from_string(const char *s
) {
2373 ExecDirectoryType t
;
2377 if (streq(s
, "all"))
2378 return EXEC_CLEAN_ALL
;
2379 if (streq(s
, "fdstore"))
2380 return EXEC_CLEAN_FDSTORE
;
2382 t
= exec_resource_type_from_string(s
);
2384 return (ExecCleanMask
) t
;
2389 static const char* const exec_input_table
[_EXEC_INPUT_MAX
] = {
2390 [EXEC_INPUT_NULL
] = "null",
2391 [EXEC_INPUT_TTY
] = "tty",
2392 [EXEC_INPUT_TTY_FORCE
] = "tty-force",
2393 [EXEC_INPUT_TTY_FAIL
] = "tty-fail",
2394 [EXEC_INPUT_SOCKET
] = "socket",
2395 [EXEC_INPUT_NAMED_FD
] = "fd",
2396 [EXEC_INPUT_DATA
] = "data",
2397 [EXEC_INPUT_FILE
] = "file",
2400 DEFINE_STRING_TABLE_LOOKUP(exec_input
, ExecInput
);
2402 static const char* const exec_output_table
[_EXEC_OUTPUT_MAX
] = {
2403 [EXEC_OUTPUT_INHERIT
] = "inherit",
2404 [EXEC_OUTPUT_NULL
] = "null",
2405 [EXEC_OUTPUT_TTY
] = "tty",
2406 [EXEC_OUTPUT_KMSG
] = "kmsg",
2407 [EXEC_OUTPUT_KMSG_AND_CONSOLE
] = "kmsg+console",
2408 [EXEC_OUTPUT_JOURNAL
] = "journal",
2409 [EXEC_OUTPUT_JOURNAL_AND_CONSOLE
] = "journal+console",
2410 [EXEC_OUTPUT_SOCKET
] = "socket",
2411 [EXEC_OUTPUT_NAMED_FD
] = "fd",
2412 [EXEC_OUTPUT_FILE
] = "file",
2413 [EXEC_OUTPUT_FILE_APPEND
] = "append",
2414 [EXEC_OUTPUT_FILE_TRUNCATE
] = "truncate",
2417 DEFINE_STRING_TABLE_LOOKUP(exec_output
, ExecOutput
);
2419 static const char* const exec_utmp_mode_table
[_EXEC_UTMP_MODE_MAX
] = {
2420 [EXEC_UTMP_INIT
] = "init",
2421 [EXEC_UTMP_LOGIN
] = "login",
2422 [EXEC_UTMP_USER
] = "user",
2425 DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode
, ExecUtmpMode
);
2427 static const char* const exec_preserve_mode_table
[_EXEC_PRESERVE_MODE_MAX
] = {
2428 [EXEC_PRESERVE_NO
] = "no",
2429 [EXEC_PRESERVE_YES
] = "yes",
2430 [EXEC_PRESERVE_RESTART
] = "restart",
2433 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode
, ExecPreserveMode
, EXEC_PRESERVE_YES
);
2435 /* This table maps ExecDirectoryType to the setting it is configured with in the unit */
2436 static const char* const exec_directory_type_table
[_EXEC_DIRECTORY_TYPE_MAX
] = {
2437 [EXEC_DIRECTORY_RUNTIME
] = "RuntimeDirectory",
2438 [EXEC_DIRECTORY_STATE
] = "StateDirectory",
2439 [EXEC_DIRECTORY_CACHE
] = "CacheDirectory",
2440 [EXEC_DIRECTORY_LOGS
] = "LogsDirectory",
2441 [EXEC_DIRECTORY_CONFIGURATION
] = "ConfigurationDirectory",
2444 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type
, ExecDirectoryType
);
2446 /* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
2447 static const char* const exec_directory_type_symlink_table
[_EXEC_DIRECTORY_TYPE_MAX
] = {
2448 [EXEC_DIRECTORY_RUNTIME
] = "RuntimeDirectorySymlink",
2449 [EXEC_DIRECTORY_STATE
] = "StateDirectorySymlink",
2450 [EXEC_DIRECTORY_CACHE
] = "CacheDirectorySymlink",
2451 [EXEC_DIRECTORY_LOGS
] = "LogsDirectorySymlink",
2452 [EXEC_DIRECTORY_CONFIGURATION
] = "ConfigurationDirectorySymlink",
2455 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink
, ExecDirectoryType
);
2457 /* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This
2458 * one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit
2459 * directories, specifically .timer units with their timestamp touch file. */
2460 static const char* const exec_resource_type_table
[_EXEC_DIRECTORY_TYPE_MAX
] = {
2461 [EXEC_DIRECTORY_RUNTIME
] = "runtime",
2462 [EXEC_DIRECTORY_STATE
] = "state",
2463 [EXEC_DIRECTORY_CACHE
] = "cache",
2464 [EXEC_DIRECTORY_LOGS
] = "logs",
2465 [EXEC_DIRECTORY_CONFIGURATION
] = "configuration",
2468 DEFINE_STRING_TABLE_LOOKUP(exec_resource_type
, ExecDirectoryType
);
2470 static const char* const exec_keyring_mode_table
[_EXEC_KEYRING_MODE_MAX
] = {
2471 [EXEC_KEYRING_INHERIT
] = "inherit",
2472 [EXEC_KEYRING_PRIVATE
] = "private",
2473 [EXEC_KEYRING_SHARED
] = "shared",
2476 DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode
, ExecKeyringMode
);