]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/execute.c
Merge pull request #29630 from DaanDeMeyer/manager-json
[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 const char *exec_context_tty_path(const ExecContext *context) {
77 assert(context);
78
79 if (context->stdio_as_fds)
80 return NULL;
81
82 if (context->tty_path)
83 return context->tty_path;
84
85 return "/dev/console";
86 }
87
88 int exec_context_tty_size(const ExecContext *context, unsigned *ret_rows, unsigned *ret_cols) {
89 unsigned rows, cols;
90 const char *tty;
91
92 assert(context);
93 assert(ret_rows);
94 assert(ret_cols);
95
96 rows = context->tty_rows;
97 cols = context->tty_cols;
98
99 tty = exec_context_tty_path(context);
100 if (tty)
101 (void) proc_cmdline_tty_size(tty, rows == UINT_MAX ? &rows : NULL, cols == UINT_MAX ? &cols : NULL);
102
103 *ret_rows = rows;
104 *ret_cols = cols;
105
106 return 0;
107 }
108
109 void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p) {
110 _cleanup_close_ int _fd = -EBADF, lock_fd = -EBADF;
111 const char *path = exec_context_tty_path(ASSERT_PTR(context));
112 int fd;
113
114 if (p && p->stdin_fd >= 0)
115 fd = p->stdin_fd;
116 else if (path) {
117 fd = _fd = open_terminal(path, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
118 if (fd < 0)
119 return;
120 } else
121 return; /* nothing to do */
122
123 /* Take a synchronization lock for the duration of the setup that we do here.
124 * systemd-vconsole-setup.service also takes the lock to avoid being interrupted.
125 * We open a new fd that will be closed automatically, and operate on it for convenience.
126 */
127 lock_fd = lock_dev_console();
128 if (lock_fd < 0)
129 return (void) log_debug_errno(lock_fd,
130 "Failed to lock /dev/console: %m");
131
132 if (context->tty_vhangup)
133 (void) terminal_vhangup_fd(fd);
134
135 if (context->tty_reset)
136 (void) reset_terminal_fd(fd, true);
137
138 if (p && p->stdin_fd >= 0) {
139 unsigned rows = context->tty_rows, cols = context->tty_cols;
140
141 (void) exec_context_tty_size(context, &rows, &cols);
142 (void) terminal_set_size_fd(p->stdin_fd, path, rows, cols);
143 }
144
145 if (context->tty_vt_disallocate && path)
146 (void) vt_disallocate(path);
147 }
148
149 static bool is_terminal_input(ExecInput i) {
150 return IN_SET(i,
151 EXEC_INPUT_TTY,
152 EXEC_INPUT_TTY_FORCE,
153 EXEC_INPUT_TTY_FAIL);
154 }
155
156 static bool is_terminal_output(ExecOutput o) {
157 return IN_SET(o,
158 EXEC_OUTPUT_TTY,
159 EXEC_OUTPUT_KMSG_AND_CONSOLE,
160 EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
161 }
162
163 bool exec_needs_network_namespace(const ExecContext *context) {
164 assert(context);
165
166 return context->private_network || context->network_namespace_path;
167 }
168
169 static bool exec_needs_ephemeral(const ExecContext *context) {
170 return (context->root_image || context->root_directory) && context->root_ephemeral;
171 }
172
173 bool exec_needs_ipc_namespace(const ExecContext *context) {
174 assert(context);
175
176 return context->private_ipc || context->ipc_namespace_path;
177 }
178
179 bool exec_needs_mount_namespace(
180 const ExecContext *context,
181 const ExecParameters *params,
182 const ExecRuntime *runtime) {
183
184 assert(context);
185
186 if (context->root_image)
187 return true;
188
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))
194 return true;
195
196 if (context->n_bind_mounts > 0)
197 return true;
198
199 if (context->n_temporary_filesystems > 0)
200 return true;
201
202 if (context->n_mount_images > 0)
203 return true;
204
205 if (context->n_extension_images > 0)
206 return true;
207
208 if (!strv_isempty(context->extension_directories))
209 return true;
210
211 if (!IN_SET(context->mount_propagation_flag, 0, MS_SHARED))
212 return true;
213
214 if (context->private_tmp && runtime && runtime->shared && (runtime->shared->tmp_dir || runtime->shared->var_tmp_dir))
215 return true;
216
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))
229 return true;
230
231 if (context->root_directory) {
232 if (exec_context_get_effective_mount_apivfs(context))
233 return true;
234
235 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
236 if (params && !params->prefix[t])
237 continue;
238
239 if (context->directories[t].n_items > 0)
240 return true;
241 }
242 }
243
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))
248 return true;
249
250 if (context->log_namespace)
251 return true;
252
253 return false;
254 }
255
256 bool exec_directory_is_private(const ExecContext *context, ExecDirectoryType type) {
257 assert(context);
258
259 if (!context->dynamic_user)
260 return false;
261
262 if (type == EXEC_DIRECTORY_CONFIGURATION)
263 return false;
264
265 if (type == EXEC_DIRECTORY_RUNTIME && context->runtime_directory_preserve_mode == EXEC_PRESERVE_NO)
266 return false;
267
268 return true;
269 }
270
271 int exec_params_get_cgroup_path(
272 const ExecParameters *params,
273 const CGroupContext *c,
274 char **ret) {
275
276 const char *subgroup = NULL;
277 char *p;
278
279 assert(params);
280 assert(ret);
281
282 if (!params->cgroup_path)
283 return -EINVAL;
284
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. */
293
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";
297 else
298 subgroup = c->delegate_subgroup;
299 }
300
301 if (subgroup)
302 p = path_join(params->cgroup_path, subgroup);
303 else
304 p = strdup(params->cgroup_path);
305 if (!p)
306 return -ENOMEM;
307
308 *ret = p;
309 return !!subgroup;
310 }
311
312 bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
313 assert(c);
314
315 return c->cpu_affinity_from_numa;
316 }
317
318 static void log_command_line(Unit *unit, const char *msg, const char *executable, char **argv) {
319 assert(unit);
320 assert(msg);
321 assert(executable);
322
323 if (!DEBUG_LOGGING)
324 return;
325
326 _cleanup_free_ char *cmdline = quote_command_line(argv, SHELL_ESCAPE_EMPTY);
327
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));
332 }
333
334 static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
335
336 int exec_spawn(Unit *unit,
337 ExecCommand *command,
338 const ExecContext *context,
339 ExecParameters *params,
340 ExecRuntime *runtime,
341 const CGroupContext *cgroup_context,
342 pid_t *ret) {
343
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;
348 pid_t pid;
349 int r;
350
351 assert(unit);
352 assert(unit->manager);
353 assert(unit->manager->executor_fd >= 0);
354 assert(command);
355 assert(context);
356 assert(ret);
357 assert(params);
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 */
360
361 LOG_CONTEXT_PUSH_UNIT(unit);
362
363 r = exec_context_load_environment(unit, context, &params->files_env);
364 if (r < 0)
365 return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
366
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();
370
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);
374
375 if (params->cgroup_path) {
376 r = exec_params_get_cgroup_path(params, cgroup_context, &subcgroup_path);
377 if (r < 0)
378 return log_unit_error_errno(unit, r, "Failed to acquire subcgroup path: %m");
379 if (r > 0) {
380 /* If there's a subcgroup, then let's create it here now (the main cgroup was already
381 * realized by the unit logic) */
382
383 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path);
384 if (r < 0)
385 return log_unit_error_errno(unit, r, "Failed to create subcgroup '%s': %m", subcgroup_path);
386 }
387 }
388
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
394 * target cgroup. */
395
396 r = open_serialization_file("sd-executor-state", &f);
397 if (r < 0)
398 return log_unit_error_errno(unit, r, "Failed to open serialization stream: %m");
399
400 fdset = fdset_new();
401 if (!fdset)
402 return log_oom();
403
404 r = exec_serialize_invocation(f, fdset, context, command, params, runtime, cgroup_context);
405 if (r < 0)
406 return log_unit_error_errno(unit, r, "Failed to serialize parameters: %m");
407
408 if (fseeko(f, 0, SEEK_SET) == (off_t) -1)
409 return log_unit_error_errno(unit, errno, "Failed to reseek on serialization stream: %m");
410
411 r = fd_cloexec(fileno(f), false);
412 if (r < 0)
413 return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialization fd: %m");
414
415 r = fdset_cloexec(fdset, false);
416 if (r < 0)
417 return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialized fds: %m");
418
419 r = log_level_to_string_alloc(log_get_max_level(), &log_level);
420 if (r < 0)
421 return log_unit_error_errno(unit, r, "Failed to convert log level to string: %m");
422
423 r = fd_get_path(unit->manager->executor_fd, &executor_path);
424 if (r < 0)
425 return log_unit_error_errno(unit, r, "Failed to get executor path from fd: %m");
426
427 xsprintf(serialization_fd_number, "%i", fileno(f));
428
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))),
436 environ,
437 &pid);
438 if (r < 0)
439 return log_unit_error_errno(unit, r, "Failed to spawn executor: %m");
440
441 log_unit_debug(unit, "Forked %s as "PID_FMT, command->path, pid);
442
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). */
446 if (subcgroup_path)
447 (void) cg_attach(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path, pid);
448
449 exec_status_start(&command->exec_status, pid);
450
451 *ret = pid;
452 return 0;
453 }
454
455 void exec_context_init(ExecContext *c) {
456 assert(c);
457
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(). */
460
461 *c = (ExecContext) {
462 .umask = 0022,
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,
473 .log_level_max = -1,
474 #if HAVE_SECCOMP
475 .syscall_errno = SECCOMP_ERROR_NUMBER_KILL,
476 #endif
477 .tty_rows = UINT_MAX,
478 .tty_cols = UINT_MAX,
479 .private_mounts = -1,
480 .memory_ksm = -1,
481 .set_login_environment = -1,
482 };
483
484 FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
485 d->mode = 0755;
486
487 numa_policy_reset(&c->numa_policy);
488
489 assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
490 }
491
492 void exec_context_done(ExecContext *c) {
493 assert(c);
494
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);
499
500 rlimit_free_all(c->rlimit);
501
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]);
505 }
506
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);
524
525 c->supplementary_groups = strv_free(c->supplementary_groups);
526
527 c->pam_name = mfree(c->pam_name);
528
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);
535
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);
543
544 cpu_set_reset(&c->cpu_set);
545 numa_policy_reset(&c->numa_policy);
546
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);
551
552 c->restrict_filesystems = set_free_free(c->restrict_filesystems);
553
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);
557
558 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
559 exec_directory_done(&c->directories[t]);
560
561 c->log_level_max = -1;
562
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);
566
567 c->log_ratelimit_interval_usec = 0;
568 c->log_ratelimit_burst = 0;
569
570 c->stdin_data = mfree(c->stdin_data);
571 c->stdin_data_size = 0;
572
573 c->network_namespace_path = mfree(c->network_namespace_path);
574 c->ipc_namespace_path = mfree(c->ipc_namespace_path);
575
576 c->log_namespace = mfree(c->log_namespace);
577
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);
581
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);
585 }
586
587 int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
588 assert(c);
589
590 if (!runtime_prefix)
591 return 0;
592
593 FOREACH_ARRAY(i, c->directories[EXEC_DIRECTORY_RUNTIME].items, c->directories[EXEC_DIRECTORY_RUNTIME].n_items) {
594 _cleanup_free_ char *p = NULL;
595
596 if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
597 p = path_join(runtime_prefix, "private", i->path);
598 else
599 p = path_join(runtime_prefix, i->path);
600 if (!p)
601 return -ENOMEM;
602
603 /* We execute this synchronously, since we need to be sure this is gone when we start the
604 * service next. */
605 (void) rm_rf(p, REMOVE_ROOT);
606
607 STRV_FOREACH(symlink, i->symlinks) {
608 _cleanup_free_ char *symlink_abs = NULL;
609
610 if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
611 symlink_abs = path_join(runtime_prefix, "private", *symlink);
612 else
613 symlink_abs = path_join(runtime_prefix, *symlink);
614 if (!symlink_abs)
615 return -ENOMEM;
616
617 (void) unlink(symlink_abs);
618 }
619 }
620
621 return 0;
622 }
623
624 int exec_context_destroy_mount_ns_dir(Unit *u) {
625 _cleanup_free_ char *p = NULL;
626
627 if (!u || !MANAGER_IS_SYSTEM(u->manager))
628 return 0;
629
630 p = path_join("/run/systemd/propagate/", u->id);
631 if (!p)
632 return -ENOMEM;
633
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);
637
638 return 0;
639 }
640
641 void exec_command_done(ExecCommand *c) {
642 assert(c);
643
644 c->path = mfree(c->path);
645 c->argv = strv_free(c->argv);
646 }
647
648 void exec_command_done_array(ExecCommand *c, size_t n) {
649 FOREACH_ARRAY(i, c, n)
650 exec_command_done(i);
651 }
652
653 ExecCommand* exec_command_free_list(ExecCommand *c) {
654 ExecCommand *i;
655
656 while ((i = LIST_POP(command, c))) {
657 exec_command_done(i);
658 free(i);
659 }
660
661 return NULL;
662 }
663
664 void exec_command_free_array(ExecCommand **c, size_t n) {
665 FOREACH_ARRAY(i, c, n)
666 *i = exec_command_free_list(*i);
667 }
668
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);
672 }
673
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);
678 }
679
680 typedef struct InvalidEnvInfo {
681 const Unit *unit;
682 const char *path;
683 } InvalidEnvInfo;
684
685 static void invalid_env(const char *p, void *userdata) {
686 InvalidEnvInfo *info = userdata;
687
688 log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path);
689 }
690
691 const char* exec_context_fdname(const ExecContext *c, int fd_index) {
692 assert(c);
693
694 switch (fd_index) {
695
696 case STDIN_FILENO:
697 if (c->std_input != EXEC_INPUT_NAMED_FD)
698 return NULL;
699
700 return c->stdio_fdname[STDIN_FILENO] ?: "stdin";
701
702 case STDOUT_FILENO:
703 if (c->std_output != EXEC_OUTPUT_NAMED_FD)
704 return NULL;
705
706 return c->stdio_fdname[STDOUT_FILENO] ?: "stdout";
707
708 case STDERR_FILENO:
709 if (c->std_error != EXEC_OUTPUT_NAMED_FD)
710 return NULL;
711
712 return c->stdio_fdname[STDERR_FILENO] ?: "stderr";
713
714 default:
715 return NULL;
716 }
717 }
718
719 static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***ret) {
720 _cleanup_strv_free_ char **v = NULL;
721 int r;
722
723 assert(c);
724 assert(ret);
725
726 STRV_FOREACH(i, c->environment_files) {
727 _cleanup_globfree_ glob_t pglob = {};
728 bool ignore = false;
729 char *fn = *i;
730
731 if (fn[0] == '-') {
732 ignore = true;
733 fn++;
734 }
735
736 if (!path_is_absolute(fn)) {
737 if (ignore)
738 continue;
739 return -EINVAL;
740 }
741
742 /* Filename supports globbing, take all matching files */
743 r = safe_glob(fn, 0, &pglob);
744 if (r < 0) {
745 if (ignore)
746 continue;
747 return r;
748 }
749
750 /* When we don't match anything, -ENOENT should be returned */
751 assert(pglob.gl_pathc > 0);
752
753 FOREACH_ARRAY(path, pglob.gl_pathv, pglob.gl_pathc) {
754 _cleanup_strv_free_ char **p = NULL;
755
756 r = load_env_file(NULL, *path, &p);
757 if (r < 0) {
758 if (ignore)
759 continue;
760 return r;
761 }
762
763 /* Log invalid environment variables with filename */
764 if (p) {
765 InvalidEnvInfo info = {
766 .unit = unit,
767 .path = *path,
768 };
769
770 p = strv_env_clean_with_callback(p, invalid_env, &info);
771 }
772
773 if (!v)
774 v = TAKE_PTR(p);
775 else {
776 char **m = strv_env_merge(v, p);
777 if (!m)
778 return -ENOMEM;
779
780 strv_free_and_replace(v, m);
781 }
782 }
783 }
784
785 *ret = TAKE_PTR(v);
786
787 return 0;
788 }
789
790 static bool tty_may_match_dev_console(const char *tty) {
791 _cleanup_free_ char *resolved = NULL;
792
793 if (!tty)
794 return true;
795
796 tty = skip_dev_prefix(tty);
797
798 /* trivial identity? */
799 if (streq(tty, "console"))
800 return true;
801
802 if (resolve_dev_console(&resolved) < 0)
803 return true; /* if we could not resolve, assume it may */
804
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));
807 }
808
809 static bool exec_context_may_touch_tty(const ExecContext *ec) {
810 assert(ec);
811
812 return ec->tty_reset ||
813 ec->tty_vhangup ||
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);
818 }
819
820 bool exec_context_may_touch_console(const ExecContext *ec) {
821
822 return exec_context_may_touch_tty(ec) &&
823 tty_may_match_dev_console(exec_context_tty_path(ec));
824 }
825
826 static void strv_fprintf(FILE *f, char **l) {
827 assert(f);
828
829 STRV_FOREACH(g, l)
830 fprintf(f, " %s", *g);
831 }
832
833 static void strv_dump(FILE* f, const char *prefix, const char *name, char **strv) {
834 assert(f);
835 assert(prefix);
836 assert(name);
837
838 if (!strv_isempty(strv)) {
839 fprintf(f, "%s%s:", prefix, name);
840 strv_fprintf(f, strv);
841 fputs("\n", f);
842 }
843 }
844
845 void exec_params_dump(const ExecParameters *p, FILE* f, const char *prefix) {
846 assert(p);
847 assert(f);
848
849 prefix = strempty(prefix);
850
851 fprintf(f,
852 "%sRuntimeScope: %s\n"
853 "%sExecFlags: %u\n"
854 "%sSELinuxContextNetwork: %s\n"
855 "%sCgroupSupportedMask: %u\n"
856 "%sCgroupPath: %s\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),
865 prefix, p->flags,
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));
876
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);
880
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));
883
884 strv_dump(f, prefix, "FilesEnv", p->files_env);
885 }
886
887 void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
888 int r;
889
890 assert(c);
891 assert(f);
892
893 prefix = strempty(prefix);
894
895 fprintf(f,
896 "%sUMask: %04o\n"
897 "%sWorkingDirectory: %s\n"
898 "%sRootDirectory: %s\n"
899 "%sRootEphemeral: %s\n"
900 "%sNonBlocking: %s\n"
901 "%sPrivateTmp: %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",
921 prefix, c->umask,
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));
946
947 if (c->set_login_environment >= 0)
948 fprintf(f, "%sSetLoginEnvironment: %s\n", prefix, yes_no(c->set_login_environment > 0));
949
950 if (c->root_image)
951 fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
952
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))
957 fprintf(f, " %s:%s",
958 partition_designator_to_string(o->partition_designator),
959 o->options);
960 fprintf(f, "\n");
961 }
962
963 if (c->root_hash) {
964 _cleanup_free_ char *encoded = NULL;
965 encoded = hexmem(c->root_hash, c->root_hash_size);
966 if (encoded)
967 fprintf(f, "%sRootHash: %s\n", prefix, encoded);
968 }
969
970 if (c->root_hash_path)
971 fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
972
973 if (c->root_hash_sig) {
974 _cleanup_free_ char *encoded = NULL;
975 ssize_t len;
976 len = base64mem(c->root_hash_sig, c->root_hash_sig_size, &encoded);
977 if (len)
978 fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded);
979 }
980
981 if (c->root_hash_sig_path)
982 fprintf(f, "%sRootHashSignature: %s\n", prefix, c->root_hash_sig_path);
983
984 if (c->root_verity)
985 fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
986
987 STRV_FOREACH(e, c->environment)
988 fprintf(f, "%sEnvironment: %s\n", prefix, *e);
989
990 STRV_FOREACH(e, c->environment_files)
991 fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
992
993 STRV_FOREACH(e, c->pass_environment)
994 fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
995
996 STRV_FOREACH(e, c->unset_environment)
997 fprintf(f, "%sUnsetEnvironment: %s\n", prefix, *e);
998
999 fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
1000
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);
1003
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);
1006
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);
1009 }
1010 }
1011
1012 fprintf(f, "%sTimeoutCleanSec: %s\n", prefix, FORMAT_TIMESPAN(c->timeout_clean_usec, USEC_PER_SEC));
1013
1014 if (c->memory_ksm >= 0)
1015 fprintf(f, "%sMemoryKSM: %s\n", prefix, yes_no(c->memory_ksm > 0));
1016
1017 if (c->nice_set)
1018 fprintf(f, "%sNice: %i\n", prefix, c->nice);
1019
1020 if (c->oom_score_adjust_set)
1021 fprintf(f, "%sOOMScoreAdjust: %i\n", prefix, c->oom_score_adjust);
1022
1023 if (c->coredump_filter_set)
1024 fprintf(f, "%sCoredumpFilter: 0x%"PRIx64"\n", prefix, c->coredump_filter);
1025
1026 for (unsigned i = 0; i < RLIM_NLIMITS; i++)
1027 if (c->rlimit[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);
1032 }
1033
1034 if (c->ioprio_set) {
1035 _cleanup_free_ char *class_str = NULL;
1036
1037 r = ioprio_class_to_string_alloc(ioprio_prio_class(c->ioprio), &class_str);
1038 if (r >= 0)
1039 fprintf(f, "%sIOSchedulingClass: %s\n", prefix, class_str);
1040
1041 fprintf(f, "%sIOPriority: %d\n", prefix, ioprio_prio_data(c->ioprio));
1042 }
1043
1044 if (c->cpu_sched_set) {
1045 _cleanup_free_ char *policy_str = NULL;
1046
1047 r = sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
1048 if (r >= 0)
1049 fprintf(f, "%sCPUSchedulingPolicy: %s\n", prefix, policy_str);
1050
1051 fprintf(f,
1052 "%sCPUSchedulingPriority: %i\n"
1053 "%sCPUSchedulingResetOnFork: %s\n",
1054 prefix, c->cpu_sched_priority,
1055 prefix, yes_no(c->cpu_sched_reset_on_fork));
1056 }
1057
1058 if (c->cpu_set.set) {
1059 _cleanup_free_ char *affinity = NULL;
1060
1061 affinity = cpu_set_to_range_string(&c->cpu_set);
1062 fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity);
1063 }
1064
1065 if (mpol_is_valid(numa_policy_get_type(&c->numa_policy))) {
1066 _cleanup_free_ char *nodes = NULL;
1067
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));
1071 }
1072
1073 if (c->timer_slack_nsec != NSEC_INFINITY)
1074 fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec);
1075
1076 fprintf(f,
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));
1083
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]);
1090
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]);
1105
1106 if (c->tty_path)
1107 fprintf(f,
1108 "%sTTYPath: %s\n"
1109 "%sTTYReset: %s\n"
1110 "%sTTYVHangup: %s\n"
1111 "%sTTYVTDisallocate: %s\n"
1112 "%sTTYRows: %u\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);
1120
1121 if (IN_SET(c->std_output,
1122 EXEC_OUTPUT_KMSG,
1123 EXEC_OUTPUT_JOURNAL,
1124 EXEC_OUTPUT_KMSG_AND_CONSOLE,
1125 EXEC_OUTPUT_JOURNAL_AND_CONSOLE) ||
1126 IN_SET(c->std_error,
1127 EXEC_OUTPUT_KMSG,
1128 EXEC_OUTPUT_JOURNAL,
1129 EXEC_OUTPUT_KMSG_AND_CONSOLE,
1130 EXEC_OUTPUT_JOURNAL_AND_CONSOLE)) {
1131
1132 _cleanup_free_ char *fac_str = NULL, *lvl_str = NULL;
1133
1134 r = log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
1135 if (r >= 0)
1136 fprintf(f, "%sSyslogFacility: %s\n", prefix, fac_str);
1137
1138 r = log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str);
1139 if (r >= 0)
1140 fprintf(f, "%sSyslogLevel: %s\n", prefix, lvl_str);
1141 }
1142
1143 if (c->log_level_max >= 0) {
1144 _cleanup_free_ char *t = NULL;
1145
1146 (void) log_level_to_string_alloc(c->log_level_max, &t);
1147
1148 fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t));
1149 }
1150
1151 if (c->log_ratelimit_interval_usec > 0)
1152 fprintf(f,
1153 "%sLogRateLimitIntervalSec: %s\n",
1154 prefix, FORMAT_TIMESPAN(c->log_ratelimit_interval_usec, USEC_PER_SEC));
1155
1156 if (c->log_ratelimit_burst > 0)
1157 fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_ratelimit_burst);
1158
1159 if (!set_isempty(c->log_filter_allowed_patterns) || !set_isempty(c->log_filter_denied_patterns)) {
1160 fprintf(f, "%sLogFilterPatterns:", prefix);
1161
1162 char *pattern;
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);
1167 fputc('\n', f);
1168 }
1169
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);
1173 fputc('\n', f);
1174 }
1175
1176 if (c->log_namespace)
1177 fprintf(f, "%sLogNamespace: %s\n", prefix, c->log_namespace);
1178
1179 if (c->secure_bits) {
1180 _cleanup_free_ char *str = NULL;
1181
1182 r = secure_bits_to_string_alloc(c->secure_bits, &str);
1183 if (r >= 0)
1184 fprintf(f, "%sSecure Bits: %s\n", prefix, str);
1185 }
1186
1187 if (c->capability_bounding_set != CAP_MASK_UNSET) {
1188 _cleanup_free_ char *str = NULL;
1189
1190 r = capability_set_to_string(c->capability_bounding_set, &str);
1191 if (r >= 0)
1192 fprintf(f, "%sCapabilityBoundingSet: %s\n", prefix, str);
1193 }
1194
1195 if (c->capability_ambient_set != 0) {
1196 _cleanup_free_ char *str = NULL;
1197
1198 r = capability_set_to_string(c->capability_ambient_set, &str);
1199 if (r >= 0)
1200 fprintf(f, "%sAmbientCapabilities: %s\n", prefix, str);
1201 }
1202
1203 if (c->user)
1204 fprintf(f, "%sUser: %s\n", prefix, c->user);
1205 if (c->group)
1206 fprintf(f, "%sGroup: %s\n", prefix, c->group);
1207
1208 fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
1209
1210 strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups);
1211
1212 if (c->pam_name)
1213 fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
1214
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);
1221
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 ? "-": "",
1226 mount->source,
1227 mount->destination,
1228 mount->recursive ? "rbind" : "norbind");
1229
1230 FOREACH_ARRAY(tmpfs, c->temporary_filesystems, c->n_temporary_filesystems)
1231 fprintf(f, "%sTemporaryFileSystem: %s%s%s\n", prefix,
1232 tmpfs->path,
1233 isempty(tmpfs->options) ? "" : ":",
1234 strempty(tmpfs->options));
1235
1236 if (c->utmp_id)
1237 fprintf(f,
1238 "%sUtmpIdentifier: %s\n",
1239 prefix, c->utmp_id);
1240
1241 if (c->selinux_context)
1242 fprintf(f,
1243 "%sSELinuxContext: %s%s\n",
1244 prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
1245
1246 if (c->apparmor_profile)
1247 fprintf(f,
1248 "%sAppArmorProfile: %s%s\n",
1249 prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
1250
1251 if (c->smack_process_label)
1252 fprintf(f,
1253 "%sSmackProcessLabel: %s%s\n",
1254 prefix, c->smack_process_label_ignore ? "-" : "", c->smack_process_label);
1255
1256 if (c->personality != PERSONALITY_INVALID)
1257 fprintf(f,
1258 "%sPersonality: %s\n",
1259 prefix, strna(personality_to_string(c->personality)));
1260
1261 fprintf(f,
1262 "%sLockPersonality: %s\n",
1263 prefix, yes_no(c->lock_personality));
1264
1265 if (c->syscall_filter) {
1266 fprintf(f,
1267 "%sSystemCallFilter: ",
1268 prefix);
1269
1270 if (!c->syscall_allow_list)
1271 fputc('~', f);
1272
1273 #if HAVE_SECCOMP
1274 void *id, *val;
1275 bool first = true;
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);
1280
1281 if (first)
1282 first = false;
1283 else
1284 fputc(' ', f);
1285
1286 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1287 fputs(strna(name), f);
1288
1289 if (num >= 0) {
1290 errno_name = seccomp_errno_or_action_to_string(num);
1291 if (errno_name)
1292 fprintf(f, ":%s", errno_name);
1293 else
1294 fprintf(f, ":%d", num);
1295 }
1296 }
1297 #endif
1298
1299 fputc('\n', f);
1300 }
1301
1302 if (c->syscall_archs) {
1303 fprintf(f,
1304 "%sSystemCallArchitectures:",
1305 prefix);
1306
1307 #if HAVE_SECCOMP
1308 void *id;
1309 SET_FOREACH(id, c->syscall_archs)
1310 fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1)));
1311 #endif
1312 fputc('\n', f);
1313 }
1314
1315 if (exec_context_restrict_namespaces_set(c)) {
1316 _cleanup_free_ char *s = NULL;
1317
1318 r = namespace_flags_to_string(c->restrict_namespaces, &s);
1319 if (r >= 0)
1320 fprintf(f, "%sRestrictNamespaces: %s\n",
1321 prefix, strna(s));
1322 }
1323
1324 #if HAVE_LIBBPF
1325 if (exec_context_restrict_filesystems_set(c)) {
1326 char *fs;
1327 SET_FOREACH(fs, c->restrict_filesystems)
1328 fprintf(f, "%sRestrictFileSystems: %s\n", prefix, fs);
1329 }
1330 #endif
1331
1332 if (c->network_namespace_path)
1333 fprintf(f,
1334 "%sNetworkNamespacePath: %s\n",
1335 prefix, c->network_namespace_path);
1336
1337 if (c->syscall_errno > 0) {
1338 fprintf(f, "%sSystemCallErrorNumber: ", prefix);
1339
1340 #if HAVE_SECCOMP
1341 const char *errno_name = seccomp_errno_or_action_to_string(c->syscall_errno);
1342 if (errno_name)
1343 fputs(errno_name, f);
1344 else
1345 fprintf(f, "%d", c->syscall_errno);
1346 #endif
1347 fputc('\n', f);
1348 }
1349
1350 FOREACH_ARRAY(mount, c->mount_images, c->n_mount_images) {
1351 fprintf(f, "%sMountImages: %s%s:%s", prefix,
1352 mount->ignore_enoent ? "-": "",
1353 mount->source,
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));
1359 fprintf(f, "\n");
1360 }
1361
1362 FOREACH_ARRAY(mount, c->extension_images, c->n_extension_images) {
1363 fprintf(f, "%sExtensionImages: %s%s", prefix,
1364 mount->ignore_enoent ? "-": "",
1365 mount->source);
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));
1370 fprintf(f, "\n");
1371 }
1372
1373 strv_dump(f, prefix, "ExtensionDirectories", c->extension_directories);
1374 }
1375
1376 bool exec_context_maintains_privileges(const ExecContext *c) {
1377 assert(c);
1378
1379 /* Returns true if the process forked off would run under
1380 * an unchanged UID or as root. */
1381
1382 if (!c->user)
1383 return true;
1384
1385 if (streq(c->user, "root") || streq(c->user, "0"))
1386 return true;
1387
1388 return false;
1389 }
1390
1391 int exec_context_get_effective_ioprio(const ExecContext *c) {
1392 int p;
1393
1394 assert(c);
1395
1396 if (c->ioprio_set)
1397 return c->ioprio;
1398
1399 p = ioprio_get(IOPRIO_WHO_PROCESS, 0);
1400 if (p < 0)
1401 return IOPRIO_DEFAULT_CLASS_AND_PRIO;
1402
1403 return ioprio_normalize(p);
1404 }
1405
1406 bool exec_context_get_effective_mount_apivfs(const ExecContext *c) {
1407 assert(c);
1408
1409 /* Explicit setting wins */
1410 if (c->mount_apivfs_set)
1411 return c->mount_apivfs;
1412
1413 /* Default to "yes" if root directory or image are specified */
1414 if (exec_context_with_rootfs(c))
1415 return true;
1416
1417 return false;
1418 }
1419
1420 void exec_context_free_log_extra_fields(ExecContext *c) {
1421 assert(c);
1422
1423 FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields)
1424 free(field->iov_base);
1425
1426 c->log_extra_fields = mfree(c->log_extra_fields);
1427 c->n_log_extra_fields = 0;
1428 }
1429
1430 void exec_context_revert_tty(ExecContext *c) {
1431 _cleanup_close_ int fd = -EBADF;
1432 const char *path;
1433 struct stat st;
1434 int r;
1435
1436 assert(c);
1437
1438 /* First, reset the TTY (possibly kicking everybody else from the TTY) */
1439 exec_context_tty_reset(c, NULL);
1440
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))
1445 return;
1446
1447 path = exec_context_tty_path(c);
1448 if (!path)
1449 return;
1450
1451 fd = open(path, O_PATH|O_CLOEXEC);
1452 if (fd < 0)
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",
1455 path);
1456
1457 if (fstat(fd, &st) < 0)
1458 return (void) log_warning_errno(errno, "Failed to stat TTY '%s', ignoring: %m", path);
1459
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);
1467
1468 r = fchmod_and_chown(fd, TTY_MODE, 0, TTY_GID);
1469 if (r < 0)
1470 log_warning_errno(r, "Failed to reset TTY ownership/access mode of %s, ignoring: %m", path);
1471 }
1472
1473 int exec_context_get_clean_directories(
1474 ExecContext *c,
1475 char **prefix,
1476 ExecCleanMask mask,
1477 char ***ret) {
1478
1479 _cleanup_strv_free_ char **l = NULL;
1480 int r;
1481
1482 assert(c);
1483 assert(prefix);
1484 assert(ret);
1485
1486 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
1487 if (!FLAGS_SET(mask, 1U << t))
1488 continue;
1489
1490 if (!prefix[t])
1491 continue;
1492
1493 FOREACH_ARRAY(i, c->directories[t].items, c->directories[t].n_items) {
1494 char *j;
1495
1496 j = path_join(prefix[t], i->path);
1497 if (!j)
1498 return -ENOMEM;
1499
1500 r = strv_consume(&l, j);
1501 if (r < 0)
1502 return r;
1503
1504 /* Also remove private directories unconditionally. */
1505 if (t != EXEC_DIRECTORY_CONFIGURATION) {
1506 j = path_join(prefix[t], "private", i->path);
1507 if (!j)
1508 return -ENOMEM;
1509
1510 r = strv_consume(&l, j);
1511 if (r < 0)
1512 return r;
1513 }
1514
1515 STRV_FOREACH(symlink, i->symlinks) {
1516 j = path_join(prefix[t], *symlink);
1517 if (!j)
1518 return -ENOMEM;
1519
1520 r = strv_consume(&l, j);
1521 if (r < 0)
1522 return r;
1523 }
1524 }
1525 }
1526
1527 *ret = TAKE_PTR(l);
1528 return 0;
1529 }
1530
1531 int exec_context_get_clean_mask(ExecContext *c, ExecCleanMask *ret) {
1532 ExecCleanMask mask = 0;
1533
1534 assert(c);
1535 assert(ret);
1536
1537 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
1538 if (c->directories[t].n_items > 0)
1539 mask |= 1U << t;
1540
1541 *ret = mask;
1542 return 0;
1543 }
1544
1545 int exec_context_get_oom_score_adjust(const ExecContext *c) {
1546 int n = 0, r;
1547
1548 assert(c);
1549
1550 if (c->oom_score_adjust_set)
1551 return c->oom_score_adjust;
1552
1553 r = get_oom_score_adjust(&n);
1554 if (r < 0)
1555 log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
1556
1557 return n;
1558 }
1559
1560 uint64_t exec_context_get_coredump_filter(const ExecContext *c) {
1561 _cleanup_free_ char *t = NULL;
1562 uint64_t n = COREDUMP_FILTER_MASK_DEFAULT;
1563 int r;
1564
1565 assert(c);
1566
1567 if (c->coredump_filter_set)
1568 return c->coredump_filter;
1569
1570 r = read_one_line_file("/proc/self/coredump_filter", &t);
1571 if (r < 0)
1572 log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
1573 else {
1574 r = safe_atoux64(t, &n);
1575 if (r < 0)
1576 log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
1577 }
1578
1579 return n;
1580 }
1581
1582 int exec_context_get_nice(const ExecContext *c) {
1583 int n;
1584
1585 assert(c);
1586
1587 if (c->nice_set)
1588 return c->nice;
1589
1590 errno = 0;
1591 n = getpriority(PRIO_PROCESS, 0);
1592 if (errno > 0) {
1593 log_debug_errno(errno, "Failed to get process nice value, ignoring: %m");
1594 n = 0;
1595 }
1596
1597 return n;
1598 }
1599
1600 int exec_context_get_cpu_sched_policy(const ExecContext *c) {
1601 int n;
1602
1603 assert(c);
1604
1605 if (c->cpu_sched_set)
1606 return c->cpu_sched_policy;
1607
1608 n = sched_getscheduler(0);
1609 if (n < 0)
1610 log_debug_errno(errno, "Failed to get scheduler policy, ignoring: %m");
1611
1612 return n < 0 ? SCHED_OTHER : n;
1613 }
1614
1615 int exec_context_get_cpu_sched_priority(const ExecContext *c) {
1616 struct sched_param p = {};
1617 int r;
1618
1619 assert(c);
1620
1621 if (c->cpu_sched_set)
1622 return c->cpu_sched_priority;
1623
1624 r = sched_getparam(0, &p);
1625 if (r < 0)
1626 log_debug_errno(errno, "Failed to get scheduler priority, ignoring: %m");
1627
1628 return r >= 0 ? p.sched_priority : 0;
1629 }
1630
1631 uint64_t exec_context_get_timer_slack_nsec(const ExecContext *c) {
1632 int r;
1633
1634 assert(c);
1635
1636 if (c->timer_slack_nsec != NSEC_INFINITY)
1637 return c->timer_slack_nsec;
1638
1639 r = prctl(PR_GET_TIMERSLACK);
1640 if (r < 0)
1641 log_debug_errno(r, "Failed to get timer slack, ignoring: %m");
1642
1643 return (uint64_t) MAX(r, 0);
1644 }
1645
1646 char** exec_context_get_syscall_filter(const ExecContext *c) {
1647 _cleanup_strv_free_ char **l = NULL;
1648
1649 assert(c);
1650
1651 #if HAVE_SECCOMP
1652 void *id, *val;
1653 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
1654 _cleanup_free_ char *name = NULL;
1655 const char *e = NULL;
1656 char *s;
1657 int num = PTR_TO_INT(val);
1658
1659 if (c->syscall_allow_list && num >= 0)
1660 /* syscall with num >= 0 in allow-list is denied. */
1661 continue;
1662
1663 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1664 if (!name)
1665 continue;
1666
1667 if (num >= 0) {
1668 e = seccomp_errno_or_action_to_string(num);
1669 if (e) {
1670 s = strjoin(name, ":", e);
1671 if (!s)
1672 return NULL;
1673 } else {
1674 if (asprintf(&s, "%s:%d", name, num) < 0)
1675 return NULL;
1676 }
1677 } else
1678 s = TAKE_PTR(name);
1679
1680 if (strv_consume(&l, s) < 0)
1681 return NULL;
1682 }
1683
1684 strv_sort(l);
1685 #endif
1686
1687 return l ? TAKE_PTR(l) : strv_new(NULL);
1688 }
1689
1690 char** exec_context_get_syscall_archs(const ExecContext *c) {
1691 _cleanup_strv_free_ char **l = NULL;
1692
1693 assert(c);
1694
1695 #if HAVE_SECCOMP
1696 void *id;
1697 SET_FOREACH(id, c->syscall_archs) {
1698 const char *name;
1699
1700 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
1701 if (!name)
1702 continue;
1703
1704 if (strv_extend(&l, name) < 0)
1705 return NULL;
1706 }
1707
1708 strv_sort(l);
1709 #endif
1710
1711 return l ? TAKE_PTR(l) : strv_new(NULL);
1712 }
1713
1714 char** exec_context_get_syscall_log(const ExecContext *c) {
1715 _cleanup_strv_free_ char **l = NULL;
1716
1717 assert(c);
1718
1719 #if HAVE_SECCOMP
1720 void *id, *val;
1721 HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
1722 char *name = NULL;
1723
1724 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1725 if (!name)
1726 continue;
1727
1728 if (strv_consume(&l, name) < 0)
1729 return NULL;
1730 }
1731
1732 strv_sort(l);
1733 #endif
1734
1735 return l ? TAKE_PTR(l) : strv_new(NULL);
1736 }
1737
1738 char** exec_context_get_address_families(const ExecContext *c) {
1739 _cleanup_strv_free_ char **l = NULL;
1740 void *af;
1741
1742 assert(c);
1743
1744 SET_FOREACH(af, c->address_families) {
1745 const char *name;
1746
1747 name = af_to_name(PTR_TO_INT(af));
1748 if (!name)
1749 continue;
1750
1751 if (strv_extend(&l, name) < 0)
1752 return NULL;
1753 }
1754
1755 strv_sort(l);
1756
1757 return l ? TAKE_PTR(l) : strv_new(NULL);
1758 }
1759
1760 char** exec_context_get_restrict_filesystems(const ExecContext *c) {
1761 _cleanup_strv_free_ char **l = NULL;
1762
1763 assert(c);
1764
1765 #if HAVE_LIBBPF
1766 l = set_get_strv(c->restrict_filesystems);
1767 if (!l)
1768 return NULL;
1769
1770 strv_sort(l);
1771 #endif
1772
1773 return l ? TAKE_PTR(l) : strv_new(NULL);
1774 }
1775
1776 void exec_status_start(ExecStatus *s, pid_t pid) {
1777 assert(s);
1778
1779 *s = (ExecStatus) {
1780 .pid = pid,
1781 };
1782
1783 dual_timestamp_get(&s->start_timestamp);
1784 }
1785
1786 void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status) {
1787 assert(s);
1788
1789 if (s->pid != pid)
1790 *s = (ExecStatus) {
1791 .pid = pid,
1792 };
1793
1794 dual_timestamp_get(&s->exit_timestamp);
1795
1796 s->code = code;
1797 s->status = status;
1798
1799 if (context && context->utmp_id)
1800 (void) utmp_put_dead_process(context->utmp_id, pid, code, status);
1801 }
1802
1803 void exec_status_reset(ExecStatus *s) {
1804 assert(s);
1805
1806 *s = (ExecStatus) {};
1807 }
1808
1809 void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
1810 assert(s);
1811 assert(f);
1812
1813 if (s->pid <= 0)
1814 return;
1815
1816 prefix = strempty(prefix);
1817
1818 fprintf(f,
1819 "%sPID: "PID_FMT"\n",
1820 prefix, s->pid);
1821
1822 if (dual_timestamp_is_set(&s->start_timestamp))
1823 fprintf(f,
1824 "%sStart Timestamp: %s\n",
1825 prefix, FORMAT_TIMESTAMP(s->start_timestamp.realtime));
1826
1827 if (dual_timestamp_is_set(&s->exit_timestamp))
1828 fprintf(f,
1829 "%sExit Timestamp: %s\n"
1830 "%sExit Code: %s\n"
1831 "%sExit Status: %i\n",
1832 prefix, FORMAT_TIMESTAMP(s->exit_timestamp.realtime),
1833 prefix, sigchld_code_to_string(s->code),
1834 prefix, s->status);
1835 }
1836
1837 static void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
1838 _cleanup_free_ char *cmd = NULL;
1839 const char *prefix2;
1840
1841 assert(c);
1842 assert(f);
1843
1844 prefix = strempty(prefix);
1845 prefix2 = strjoina(prefix, "\t");
1846
1847 cmd = quote_command_line(c->argv, SHELL_ESCAPE_EMPTY);
1848
1849 fprintf(f,
1850 "%sCommand Line: %s\n",
1851 prefix, strnull(cmd));
1852
1853 exec_status_dump(&c->exec_status, f, prefix2);
1854 }
1855
1856 void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
1857 assert(f);
1858
1859 prefix = strempty(prefix);
1860
1861 LIST_FOREACH(command, i, c)
1862 exec_command_dump(i, f, prefix);
1863 }
1864
1865 void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
1866 ExecCommand *end;
1867
1868 assert(l);
1869 assert(e);
1870
1871 if (*l) {
1872 /* It's kind of important, that we keep the order here */
1873 end = LIST_FIND_TAIL(command, *l);
1874 LIST_INSERT_AFTER(command, *l, end, e);
1875 } else
1876 *l = e;
1877 }
1878
1879 int exec_command_set(ExecCommand *c, const char *path, ...) {
1880 va_list ap;
1881 char **l, *p;
1882
1883 assert(c);
1884 assert(path);
1885
1886 va_start(ap, path);
1887 l = strv_new_ap(path, ap);
1888 va_end(ap);
1889
1890 if (!l)
1891 return -ENOMEM;
1892
1893 p = strdup(path);
1894 if (!p) {
1895 strv_free(l);
1896 return -ENOMEM;
1897 }
1898
1899 free_and_replace(c->path, p);
1900
1901 return strv_free_and_replace(c->argv, l);
1902 }
1903
1904 int exec_command_append(ExecCommand *c, const char *path, ...) {
1905 _cleanup_strv_free_ char **l = NULL;
1906 va_list ap;
1907 int r;
1908
1909 assert(c);
1910 assert(path);
1911
1912 va_start(ap, path);
1913 l = strv_new_ap(path, ap);
1914 va_end(ap);
1915
1916 if (!l)
1917 return -ENOMEM;
1918
1919 r = strv_extend_strv(&c->argv, l, false);
1920 if (r < 0)
1921 return r;
1922
1923 return 0;
1924 }
1925
1926 static char *destroy_tree(char *path) {
1927 if (!path)
1928 return NULL;
1929
1930 if (!path_equal(path, RUN_SYSTEMD_EMPTY)) {
1931 log_debug("Spawning process to nuke '%s'", path);
1932
1933 (void) asynchronous_rm_rf(path, REMOVE_ROOT|REMOVE_SUBVOLUME|REMOVE_PHYSICAL);
1934 }
1935
1936 return mfree(path);
1937 }
1938
1939 void exec_shared_runtime_done(ExecSharedRuntime *rt) {
1940 if (!rt)
1941 return;
1942
1943 if (rt->manager)
1944 (void) hashmap_remove(rt->manager->exec_shared_runtime_by_id, rt->id);
1945
1946 rt->id = mfree(rt->id);
1947 rt->tmp_dir = mfree(rt->tmp_dir);
1948 rt->var_tmp_dir = mfree(rt->var_tmp_dir);
1949 safe_close_pair(rt->netns_storage_socket);
1950 safe_close_pair(rt->ipcns_storage_socket);
1951 }
1952
1953 static ExecSharedRuntime* exec_shared_runtime_free(ExecSharedRuntime *rt) {
1954 exec_shared_runtime_done(rt);
1955
1956 return mfree(rt);
1957 }
1958
1959 DEFINE_TRIVIAL_UNREF_FUNC(ExecSharedRuntime, exec_shared_runtime, exec_shared_runtime_free);
1960 DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSharedRuntime*, exec_shared_runtime_free);
1961
1962 ExecSharedRuntime* exec_shared_runtime_destroy(ExecSharedRuntime *rt) {
1963 if (!rt)
1964 return NULL;
1965
1966 assert(rt->n_ref > 0);
1967 rt->n_ref--;
1968
1969 if (rt->n_ref > 0)
1970 return NULL;
1971
1972 rt->tmp_dir = destroy_tree(rt->tmp_dir);
1973 rt->var_tmp_dir = destroy_tree(rt->var_tmp_dir);
1974
1975 return exec_shared_runtime_free(rt);
1976 }
1977
1978 static int exec_shared_runtime_allocate(ExecSharedRuntime **ret, const char *id) {
1979 _cleanup_free_ char *id_copy = NULL;
1980 ExecSharedRuntime *n;
1981
1982 assert(ret);
1983
1984 id_copy = strdup(id);
1985 if (!id_copy)
1986 return -ENOMEM;
1987
1988 n = new(ExecSharedRuntime, 1);
1989 if (!n)
1990 return -ENOMEM;
1991
1992 *n = (ExecSharedRuntime) {
1993 .id = TAKE_PTR(id_copy),
1994 .netns_storage_socket = PIPE_EBADF,
1995 .ipcns_storage_socket = PIPE_EBADF,
1996 };
1997
1998 *ret = n;
1999 return 0;
2000 }
2001
2002 static int exec_shared_runtime_add(
2003 Manager *m,
2004 const char *id,
2005 char **tmp_dir,
2006 char **var_tmp_dir,
2007 int netns_storage_socket[2],
2008 int ipcns_storage_socket[2],
2009 ExecSharedRuntime **ret) {
2010
2011 _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt = NULL;
2012 int r;
2013
2014 assert(m);
2015 assert(id);
2016
2017 /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
2018
2019 r = exec_shared_runtime_allocate(&rt, id);
2020 if (r < 0)
2021 return r;
2022
2023 r = hashmap_ensure_put(&m->exec_shared_runtime_by_id, &string_hash_ops, rt->id, rt);
2024 if (r < 0)
2025 return r;
2026
2027 assert(!!rt->tmp_dir == !!rt->var_tmp_dir); /* We require both to be set together */
2028 rt->tmp_dir = TAKE_PTR(*tmp_dir);
2029 rt->var_tmp_dir = TAKE_PTR(*var_tmp_dir);
2030
2031 if (netns_storage_socket) {
2032 rt->netns_storage_socket[0] = TAKE_FD(netns_storage_socket[0]);
2033 rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
2034 }
2035
2036 if (ipcns_storage_socket) {
2037 rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
2038 rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
2039 }
2040
2041 rt->manager = m;
2042
2043 if (ret)
2044 *ret = rt;
2045 /* do not remove created ExecSharedRuntime object when the operation succeeds. */
2046 TAKE_PTR(rt);
2047 return 0;
2048 }
2049
2050 static int exec_shared_runtime_make(
2051 Manager *m,
2052 const ExecContext *c,
2053 const char *id,
2054 ExecSharedRuntime **ret) {
2055
2056 _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
2057 _cleanup_close_pair_ int netns_storage_socket[2] = PIPE_EBADF, ipcns_storage_socket[2] = PIPE_EBADF;
2058 int r;
2059
2060 assert(m);
2061 assert(c);
2062 assert(id);
2063
2064 /* It is not necessary to create ExecSharedRuntime object. */
2065 if (!exec_needs_network_namespace(c) && !exec_needs_ipc_namespace(c) && !c->private_tmp) {
2066 *ret = NULL;
2067 return 0;
2068 }
2069
2070 if (c->private_tmp &&
2071 !(prefixed_path_strv_contains(c->inaccessible_paths, "/tmp") &&
2072 (prefixed_path_strv_contains(c->inaccessible_paths, "/var/tmp") ||
2073 prefixed_path_strv_contains(c->inaccessible_paths, "/var")))) {
2074 r = setup_tmp_dirs(id, &tmp_dir, &var_tmp_dir);
2075 if (r < 0)
2076 return r;
2077 }
2078
2079 if (exec_needs_network_namespace(c)) {
2080 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, netns_storage_socket) < 0)
2081 return -errno;
2082 }
2083
2084 if (exec_needs_ipc_namespace(c)) {
2085 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
2086 return -errno;
2087 }
2088
2089 r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
2090 if (r < 0)
2091 return r;
2092
2093 return 1;
2094 }
2095
2096 int exec_shared_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecSharedRuntime **ret) {
2097 ExecSharedRuntime *rt;
2098 int r;
2099
2100 assert(m);
2101 assert(id);
2102 assert(ret);
2103
2104 rt = hashmap_get(m->exec_shared_runtime_by_id, id);
2105 if (rt)
2106 /* We already have an ExecSharedRuntime object, let's increase the ref count and reuse it */
2107 goto ref;
2108
2109 if (!create) {
2110 *ret = NULL;
2111 return 0;
2112 }
2113
2114 /* If not found, then create a new object. */
2115 r = exec_shared_runtime_make(m, c, id, &rt);
2116 if (r < 0)
2117 return r;
2118 if (r == 0) {
2119 /* When r == 0, it is not necessary to create ExecSharedRuntime object. */
2120 *ret = NULL;
2121 return 0;
2122 }
2123
2124 ref:
2125 /* increment reference counter. */
2126 rt->n_ref++;
2127 *ret = rt;
2128 return 1;
2129 }
2130
2131 int exec_shared_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
2132 ExecSharedRuntime *rt;
2133
2134 assert(m);
2135 assert(f);
2136 assert(fds);
2137
2138 HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
2139 fprintf(f, "exec-runtime=%s", rt->id);
2140
2141 if (rt->tmp_dir)
2142 fprintf(f, " tmp-dir=%s", rt->tmp_dir);
2143
2144 if (rt->var_tmp_dir)
2145 fprintf(f, " var-tmp-dir=%s", rt->var_tmp_dir);
2146
2147 if (rt->netns_storage_socket[0] >= 0) {
2148 int copy;
2149
2150 copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
2151 if (copy < 0)
2152 return copy;
2153
2154 fprintf(f, " netns-socket-0=%i", copy);
2155 }
2156
2157 if (rt->netns_storage_socket[1] >= 0) {
2158 int copy;
2159
2160 copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
2161 if (copy < 0)
2162 return copy;
2163
2164 fprintf(f, " netns-socket-1=%i", copy);
2165 }
2166
2167 if (rt->ipcns_storage_socket[0] >= 0) {
2168 int copy;
2169
2170 copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
2171 if (copy < 0)
2172 return copy;
2173
2174 fprintf(f, " ipcns-socket-0=%i", copy);
2175 }
2176
2177 if (rt->ipcns_storage_socket[1] >= 0) {
2178 int copy;
2179
2180 copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
2181 if (copy < 0)
2182 return copy;
2183
2184 fprintf(f, " ipcns-socket-1=%i", copy);
2185 }
2186
2187 fputc('\n', f);
2188 }
2189
2190 return 0;
2191 }
2192
2193 int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
2194 _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt_create = NULL;
2195 ExecSharedRuntime *rt = NULL;
2196 int r;
2197
2198 /* This is for the migration from old (v237 or earlier) deserialization text.
2199 * Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
2200 * Even if the ExecSharedRuntime object originally created by the other unit, we cannot judge
2201 * so or not from the serialized text, then we always creates a new object owned by this. */
2202
2203 assert(u);
2204 assert(key);
2205 assert(value);
2206
2207 /* Manager manages ExecSharedRuntime objects by the unit id.
2208 * So, we omit the serialized text when the unit does not have id (yet?)... */
2209 if (isempty(u->id)) {
2210 log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.");
2211 return 0;
2212 }
2213
2214 if (u->manager) {
2215 if (hashmap_ensure_allocated(&u->manager->exec_shared_runtime_by_id, &string_hash_ops) < 0)
2216 return log_oom();
2217
2218 rt = hashmap_get(u->manager->exec_shared_runtime_by_id, u->id);
2219 }
2220 if (!rt) {
2221 if (exec_shared_runtime_allocate(&rt_create, u->id) < 0)
2222 return log_oom();
2223
2224 rt = rt_create;
2225 }
2226
2227 if (streq(key, "tmp-dir")) {
2228 if (free_and_strdup_warn(&rt->tmp_dir, value) < 0)
2229 return -ENOMEM;
2230
2231 } else if (streq(key, "var-tmp-dir")) {
2232 if (free_and_strdup_warn(&rt->var_tmp_dir, value) < 0)
2233 return -ENOMEM;
2234
2235 } else if (streq(key, "netns-socket-0")) {
2236
2237 safe_close(rt->netns_storage_socket[0]);
2238 rt->netns_storage_socket[0] = deserialize_fd(fds, value);
2239 if (rt->netns_storage_socket[0] < 0)
2240 return 0;
2241
2242 } else if (streq(key, "netns-socket-1")) {
2243
2244 safe_close(rt->netns_storage_socket[1]);
2245 rt->netns_storage_socket[1] = deserialize_fd(fds, value);
2246 if (rt->netns_storage_socket[1] < 0)
2247 return 0;
2248 } else
2249 return 0;
2250
2251 /* If the object is newly created, then put it to the hashmap which manages ExecSharedRuntime objects. */
2252 if (rt_create && u->manager) {
2253 r = hashmap_put(u->manager->exec_shared_runtime_by_id, rt_create->id, rt_create);
2254 if (r < 0) {
2255 log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m");
2256 return 0;
2257 }
2258
2259 rt_create->manager = u->manager;
2260
2261 /* Avoid cleanup */
2262 TAKE_PTR(rt_create);
2263 }
2264
2265 return 1;
2266 }
2267
2268 int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
2269 _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
2270 char *id = NULL;
2271 int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
2272 const char *p, *v = ASSERT_PTR(value);
2273 size_t n;
2274
2275 assert(m);
2276 assert(fds);
2277
2278 n = strcspn(v, " ");
2279 id = strndupa_safe(v, n);
2280 if (v[n] != ' ')
2281 goto finalize;
2282 p = v + n + 1;
2283
2284 v = startswith(p, "tmp-dir=");
2285 if (v) {
2286 n = strcspn(v, " ");
2287 tmp_dir = strndup(v, n);
2288 if (!tmp_dir)
2289 return log_oom();
2290 if (v[n] != ' ')
2291 goto finalize;
2292 p = v + n + 1;
2293 }
2294
2295 v = startswith(p, "var-tmp-dir=");
2296 if (v) {
2297 n = strcspn(v, " ");
2298 var_tmp_dir = strndup(v, n);
2299 if (!var_tmp_dir)
2300 return log_oom();
2301 if (v[n] != ' ')
2302 goto finalize;
2303 p = v + n + 1;
2304 }
2305
2306 v = startswith(p, "netns-socket-0=");
2307 if (v) {
2308 char *buf;
2309
2310 n = strcspn(v, " ");
2311 buf = strndupa_safe(v, n);
2312
2313 netns_fdpair[0] = deserialize_fd(fds, buf);
2314 if (netns_fdpair[0] < 0)
2315 return netns_fdpair[0];
2316 if (v[n] != ' ')
2317 goto finalize;
2318 p = v + n + 1;
2319 }
2320
2321 v = startswith(p, "netns-socket-1=");
2322 if (v) {
2323 char *buf;
2324
2325 n = strcspn(v, " ");
2326 buf = strndupa_safe(v, n);
2327
2328 netns_fdpair[1] = deserialize_fd(fds, buf);
2329 if (netns_fdpair[1] < 0)
2330 return netns_fdpair[1];
2331 if (v[n] != ' ')
2332 goto finalize;
2333 p = v + n + 1;
2334 }
2335
2336 v = startswith(p, "ipcns-socket-0=");
2337 if (v) {
2338 char *buf;
2339
2340 n = strcspn(v, " ");
2341 buf = strndupa_safe(v, n);
2342
2343 ipcns_fdpair[0] = deserialize_fd(fds, buf);
2344 if (ipcns_fdpair[0] < 0)
2345 return ipcns_fdpair[0];
2346 if (v[n] != ' ')
2347 goto finalize;
2348 p = v + n + 1;
2349 }
2350
2351 v = startswith(p, "ipcns-socket-1=");
2352 if (v) {
2353 char *buf;
2354
2355 n = strcspn(v, " ");
2356 buf = strndupa_safe(v, n);
2357
2358 ipcns_fdpair[1] = deserialize_fd(fds, buf);
2359 if (ipcns_fdpair[1] < 0)
2360 return ipcns_fdpair[1];
2361 }
2362
2363 finalize:
2364 r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
2365 if (r < 0)
2366 return log_debug_errno(r, "Failed to add exec-runtime: %m");
2367 return 0;
2368 }
2369
2370 void exec_shared_runtime_vacuum(Manager *m) {
2371 ExecSharedRuntime *rt;
2372
2373 assert(m);
2374
2375 /* Free unreferenced ExecSharedRuntime objects. This is used after manager deserialization process. */
2376
2377 HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
2378 if (rt->n_ref > 0)
2379 continue;
2380
2381 (void) exec_shared_runtime_free(rt);
2382 }
2383 }
2384
2385 int exec_runtime_make(
2386 const Unit *unit,
2387 const ExecContext *context,
2388 ExecSharedRuntime *shared,
2389 DynamicCreds *creds,
2390 ExecRuntime **ret) {
2391 _cleanup_close_pair_ int ephemeral_storage_socket[2] = PIPE_EBADF;
2392 _cleanup_free_ char *ephemeral = NULL;
2393 _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
2394 int r;
2395
2396 assert(unit);
2397 assert(context);
2398 assert(ret);
2399
2400 if (!shared && !creds && !exec_needs_ephemeral(context)) {
2401 *ret = NULL;
2402 return 0;
2403 }
2404
2405 if (exec_needs_ephemeral(context)) {
2406 r = mkdir_p("/var/lib/systemd/ephemeral-trees", 0755);
2407 if (r < 0)
2408 return r;
2409
2410 r = tempfn_random_child("/var/lib/systemd/ephemeral-trees", unit->id, &ephemeral);
2411 if (r < 0)
2412 return r;
2413
2414 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ephemeral_storage_socket) < 0)
2415 return -errno;
2416 }
2417
2418 rt = new(ExecRuntime, 1);
2419 if (!rt)
2420 return -ENOMEM;
2421
2422 *rt = (ExecRuntime) {
2423 .shared = shared,
2424 .dynamic_creds = creds,
2425 .ephemeral_copy = TAKE_PTR(ephemeral),
2426 .ephemeral_storage_socket[0] = TAKE_FD(ephemeral_storage_socket[0]),
2427 .ephemeral_storage_socket[1] = TAKE_FD(ephemeral_storage_socket[1]),
2428 };
2429
2430 *ret = TAKE_PTR(rt);
2431 return 1;
2432 }
2433
2434 ExecRuntime* exec_runtime_free(ExecRuntime *rt) {
2435 if (!rt)
2436 return NULL;
2437
2438 exec_shared_runtime_unref(rt->shared);
2439 dynamic_creds_unref(rt->dynamic_creds);
2440
2441 rt->ephemeral_copy = destroy_tree(rt->ephemeral_copy);
2442
2443 safe_close_pair(rt->ephemeral_storage_socket);
2444 return mfree(rt);
2445 }
2446
2447 ExecRuntime* exec_runtime_destroy(ExecRuntime *rt) {
2448 if (!rt)
2449 return NULL;
2450
2451 rt->shared = exec_shared_runtime_destroy(rt->shared);
2452 rt->dynamic_creds = dynamic_creds_destroy(rt->dynamic_creds);
2453 return exec_runtime_free(rt);
2454 }
2455
2456 void exec_runtime_clear(ExecRuntime *rt) {
2457 if (!rt)
2458 return;
2459
2460 safe_close_pair(rt->ephemeral_storage_socket);
2461 rt->ephemeral_copy = mfree(rt->ephemeral_copy);
2462 }
2463
2464 void exec_params_clear(ExecParameters *p) {
2465 if (!p)
2466 return;
2467
2468 p->environment = strv_free(p->environment);
2469 p->fd_names = strv_free(p->fd_names);
2470 p->files_env = strv_free(p->files_env);
2471 p->fds = mfree(p->fds);
2472 p->exec_fd = safe_close(p->exec_fd);
2473 p->user_lookup_fd = -EBADF;
2474 p->bpf_outer_map_fd = -EBADF;
2475 p->unit_id = mfree(p->unit_id);
2476 p->invocation_id = SD_ID128_NULL;
2477 p->invocation_id_string[0] = '\0';
2478 p->confirm_spawn = mfree(p->confirm_spawn);
2479 }
2480
2481 void exec_params_serialized_done(ExecParameters *p) {
2482 if (!p)
2483 return;
2484
2485 close_many_unset(p->fds, p->n_socket_fds + p->n_storage_fds);
2486
2487 p->cgroup_path = mfree(p->cgroup_path);
2488
2489 if (p->prefix) {
2490 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
2491 free(p->prefix[t]);
2492
2493 p->prefix = mfree(p->prefix);
2494 }
2495
2496 p->received_credentials_directory = mfree(p->received_credentials_directory);
2497 p->received_encrypted_credentials_directory = mfree(p->received_encrypted_credentials_directory);
2498
2499 if (p->idle_pipe) {
2500 close_many_and_free(p->idle_pipe, 4);
2501 p->idle_pipe = NULL;
2502 }
2503
2504 p->stdin_fd = safe_close(p->stdin_fd);
2505 p->stdout_fd = safe_close(p->stdout_fd);
2506 p->stderr_fd = safe_close(p->stderr_fd);
2507
2508 p->notify_socket = mfree(p->notify_socket);
2509
2510 open_file_free_many(&p->open_files);
2511
2512 p->fallback_smack_process_label = mfree(p->fallback_smack_process_label);
2513
2514 exec_params_clear(p);
2515 }
2516
2517 void exec_directory_done(ExecDirectory *d) {
2518 if (!d)
2519 return;
2520
2521 FOREACH_ARRAY(i, d->items, d->n_items) {
2522 free(i->path);
2523 strv_free(i->symlinks);
2524 }
2525
2526 d->items = mfree(d->items);
2527 d->n_items = 0;
2528 d->mode = 0755;
2529 }
2530
2531 static ExecDirectoryItem *exec_directory_find(ExecDirectory *d, const char *path) {
2532 assert(d);
2533 assert(path);
2534
2535 FOREACH_ARRAY(i, d->items, d->n_items)
2536 if (path_equal(i->path, path))
2537 return i;
2538
2539 return NULL;
2540 }
2541
2542 int exec_directory_add(ExecDirectory *d, const char *path, const char *symlink) {
2543 _cleanup_strv_free_ char **s = NULL;
2544 _cleanup_free_ char *p = NULL;
2545 ExecDirectoryItem *existing;
2546 int r;
2547
2548 assert(d);
2549 assert(path);
2550
2551 existing = exec_directory_find(d, path);
2552 if (existing) {
2553 r = strv_extend(&existing->symlinks, symlink);
2554 if (r < 0)
2555 return r;
2556
2557 return 0; /* existing item is updated */
2558 }
2559
2560 p = strdup(path);
2561 if (!p)
2562 return -ENOMEM;
2563
2564 if (symlink) {
2565 s = strv_new(symlink);
2566 if (!s)
2567 return -ENOMEM;
2568 }
2569
2570 if (!GREEDY_REALLOC(d->items, d->n_items + 1))
2571 return -ENOMEM;
2572
2573 d->items[d->n_items++] = (ExecDirectoryItem) {
2574 .path = TAKE_PTR(p),
2575 .symlinks = TAKE_PTR(s),
2576 };
2577
2578 return 1; /* new item is added */
2579 }
2580
2581 static int exec_directory_item_compare_func(const ExecDirectoryItem *a, const ExecDirectoryItem *b) {
2582 assert(a);
2583 assert(b);
2584
2585 return path_compare(a->path, b->path);
2586 }
2587
2588 void exec_directory_sort(ExecDirectory *d) {
2589 assert(d);
2590
2591 /* Sort the exec directories to make always parent directories processed at first in
2592 * setup_exec_directory(), e.g., even if StateDirectory=foo/bar foo, we need to create foo at first,
2593 * then foo/bar. Also, set .only_create flag if one of the parent directories is contained in the
2594 * list. See also comments in setup_exec_directory() and issue #24783. */
2595
2596 if (d->n_items <= 1)
2597 return;
2598
2599 typesafe_qsort(d->items, d->n_items, exec_directory_item_compare_func);
2600
2601 for (size_t i = 1; i < d->n_items; i++)
2602 for (size_t j = 0; j < i; j++)
2603 if (path_startswith(d->items[i].path, d->items[j].path)) {
2604 d->items[i].only_create = true;
2605 break;
2606 }
2607 }
2608
2609 ExecCleanMask exec_clean_mask_from_string(const char *s) {
2610 ExecDirectoryType t;
2611
2612 assert(s);
2613
2614 if (streq(s, "all"))
2615 return EXEC_CLEAN_ALL;
2616 if (streq(s, "fdstore"))
2617 return EXEC_CLEAN_FDSTORE;
2618
2619 t = exec_resource_type_from_string(s);
2620 if (t < 0)
2621 return (ExecCleanMask) t;
2622
2623 return 1U << t;
2624 }
2625
2626 static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
2627 [EXEC_INPUT_NULL] = "null",
2628 [EXEC_INPUT_TTY] = "tty",
2629 [EXEC_INPUT_TTY_FORCE] = "tty-force",
2630 [EXEC_INPUT_TTY_FAIL] = "tty-fail",
2631 [EXEC_INPUT_SOCKET] = "socket",
2632 [EXEC_INPUT_NAMED_FD] = "fd",
2633 [EXEC_INPUT_DATA] = "data",
2634 [EXEC_INPUT_FILE] = "file",
2635 };
2636
2637 DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
2638
2639 static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
2640 [EXEC_OUTPUT_INHERIT] = "inherit",
2641 [EXEC_OUTPUT_NULL] = "null",
2642 [EXEC_OUTPUT_TTY] = "tty",
2643 [EXEC_OUTPUT_KMSG] = "kmsg",
2644 [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
2645 [EXEC_OUTPUT_JOURNAL] = "journal",
2646 [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
2647 [EXEC_OUTPUT_SOCKET] = "socket",
2648 [EXEC_OUTPUT_NAMED_FD] = "fd",
2649 [EXEC_OUTPUT_FILE] = "file",
2650 [EXEC_OUTPUT_FILE_APPEND] = "append",
2651 [EXEC_OUTPUT_FILE_TRUNCATE] = "truncate",
2652 };
2653
2654 DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
2655
2656 static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
2657 [EXEC_UTMP_INIT] = "init",
2658 [EXEC_UTMP_LOGIN] = "login",
2659 [EXEC_UTMP_USER] = "user",
2660 };
2661
2662 DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode);
2663
2664 static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
2665 [EXEC_PRESERVE_NO] = "no",
2666 [EXEC_PRESERVE_YES] = "yes",
2667 [EXEC_PRESERVE_RESTART] = "restart",
2668 };
2669
2670 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
2671
2672 /* This table maps ExecDirectoryType to the setting it is configured with in the unit */
2673 static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2674 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory",
2675 [EXEC_DIRECTORY_STATE] = "StateDirectory",
2676 [EXEC_DIRECTORY_CACHE] = "CacheDirectory",
2677 [EXEC_DIRECTORY_LOGS] = "LogsDirectory",
2678 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
2679 };
2680
2681 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
2682
2683 /* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
2684 static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2685 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectorySymlink",
2686 [EXEC_DIRECTORY_STATE] = "StateDirectorySymlink",
2687 [EXEC_DIRECTORY_CACHE] = "CacheDirectorySymlink",
2688 [EXEC_DIRECTORY_LOGS] = "LogsDirectorySymlink",
2689 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectorySymlink",
2690 };
2691
2692 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink, ExecDirectoryType);
2693
2694 static const char* const exec_directory_type_mode_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2695 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectoryMode",
2696 [EXEC_DIRECTORY_STATE] = "StateDirectoryMode",
2697 [EXEC_DIRECTORY_CACHE] = "CacheDirectoryMode",
2698 [EXEC_DIRECTORY_LOGS] = "LogsDirectoryMode",
2699 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectoryMode",
2700 };
2701
2702 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_mode, ExecDirectoryType);
2703
2704 /* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This
2705 * one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit
2706 * directories, specifically .timer units with their timestamp touch file. */
2707 static const char* const exec_resource_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2708 [EXEC_DIRECTORY_RUNTIME] = "runtime",
2709 [EXEC_DIRECTORY_STATE] = "state",
2710 [EXEC_DIRECTORY_CACHE] = "cache",
2711 [EXEC_DIRECTORY_LOGS] = "logs",
2712 [EXEC_DIRECTORY_CONFIGURATION] = "configuration",
2713 };
2714
2715 DEFINE_STRING_TABLE_LOOKUP(exec_resource_type, ExecDirectoryType);
2716
2717 static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
2718 [EXEC_KEYRING_INHERIT] = "inherit",
2719 [EXEC_KEYRING_PRIVATE] = "private",
2720 [EXEC_KEYRING_SHARED] = "shared",
2721 };
2722
2723 DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode, ExecKeyringMode);