]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-execute.c
Merge pull request #18990 from yuwata/network-dhcpv6-use-domains
[thirdparty/systemd.git] / src / core / dbus-execute.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <sys/mount.h>
4 #include <sys/prctl.h>
5
6 #if HAVE_SECCOMP
7 #include <seccomp.h>
8 #endif
9
10 #include "af-list.h"
11 #include "alloc-util.h"
12 #include "bus-get-properties.h"
13 #include "cap-list.h"
14 #include "capability-util.h"
15 #include "cpu-set-util.h"
16 #include "creds-util.h"
17 #include "dbus-execute.h"
18 #include "dbus-util.h"
19 #include "env-util.h"
20 #include "errno-list.h"
21 #include "escape.h"
22 #include "execute.h"
23 #include "fd-util.h"
24 #include "fileio.h"
25 #include "hexdecoct.h"
26 #include "io-util.h"
27 #include "ioprio.h"
28 #include "journal-file.h"
29 #include "mountpoint-util.h"
30 #include "namespace.h"
31 #include "parse-util.h"
32 #include "path-util.h"
33 #include "process-util.h"
34 #include "rlimit-util.h"
35 #if HAVE_SECCOMP
36 #include "seccomp-util.h"
37 #endif
38 #include "securebits-util.h"
39 #include "specifier.h"
40 #include "strv.h"
41 #include "syslog-util.h"
42 #include "unit-printf.h"
43 #include "user-util.h"
44 #include "utf8.h"
45
46 BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
47 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
48 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode);
49 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode);
50 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode);
51 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_proc, protect_proc, ProtectProc);
52 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_proc_subset, proc_subset, ProcSubset);
53 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_home, protect_home, ProtectHome);
54 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_system, protect_system, ProtectSystem);
55 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_personality, personality, unsigned long);
56 static BUS_DEFINE_PROPERTY_GET(property_get_ioprio, "i", ExecContext, exec_context_get_effective_ioprio);
57 static BUS_DEFINE_PROPERTY_GET(property_get_mount_apivfs, "b", ExecContext, exec_context_get_effective_mount_apivfs);
58 static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_class, "i", ExecContext, exec_context_get_effective_ioprio, IOPRIO_PRIO_CLASS);
59 static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_priority, "i", ExecContext, exec_context_get_effective_ioprio, IOPRIO_PRIO_DATA);
60 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL);
61 static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_level, "i", int, LOG_PRI);
62 static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_facility, "i", int, LOG_FAC);
63 static BUS_DEFINE_PROPERTY_GET(property_get_cpu_affinity_from_numa, "b", ExecContext, exec_context_get_cpu_affinity_from_numa);
64
65 static int property_get_environment_files(
66 sd_bus *bus,
67 const char *path,
68 const char *interface,
69 const char *property,
70 sd_bus_message *reply,
71 void *userdata,
72 sd_bus_error *error) {
73
74 ExecContext *c = userdata;
75 char **j;
76 int r;
77
78 assert(bus);
79 assert(reply);
80 assert(c);
81
82 r = sd_bus_message_open_container(reply, 'a', "(sb)");
83 if (r < 0)
84 return r;
85
86 STRV_FOREACH(j, c->environment_files) {
87 const char *fn = *j;
88
89 r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
90 if (r < 0)
91 return r;
92 }
93
94 return sd_bus_message_close_container(reply);
95 }
96
97 static int property_get_oom_score_adjust(
98 sd_bus *bus,
99 const char *path,
100 const char *interface,
101 const char *property,
102 sd_bus_message *reply,
103 void *userdata,
104 sd_bus_error *error) {
105
106 ExecContext *c = userdata;
107 int32_t n;
108 int r;
109
110 assert(bus);
111 assert(reply);
112 assert(c);
113
114 if (c->oom_score_adjust_set)
115 n = c->oom_score_adjust;
116 else {
117 _cleanup_free_ char *t = NULL;
118
119 n = 0;
120 r = read_one_line_file("/proc/self/oom_score_adj", &t);
121 if (r < 0)
122 log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
123 else {
124 r = safe_atoi32(t, &n);
125 if (r < 0)
126 log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/oom_score_adj, ignoring: %m", t);
127 }
128 }
129
130 return sd_bus_message_append(reply, "i", n);
131 }
132
133 static int property_get_coredump_filter(
134 sd_bus *bus,
135 const char *path,
136 const char *interface,
137 const char *property,
138 sd_bus_message *reply,
139 void *userdata,
140 sd_bus_error *error) {
141
142 ExecContext *c = userdata;
143 uint64_t n;
144 int r;
145
146 assert(bus);
147 assert(reply);
148 assert(c);
149
150 if (c->coredump_filter_set)
151 n = c->coredump_filter;
152 else {
153 _cleanup_free_ char *t = NULL;
154
155 n = COREDUMP_FILTER_MASK_DEFAULT;
156 r = read_one_line_file("/proc/self/coredump_filter", &t);
157 if (r < 0)
158 log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
159 else {
160 r = safe_atoux64(t, &n);
161 if (r < 0)
162 log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
163 }
164 }
165
166 return sd_bus_message_append(reply, "t", n);
167 }
168
169 static int property_get_nice(
170 sd_bus *bus,
171 const char *path,
172 const char *interface,
173 const char *property,
174 sd_bus_message *reply,
175 void *userdata,
176 sd_bus_error *error) {
177
178 ExecContext *c = userdata;
179 int32_t n;
180
181 assert(bus);
182 assert(reply);
183 assert(c);
184
185 if (c->nice_set)
186 n = c->nice;
187 else {
188 errno = 0;
189 n = getpriority(PRIO_PROCESS, 0);
190 if (errno > 0)
191 n = 0;
192 }
193
194 return sd_bus_message_append(reply, "i", n);
195 }
196
197 static int property_get_cpu_sched_policy(
198 sd_bus *bus,
199 const char *path,
200 const char *interface,
201 const char *property,
202 sd_bus_message *reply,
203 void *userdata,
204 sd_bus_error *error) {
205
206 ExecContext *c = userdata;
207 int32_t n;
208
209 assert(bus);
210 assert(reply);
211 assert(c);
212
213 if (c->cpu_sched_set)
214 n = c->cpu_sched_policy;
215 else {
216 n = sched_getscheduler(0);
217 if (n < 0)
218 n = SCHED_OTHER;
219 }
220
221 return sd_bus_message_append(reply, "i", n);
222 }
223
224 static int property_get_cpu_sched_priority(
225 sd_bus *bus,
226 const char *path,
227 const char *interface,
228 const char *property,
229 sd_bus_message *reply,
230 void *userdata,
231 sd_bus_error *error) {
232
233 ExecContext *c = userdata;
234 int32_t n;
235
236 assert(bus);
237 assert(reply);
238 assert(c);
239
240 if (c->cpu_sched_set)
241 n = c->cpu_sched_priority;
242 else {
243 struct sched_param p = {};
244
245 if (sched_getparam(0, &p) >= 0)
246 n = p.sched_priority;
247 else
248 n = 0;
249 }
250
251 return sd_bus_message_append(reply, "i", n);
252 }
253
254 static int property_get_cpu_affinity(
255 sd_bus *bus,
256 const char *path,
257 const char *interface,
258 const char *property,
259 sd_bus_message *reply,
260 void *userdata,
261 sd_bus_error *error) {
262
263 ExecContext *c = userdata;
264 _cleanup_(cpu_set_reset) CPUSet s = {};
265 _cleanup_free_ uint8_t *array = NULL;
266 size_t allocated;
267
268 assert(bus);
269 assert(reply);
270 assert(c);
271
272 if (c->cpu_affinity_from_numa) {
273 int r;
274
275 r = numa_to_cpu_set(&c->numa_policy, &s);
276 if (r < 0)
277 return r;
278 }
279
280 (void) cpu_set_to_dbus(c->cpu_affinity_from_numa ? &s : &c->cpu_set, &array, &allocated);
281
282 return sd_bus_message_append_array(reply, 'y', array, allocated);
283 }
284
285 static int property_get_numa_mask(
286 sd_bus *bus,
287 const char *path,
288 const char *interface,
289 const char *property,
290 sd_bus_message *reply,
291 void *userdata,
292 sd_bus_error *error) {
293
294 ExecContext *c = userdata;
295 _cleanup_free_ uint8_t *array = NULL;
296 size_t allocated;
297
298 assert(bus);
299 assert(reply);
300 assert(c);
301
302 (void) cpu_set_to_dbus(&c->numa_policy.nodes, &array, &allocated);
303
304 return sd_bus_message_append_array(reply, 'y', array, allocated);
305 }
306
307 static int property_get_numa_policy(
308 sd_bus *bus,
309 const char *path,
310 const char *interface,
311 const char *property,
312 sd_bus_message *reply,
313 void *userdata,
314 sd_bus_error *error) {
315 ExecContext *c = userdata;
316 int32_t policy;
317
318 assert(bus);
319 assert(reply);
320 assert(c);
321
322 policy = numa_policy_get_type(&c->numa_policy);
323
324 return sd_bus_message_append_basic(reply, 'i', &policy);
325 }
326
327 static int property_get_timer_slack_nsec(
328 sd_bus *bus,
329 const char *path,
330 const char *interface,
331 const char *property,
332 sd_bus_message *reply,
333 void *userdata,
334 sd_bus_error *error) {
335
336 ExecContext *c = userdata;
337 uint64_t u;
338
339 assert(bus);
340 assert(reply);
341 assert(c);
342
343 if (c->timer_slack_nsec != NSEC_INFINITY)
344 u = (uint64_t) c->timer_slack_nsec;
345 else
346 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
347
348 return sd_bus_message_append(reply, "t", u);
349 }
350
351 static int property_get_syscall_filter(
352 sd_bus *bus,
353 const char *path,
354 const char *interface,
355 const char *property,
356 sd_bus_message *reply,
357 void *userdata,
358 sd_bus_error *error) {
359
360 ExecContext *c = userdata;
361 _cleanup_strv_free_ char **l = NULL;
362 int r;
363
364 #if HAVE_SECCOMP
365 void *id, *val;
366 #endif
367
368 assert(bus);
369 assert(reply);
370 assert(c);
371
372 r = sd_bus_message_open_container(reply, 'r', "bas");
373 if (r < 0)
374 return r;
375
376 r = sd_bus_message_append(reply, "b", c->syscall_allow_list);
377 if (r < 0)
378 return r;
379
380 #if HAVE_SECCOMP
381 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
382 _cleanup_free_ char *name = NULL;
383 const char *e = NULL;
384 char *s;
385 int num = PTR_TO_INT(val);
386
387 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
388 if (!name)
389 continue;
390
391 if (num >= 0) {
392 e = seccomp_errno_or_action_to_string(num);
393 if (e) {
394 s = strjoin(name, ":", e);
395 if (!s)
396 return -ENOMEM;
397 } else {
398 r = asprintf(&s, "%s:%d", name, num);
399 if (r < 0)
400 return -ENOMEM;
401 }
402 } else
403 s = TAKE_PTR(name);
404
405 r = strv_consume(&l, s);
406 if (r < 0)
407 return r;
408 }
409 #endif
410
411 strv_sort(l);
412
413 r = sd_bus_message_append_strv(reply, l);
414 if (r < 0)
415 return r;
416
417 return sd_bus_message_close_container(reply);
418 }
419
420 static int property_get_syscall_log(
421 sd_bus *bus,
422 const char *path,
423 const char *interface,
424 const char *property,
425 sd_bus_message *reply,
426 void *userdata,
427 sd_bus_error *error) {
428
429 ExecContext *c = userdata;
430 _cleanup_strv_free_ char **l = NULL;
431 int r;
432
433 #if HAVE_SECCOMP
434 void *id, *val;
435 #endif
436
437 assert(bus);
438 assert(reply);
439 assert(c);
440
441 r = sd_bus_message_open_container(reply, 'r', "bas");
442 if (r < 0)
443 return r;
444
445 r = sd_bus_message_append(reply, "b", c->syscall_log_allow_list);
446 if (r < 0)
447 return r;
448
449 #if HAVE_SECCOMP
450 HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
451 char *name = NULL;
452
453 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
454 if (!name)
455 continue;
456
457 r = strv_consume(&l, name);
458 if (r < 0)
459 return r;
460 }
461 #endif
462
463 strv_sort(l);
464
465 r = sd_bus_message_append_strv(reply, l);
466 if (r < 0)
467 return r;
468
469 return sd_bus_message_close_container(reply);
470 }
471
472 static int property_get_syscall_archs(
473 sd_bus *bus,
474 const char *path,
475 const char *interface,
476 const char *property,
477 sd_bus_message *reply,
478 void *userdata,
479 sd_bus_error *error) {
480
481 ExecContext *c = userdata;
482 _cleanup_strv_free_ char **l = NULL;
483 int r;
484
485 #if HAVE_SECCOMP
486 void *id;
487 #endif
488
489 assert(bus);
490 assert(reply);
491 assert(c);
492
493 #if HAVE_SECCOMP
494 SET_FOREACH(id, c->syscall_archs) {
495 const char *name;
496
497 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
498 if (!name)
499 continue;
500
501 r = strv_extend(&l, name);
502 if (r < 0)
503 return -ENOMEM;
504 }
505 #endif
506
507 strv_sort(l);
508
509 r = sd_bus_message_append_strv(reply, l);
510 if (r < 0)
511 return r;
512
513 return 0;
514 }
515
516 static int property_get_selinux_context(
517 sd_bus *bus,
518 const char *path,
519 const char *interface,
520 const char *property,
521 sd_bus_message *reply,
522 void *userdata,
523 sd_bus_error *error) {
524
525 ExecContext *c = userdata;
526
527 assert(bus);
528 assert(reply);
529 assert(c);
530
531 return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context);
532 }
533
534 static int property_get_apparmor_profile(
535 sd_bus *bus,
536 const char *path,
537 const char *interface,
538 const char *property,
539 sd_bus_message *reply,
540 void *userdata,
541 sd_bus_error *error) {
542
543 ExecContext *c = userdata;
544
545 assert(bus);
546 assert(reply);
547 assert(c);
548
549 return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
550 }
551
552 static int property_get_smack_process_label(
553 sd_bus *bus,
554 const char *path,
555 const char *interface,
556 const char *property,
557 sd_bus_message *reply,
558 void *userdata,
559 sd_bus_error *error) {
560
561 ExecContext *c = userdata;
562
563 assert(bus);
564 assert(reply);
565 assert(c);
566
567 return sd_bus_message_append(reply, "(bs)", c->smack_process_label_ignore, c->smack_process_label);
568 }
569
570 static int property_get_address_families(
571 sd_bus *bus,
572 const char *path,
573 const char *interface,
574 const char *property,
575 sd_bus_message *reply,
576 void *userdata,
577 sd_bus_error *error) {
578
579 ExecContext *c = userdata;
580 _cleanup_strv_free_ char **l = NULL;
581 void *af;
582 int r;
583
584 assert(bus);
585 assert(reply);
586 assert(c);
587
588 r = sd_bus_message_open_container(reply, 'r', "bas");
589 if (r < 0)
590 return r;
591
592 r = sd_bus_message_append(reply, "b", c->address_families_allow_list);
593 if (r < 0)
594 return r;
595
596 SET_FOREACH(af, c->address_families) {
597 const char *name;
598
599 name = af_to_name(PTR_TO_INT(af));
600 if (!name)
601 continue;
602
603 r = strv_extend(&l, name);
604 if (r < 0)
605 return -ENOMEM;
606 }
607
608 strv_sort(l);
609
610 r = sd_bus_message_append_strv(reply, l);
611 if (r < 0)
612 return r;
613
614 return sd_bus_message_close_container(reply);
615 }
616
617 static int property_get_working_directory(
618 sd_bus *bus,
619 const char *path,
620 const char *interface,
621 const char *property,
622 sd_bus_message *reply,
623 void *userdata,
624 sd_bus_error *error) {
625
626 ExecContext *c = userdata;
627 const char *wd;
628
629 assert(bus);
630 assert(reply);
631 assert(c);
632
633 if (c->working_directory_home)
634 wd = "~";
635 else
636 wd = c->working_directory;
637
638 if (c->working_directory_missing_ok)
639 wd = strjoina("!", wd);
640
641 return sd_bus_message_append(reply, "s", wd);
642 }
643
644 static int property_get_stdio_fdname(
645 sd_bus *bus,
646 const char *path,
647 const char *interface,
648 const char *property,
649 sd_bus_message *reply,
650 void *userdata,
651 sd_bus_error *error) {
652
653 ExecContext *c = userdata;
654 int fileno;
655
656 assert(bus);
657 assert(c);
658 assert(property);
659 assert(reply);
660
661 if (streq(property, "StandardInputFileDescriptorName"))
662 fileno = STDIN_FILENO;
663 else if (streq(property, "StandardOutputFileDescriptorName"))
664 fileno = STDOUT_FILENO;
665 else {
666 assert(streq(property, "StandardErrorFileDescriptorName"));
667 fileno = STDERR_FILENO;
668 }
669
670 return sd_bus_message_append(reply, "s", exec_context_fdname(c, fileno));
671 }
672
673 static int property_get_input_data(
674 sd_bus *bus,
675 const char *path,
676 const char *interface,
677 const char *property,
678 sd_bus_message *reply,
679 void *userdata,
680 sd_bus_error *error) {
681
682 ExecContext *c = userdata;
683
684 assert(bus);
685 assert(c);
686 assert(property);
687 assert(reply);
688
689 return sd_bus_message_append_array(reply, 'y', c->stdin_data, c->stdin_data_size);
690 }
691
692 static int property_get_bind_paths(
693 sd_bus *bus,
694 const char *path,
695 const char *interface,
696 const char *property,
697 sd_bus_message *reply,
698 void *userdata,
699 sd_bus_error *error) {
700
701 ExecContext *c = userdata;
702 bool ro;
703 int r;
704
705 assert(bus);
706 assert(c);
707 assert(property);
708 assert(reply);
709
710 ro = strstr(property, "ReadOnly");
711
712 r = sd_bus_message_open_container(reply, 'a', "(ssbt)");
713 if (r < 0)
714 return r;
715
716 for (size_t i = 0; i < c->n_bind_mounts; i++) {
717
718 if (ro != c->bind_mounts[i].read_only)
719 continue;
720
721 r = sd_bus_message_append(
722 reply, "(ssbt)",
723 c->bind_mounts[i].source,
724 c->bind_mounts[i].destination,
725 c->bind_mounts[i].ignore_enoent,
726 c->bind_mounts[i].recursive ? (uint64_t) MS_REC : (uint64_t) 0);
727 if (r < 0)
728 return r;
729 }
730
731 return sd_bus_message_close_container(reply);
732 }
733
734 static int property_get_temporary_filesystems(
735 sd_bus *bus,
736 const char *path,
737 const char *interface,
738 const char *property,
739 sd_bus_message *reply,
740 void *userdata,
741 sd_bus_error *error) {
742
743 ExecContext *c = userdata;
744 int r;
745
746 assert(bus);
747 assert(c);
748 assert(property);
749 assert(reply);
750
751 r = sd_bus_message_open_container(reply, 'a', "(ss)");
752 if (r < 0)
753 return r;
754
755 for (unsigned i = 0; i < c->n_temporary_filesystems; i++) {
756 TemporaryFileSystem *t = c->temporary_filesystems + i;
757
758 r = sd_bus_message_append(
759 reply, "(ss)",
760 t->path,
761 t->options);
762 if (r < 0)
763 return r;
764 }
765
766 return sd_bus_message_close_container(reply);
767 }
768
769 static int property_get_log_extra_fields(
770 sd_bus *bus,
771 const char *path,
772 const char *interface,
773 const char *property,
774 sd_bus_message *reply,
775 void *userdata,
776 sd_bus_error *error) {
777
778 ExecContext *c = userdata;
779 int r;
780
781 assert(bus);
782 assert(c);
783 assert(property);
784 assert(reply);
785
786 r = sd_bus_message_open_container(reply, 'a', "ay");
787 if (r < 0)
788 return r;
789
790 for (size_t i = 0; i < c->n_log_extra_fields; i++) {
791 r = sd_bus_message_append_array(reply, 'y', c->log_extra_fields[i].iov_base, c->log_extra_fields[i].iov_len);
792 if (r < 0)
793 return r;
794 }
795
796 return sd_bus_message_close_container(reply);
797 }
798
799 static int property_get_set_credential(
800 sd_bus *bus,
801 const char *path,
802 const char *interface,
803 const char *property,
804 sd_bus_message *reply,
805 void *userdata,
806 sd_bus_error *error) {
807
808 ExecContext *c = userdata;
809 ExecSetCredential *sc;
810 int r;
811
812 assert(bus);
813 assert(c);
814 assert(property);
815 assert(reply);
816
817 r = sd_bus_message_open_container(reply, 'a', "(say)");
818 if (r < 0)
819 return r;
820
821 HASHMAP_FOREACH(sc, c->set_credentials) {
822
823 r = sd_bus_message_open_container(reply, 'r', "say");
824 if (r < 0)
825 return r;
826
827 r = sd_bus_message_append(reply, "s", sc->id);
828 if (r < 0)
829 return r;
830
831 r = sd_bus_message_append_array(reply, 'y', sc->data, sc->size);
832 if (r < 0)
833 return r;
834
835 r = sd_bus_message_close_container(reply);
836 if (r < 0)
837 return r;
838 }
839
840 return sd_bus_message_close_container(reply);
841 }
842
843 static int property_get_load_credential(
844 sd_bus *bus,
845 const char *path,
846 const char *interface,
847 const char *property,
848 sd_bus_message *reply,
849 void *userdata,
850 sd_bus_error *error) {
851
852 ExecContext *c = userdata;
853 char **i, **j;
854 int r;
855
856 assert(bus);
857 assert(c);
858 assert(property);
859 assert(reply);
860
861 r = sd_bus_message_open_container(reply, 'a', "(ss)");
862 if (r < 0)
863 return r;
864
865 STRV_FOREACH_PAIR(i, j, c->load_credentials) {
866 r = sd_bus_message_append(reply, "(ss)", *i, *j);
867 if (r < 0)
868 return r;
869 }
870
871 return sd_bus_message_close_container(reply);
872 }
873
874 static int property_get_root_hash(
875 sd_bus *bus,
876 const char *path,
877 const char *interface,
878 const char *property,
879 sd_bus_message *reply,
880 void *userdata,
881 sd_bus_error *error) {
882
883 ExecContext *c = userdata;
884
885 assert(bus);
886 assert(c);
887 assert(property);
888 assert(reply);
889
890 return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size);
891 }
892
893 static int property_get_root_hash_sig(
894 sd_bus *bus,
895 const char *path,
896 const char *interface,
897 const char *property,
898 sd_bus_message *reply,
899 void *userdata,
900 sd_bus_error *error) {
901
902 ExecContext *c = userdata;
903
904 assert(bus);
905 assert(c);
906 assert(property);
907 assert(reply);
908
909 return sd_bus_message_append_array(reply, 'y', c->root_hash_sig, c->root_hash_sig_size);
910 }
911
912 static int property_get_root_image_options(
913 sd_bus *bus,
914 const char *path,
915 const char *interface,
916 const char *property,
917 sd_bus_message *reply,
918 void *userdata,
919 sd_bus_error *error) {
920
921 ExecContext *c = userdata;
922 MountOptions *m;
923 int r;
924
925 assert(bus);
926 assert(c);
927 assert(property);
928 assert(reply);
929
930 r = sd_bus_message_open_container(reply, 'a', "(ss)");
931 if (r < 0)
932 return r;
933
934 LIST_FOREACH(mount_options, m, c->root_image_options) {
935 r = sd_bus_message_append(reply, "(ss)",
936 partition_designator_to_string(m->partition_designator),
937 m->options);
938 if (r < 0)
939 return r;
940 }
941
942 return sd_bus_message_close_container(reply);
943 }
944
945 static int property_get_mount_images(
946 sd_bus *bus,
947 const char *path,
948 const char *interface,
949 const char *property,
950 sd_bus_message *reply,
951 void *userdata,
952 sd_bus_error *error) {
953
954 ExecContext *c = userdata;
955 int r;
956
957 assert(bus);
958 assert(c);
959 assert(property);
960 assert(reply);
961
962 r = sd_bus_message_open_container(reply, 'a', "(ssba(ss))");
963 if (r < 0)
964 return r;
965
966 for (size_t i = 0; i < c->n_mount_images; i++) {
967 MountOptions *m;
968
969 r = sd_bus_message_open_container(reply, SD_BUS_TYPE_STRUCT, "ssba(ss)");
970 if (r < 0)
971 return r;
972 r = sd_bus_message_append(
973 reply, "ssb",
974 c->mount_images[i].source,
975 c->mount_images[i].destination,
976 c->mount_images[i].ignore_enoent);
977 if (r < 0)
978 return r;
979 r = sd_bus_message_open_container(reply, 'a', "(ss)");
980 if (r < 0)
981 return r;
982 LIST_FOREACH(mount_options, m, c->mount_images[i].mount_options) {
983 r = sd_bus_message_append(reply, "(ss)",
984 partition_designator_to_string(m->partition_designator),
985 m->options);
986 if (r < 0)
987 return r;
988 }
989 r = sd_bus_message_close_container(reply);
990 if (r < 0)
991 return r;
992 r = sd_bus_message_close_container(reply);
993 if (r < 0)
994 return r;
995 }
996
997 return sd_bus_message_close_container(reply);
998 }
999
1000 static int property_get_extension_images(
1001 sd_bus *bus,
1002 const char *path,
1003 const char *interface,
1004 const char *property,
1005 sd_bus_message *reply,
1006 void *userdata,
1007 sd_bus_error *error) {
1008
1009 ExecContext *c = userdata;
1010 int r;
1011
1012 assert(bus);
1013 assert(c);
1014 assert(property);
1015 assert(reply);
1016
1017 r = sd_bus_message_open_container(reply, 'a', "(sba(ss))");
1018 if (r < 0)
1019 return r;
1020
1021 for (size_t i = 0; i < c->n_extension_images; i++) {
1022 MountOptions *m;
1023
1024 r = sd_bus_message_open_container(reply, SD_BUS_TYPE_STRUCT, "sba(ss)");
1025 if (r < 0)
1026 return r;
1027 r = sd_bus_message_append(
1028 reply, "sb",
1029 c->extension_images[i].source,
1030 c->extension_images[i].ignore_enoent);
1031 if (r < 0)
1032 return r;
1033 r = sd_bus_message_open_container(reply, 'a', "(ss)");
1034 if (r < 0)
1035 return r;
1036 LIST_FOREACH(mount_options, m, c->extension_images[i].mount_options) {
1037 r = sd_bus_message_append(reply, "(ss)",
1038 partition_designator_to_string(m->partition_designator),
1039 m->options);
1040 if (r < 0)
1041 return r;
1042 }
1043 r = sd_bus_message_close_container(reply);
1044 if (r < 0)
1045 return r;
1046 r = sd_bus_message_close_container(reply);
1047 if (r < 0)
1048 return r;
1049 }
1050
1051 return sd_bus_message_close_container(reply);
1052 }
1053
1054 const sd_bus_vtable bus_exec_vtable[] = {
1055 SD_BUS_VTABLE_START(0),
1056 SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
1057 SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1058 SD_BUS_PROPERTY("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), SD_BUS_VTABLE_PROPERTY_CONST),
1059 SD_BUS_PROPERTY("UnsetEnvironment", "as", NULL, offsetof(ExecContext, unset_environment), SD_BUS_VTABLE_PROPERTY_CONST),
1060 SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
1061 SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
1062 SD_BUS_PROPERTY("LimitCPUSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
1063 SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
1064 SD_BUS_PROPERTY("LimitFSIZESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
1065 SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
1066 SD_BUS_PROPERTY("LimitDATASoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
1067 SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
1068 SD_BUS_PROPERTY("LimitSTACKSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
1069 SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
1070 SD_BUS_PROPERTY("LimitCORESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
1071 SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
1072 SD_BUS_PROPERTY("LimitRSSSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
1073 SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
1074 SD_BUS_PROPERTY("LimitNOFILESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
1075 SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
1076 SD_BUS_PROPERTY("LimitASSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
1077 SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
1078 SD_BUS_PROPERTY("LimitNPROCSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
1079 SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
1080 SD_BUS_PROPERTY("LimitMEMLOCKSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
1081 SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
1082 SD_BUS_PROPERTY("LimitLOCKSSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
1083 SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
1084 SD_BUS_PROPERTY("LimitSIGPENDINGSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
1085 SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
1086 SD_BUS_PROPERTY("LimitMSGQUEUESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
1087 SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
1088 SD_BUS_PROPERTY("LimitNICESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
1089 SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
1090 SD_BUS_PROPERTY("LimitRTPRIOSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
1091 SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
1092 SD_BUS_PROPERTY("LimitRTTIMESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
1093 SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1094 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
1095 SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
1096 SD_BUS_PROPERTY("RootImageOptions", "a(ss)", property_get_root_image_options, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1097 SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1098 SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
1099 SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1100 SD_BUS_PROPERTY("RootHashSignaturePath", "s", NULL, offsetof(ExecContext, root_hash_sig_path), SD_BUS_VTABLE_PROPERTY_CONST),
1101 SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
1102 SD_BUS_PROPERTY("ExtensionImages", "a(sba(ss))", property_get_extension_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1103 SD_BUS_PROPERTY("MountImages", "a(ssba(ss))", property_get_mount_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1104 SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1105 SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1106 SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1107 SD_BUS_PROPERTY("IOSchedulingClass", "i", property_get_ioprio_class, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1108 SD_BUS_PROPERTY("IOSchedulingPriority", "i", property_get_ioprio_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1109 SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1110 SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1111 SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1112 SD_BUS_PROPERTY("CPUAffinityFromNUMA", "b", property_get_cpu_affinity_from_numa, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1113 SD_BUS_PROPERTY("NUMAPolicy", "i", property_get_numa_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1114 SD_BUS_PROPERTY("NUMAMask", "ay", property_get_numa_mask, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1115 SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1116 SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
1117 SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
1118 SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
1119 SD_BUS_PROPERTY("StandardInputFileDescriptorName", "s", property_get_stdio_fdname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1120 SD_BUS_PROPERTY("StandardInputData", "ay", property_get_input_data, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1121 SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
1122 SD_BUS_PROPERTY("StandardOutputFileDescriptorName", "s", property_get_stdio_fdname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1123 SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
1124 SD_BUS_PROPERTY("StandardErrorFileDescriptorName", "s", property_get_stdio_fdname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1125 SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
1126 SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
1127 SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
1128 SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
1129 SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
1130 SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
1131 SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
1132 SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
1133 SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
1134 SD_BUS_PROPERTY("LogLevelMax", "i", bus_property_get_int, offsetof(ExecContext, log_level_max), SD_BUS_VTABLE_PROPERTY_CONST),
1135 SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_ratelimit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST),
1136 SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_ratelimit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
1137 SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1138 SD_BUS_PROPERTY("LogNamespace", "s", NULL, offsetof(ExecContext, log_namespace), SD_BUS_VTABLE_PROPERTY_CONST),
1139 SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
1140 SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST),
1141 SD_BUS_PROPERTY("AmbientCapabilities", "t", NULL, offsetof(ExecContext, capability_ambient_set), SD_BUS_VTABLE_PROPERTY_CONST),
1142 SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
1143 SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
1144 SD_BUS_PROPERTY("DynamicUser", "b", bus_property_get_bool, offsetof(ExecContext, dynamic_user), SD_BUS_VTABLE_PROPERTY_CONST),
1145 SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(ExecContext, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
1146 SD_BUS_PROPERTY("SetCredential", "a(say)", property_get_set_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1147 SD_BUS_PROPERTY("LoadCredential", "a(ss)", property_get_load_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1148 SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
1149 SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
1150 SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1151 SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1152 SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1153 SD_BUS_PROPERTY("ExecPaths", "as", NULL, offsetof(ExecContext, exec_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1154 SD_BUS_PROPERTY("NoExecPaths", "as", NULL, offsetof(ExecContext, no_exec_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1155 SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
1156 SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
1157 SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
1158 SD_BUS_PROPERTY("ProtectClock", "b", bus_property_get_bool, offsetof(ExecContext, protect_clock), SD_BUS_VTABLE_PROPERTY_CONST),
1159 SD_BUS_PROPERTY("ProtectKernelTunables", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_tunables), SD_BUS_VTABLE_PROPERTY_CONST),
1160 SD_BUS_PROPERTY("ProtectKernelModules", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_modules), SD_BUS_VTABLE_PROPERTY_CONST),
1161 SD_BUS_PROPERTY("ProtectKernelLogs", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_logs), SD_BUS_VTABLE_PROPERTY_CONST),
1162 SD_BUS_PROPERTY("ProtectControlGroups", "b", bus_property_get_bool, offsetof(ExecContext, protect_control_groups), SD_BUS_VTABLE_PROPERTY_CONST),
1163 SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
1164 SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST),
1165 SD_BUS_PROPERTY("PrivateMounts", "b", bus_property_get_bool, offsetof(ExecContext, private_mounts), SD_BUS_VTABLE_PROPERTY_CONST),
1166 SD_BUS_PROPERTY("PrivateIPC", "b", bus_property_get_bool, offsetof(ExecContext, private_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
1167 SD_BUS_PROPERTY("ProtectHome", "s", property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
1168 SD_BUS_PROPERTY("ProtectSystem", "s", property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
1169 SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
1170 SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
1171 SD_BUS_PROPERTY("UtmpMode", "s", property_get_exec_utmp_mode, offsetof(ExecContext, utmp_mode), SD_BUS_VTABLE_PROPERTY_CONST),
1172 SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1173 SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1174 SD_BUS_PROPERTY("SmackProcessLabel", "(bs)", property_get_smack_process_label, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1175 SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
1176 SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
1177 SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1178 SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1179 SD_BUS_PROPERTY("SystemCallErrorNumber", "i", bus_property_get_int, offsetof(ExecContext, syscall_errno), SD_BUS_VTABLE_PROPERTY_CONST),
1180 SD_BUS_PROPERTY("SystemCallLog", "(bas)", property_get_syscall_log, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1181 SD_BUS_PROPERTY("Personality", "s", property_get_personality, offsetof(ExecContext, personality), SD_BUS_VTABLE_PROPERTY_CONST),
1182 SD_BUS_PROPERTY("LockPersonality", "b", bus_property_get_bool, offsetof(ExecContext, lock_personality), SD_BUS_VTABLE_PROPERTY_CONST),
1183 SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1184 SD_BUS_PROPERTY("RuntimeDirectoryPreserve", "s", property_get_exec_preserve_mode, offsetof(ExecContext, runtime_directory_preserve_mode), SD_BUS_VTABLE_PROPERTY_CONST),
1185 SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1186 SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].paths), SD_BUS_VTABLE_PROPERTY_CONST),
1187 SD_BUS_PROPERTY("StateDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1188 SD_BUS_PROPERTY("StateDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].paths), SD_BUS_VTABLE_PROPERTY_CONST),
1189 SD_BUS_PROPERTY("CacheDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1190 SD_BUS_PROPERTY("CacheDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].paths), SD_BUS_VTABLE_PROPERTY_CONST),
1191 SD_BUS_PROPERTY("LogsDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1192 SD_BUS_PROPERTY("LogsDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].paths), SD_BUS_VTABLE_PROPERTY_CONST),
1193 SD_BUS_PROPERTY("ConfigurationDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1194 SD_BUS_PROPERTY("ConfigurationDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].paths), SD_BUS_VTABLE_PROPERTY_CONST),
1195 SD_BUS_PROPERTY("TimeoutCleanUSec", "t", bus_property_get_usec, offsetof(ExecContext, timeout_clean_usec), SD_BUS_VTABLE_PROPERTY_CONST),
1196 SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
1197 SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
1198 SD_BUS_PROPERTY("RestrictSUIDSGID", "b", bus_property_get_bool, offsetof(ExecContext, restrict_suid_sgid), SD_BUS_VTABLE_PROPERTY_CONST),
1199 SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
1200 SD_BUS_PROPERTY("BindPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1201 SD_BUS_PROPERTY("BindReadOnlyPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1202 SD_BUS_PROPERTY("TemporaryFileSystem", "a(ss)", property_get_temporary_filesystems, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1203 SD_BUS_PROPERTY("MountAPIVFS", "b", property_get_mount_apivfs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1204 SD_BUS_PROPERTY("KeyringMode", "s", property_get_exec_keyring_mode, offsetof(ExecContext, keyring_mode), SD_BUS_VTABLE_PROPERTY_CONST),
1205 SD_BUS_PROPERTY("ProtectProc", "s", property_get_protect_proc, offsetof(ExecContext, protect_proc), SD_BUS_VTABLE_PROPERTY_CONST),
1206 SD_BUS_PROPERTY("ProcSubset", "s", property_get_proc_subset, offsetof(ExecContext, proc_subset), SD_BUS_VTABLE_PROPERTY_CONST),
1207 SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST),
1208 SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
1209 SD_BUS_PROPERTY("IPCNamespacePath", "s", NULL, offsetof(ExecContext, ipc_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
1210
1211 /* Obsolete/redundant properties: */
1212 SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1213 SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1214 SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1215 SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1216 SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1217
1218 SD_BUS_VTABLE_END
1219 };
1220
1221 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
1222 int r;
1223
1224 assert(reply);
1225 assert(c);
1226
1227 if (!c->path)
1228 return 0;
1229
1230 r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
1231 if (r < 0)
1232 return r;
1233
1234 r = sd_bus_message_append(reply, "s", c->path);
1235 if (r < 0)
1236 return r;
1237
1238 r = sd_bus_message_append_strv(reply, c->argv);
1239 if (r < 0)
1240 return r;
1241
1242 r = sd_bus_message_append(reply, "bttttuii",
1243 !!(c->flags & EXEC_COMMAND_IGNORE_FAILURE),
1244 c->exec_status.start_timestamp.realtime,
1245 c->exec_status.start_timestamp.monotonic,
1246 c->exec_status.exit_timestamp.realtime,
1247 c->exec_status.exit_timestamp.monotonic,
1248 (uint32_t) c->exec_status.pid,
1249 (int32_t) c->exec_status.code,
1250 (int32_t) c->exec_status.status);
1251 if (r < 0)
1252 return r;
1253
1254 return sd_bus_message_close_container(reply);
1255 }
1256
1257 static int append_exec_ex_command(sd_bus_message *reply, ExecCommand *c) {
1258 _cleanup_strv_free_ char **ex_opts = NULL;
1259 int r;
1260
1261 assert(reply);
1262 assert(c);
1263
1264 if (!c->path)
1265 return 0;
1266
1267 r = sd_bus_message_open_container(reply, 'r', "sasasttttuii");
1268 if (r < 0)
1269 return r;
1270
1271 r = sd_bus_message_append(reply, "s", c->path);
1272 if (r < 0)
1273 return r;
1274
1275 r = sd_bus_message_append_strv(reply, c->argv);
1276 if (r < 0)
1277 return r;
1278
1279 r = exec_command_flags_to_strv(c->flags, &ex_opts);
1280 if (r < 0)
1281 return r;
1282
1283 r = sd_bus_message_append_strv(reply, ex_opts);
1284 if (r < 0)
1285 return r;
1286
1287 r = sd_bus_message_append(reply, "ttttuii",
1288 c->exec_status.start_timestamp.realtime,
1289 c->exec_status.start_timestamp.monotonic,
1290 c->exec_status.exit_timestamp.realtime,
1291 c->exec_status.exit_timestamp.monotonic,
1292 (uint32_t) c->exec_status.pid,
1293 (int32_t) c->exec_status.code,
1294 (int32_t) c->exec_status.status);
1295 if (r < 0)
1296 return r;
1297
1298 return sd_bus_message_close_container(reply);
1299 }
1300
1301 int bus_property_get_exec_command(
1302 sd_bus *bus,
1303 const char *path,
1304 const char *interface,
1305 const char *property,
1306 sd_bus_message *reply,
1307 void *userdata,
1308 sd_bus_error *ret_error) {
1309
1310 ExecCommand *c = (ExecCommand*) userdata;
1311 int r;
1312
1313 assert(bus);
1314 assert(reply);
1315
1316 r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
1317 if (r < 0)
1318 return r;
1319
1320 r = append_exec_command(reply, c);
1321 if (r < 0)
1322 return r;
1323
1324 return sd_bus_message_close_container(reply);
1325 }
1326
1327 int bus_property_get_exec_command_list(
1328 sd_bus *bus,
1329 const char *path,
1330 const char *interface,
1331 const char *property,
1332 sd_bus_message *reply,
1333 void *userdata,
1334 sd_bus_error *ret_error) {
1335
1336 ExecCommand *c = *(ExecCommand**) userdata;
1337 int r;
1338
1339 assert(bus);
1340 assert(reply);
1341
1342 r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
1343 if (r < 0)
1344 return r;
1345
1346 LIST_FOREACH(command, c, c) {
1347 r = append_exec_command(reply, c);
1348 if (r < 0)
1349 return r;
1350 }
1351
1352 return sd_bus_message_close_container(reply);
1353 }
1354
1355 int bus_property_get_exec_ex_command_list(
1356 sd_bus *bus,
1357 const char *path,
1358 const char *interface,
1359 const char *property,
1360 sd_bus_message *reply,
1361 void *userdata,
1362 sd_bus_error *ret_error) {
1363
1364 ExecCommand *c, *exec_command = *(ExecCommand**) userdata;
1365 int r;
1366
1367 assert(bus);
1368 assert(reply);
1369
1370 r = sd_bus_message_open_container(reply, 'a', "(sasasttttuii)");
1371 if (r < 0)
1372 return r;
1373
1374 LIST_FOREACH(command, c, exec_command) {
1375 r = append_exec_ex_command(reply, c);
1376 if (r < 0)
1377 return r;
1378 }
1379
1380 return sd_bus_message_close_container(reply);
1381 }
1382
1383 static char *exec_command_flags_to_exec_chars(ExecCommandFlags flags) {
1384 return strjoin(FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE) ? "-" : "",
1385 FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND) ? ":" : "",
1386 FLAGS_SET(flags, EXEC_COMMAND_FULLY_PRIVILEGED) ? "+" : "",
1387 FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID) ? "!" : "",
1388 FLAGS_SET(flags, EXEC_COMMAND_AMBIENT_MAGIC) ? "!!" : "");
1389 }
1390
1391 int bus_set_transient_exec_command(
1392 Unit *u,
1393 const char *name,
1394 ExecCommand **exec_command,
1395 sd_bus_message *message,
1396 UnitWriteFlags flags,
1397 sd_bus_error *error) {
1398 bool is_ex_prop = endswith(name, "Ex");
1399 unsigned n = 0;
1400 int r;
1401
1402 r = sd_bus_message_enter_container(message, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
1403 if (r < 0)
1404 return r;
1405
1406 while ((r = sd_bus_message_enter_container(message, 'r', is_ex_prop ? "sasas" : "sasb")) > 0) {
1407 _cleanup_strv_free_ char **argv = NULL, **ex_opts = NULL;
1408 const char *path;
1409 int b;
1410
1411 r = sd_bus_message_read(message, "s", &path);
1412 if (r < 0)
1413 return r;
1414
1415 if (!path_is_absolute(path) && !filename_is_valid(path))
1416 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
1417 "\"%s\" is neither a valid executable name nor an absolute path",
1418 path);
1419
1420 r = sd_bus_message_read_strv(message, &argv);
1421 if (r < 0)
1422 return r;
1423
1424 r = is_ex_prop ? sd_bus_message_read_strv(message, &ex_opts) : sd_bus_message_read(message, "b", &b);
1425 if (r < 0)
1426 return r;
1427
1428 r = sd_bus_message_exit_container(message);
1429 if (r < 0)
1430 return r;
1431
1432 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1433 ExecCommand *c;
1434
1435 c = new0(ExecCommand, 1);
1436 if (!c)
1437 return -ENOMEM;
1438
1439 c->path = strdup(path);
1440 if (!c->path) {
1441 free(c);
1442 return -ENOMEM;
1443 }
1444
1445 c->argv = TAKE_PTR(argv);
1446
1447 if (is_ex_prop) {
1448 r = exec_command_flags_from_strv(ex_opts, &c->flags);
1449 if (r < 0)
1450 return r;
1451 } else
1452 c->flags = b ? EXEC_COMMAND_IGNORE_FAILURE : 0;
1453
1454 path_simplify(c->path, false);
1455 exec_command_append_list(exec_command, c);
1456 }
1457
1458 n++;
1459 }
1460 if (r < 0)
1461 return r;
1462
1463 r = sd_bus_message_exit_container(message);
1464 if (r < 0)
1465 return r;
1466
1467 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1468 _cleanup_free_ char *buf = NULL;
1469 _cleanup_fclose_ FILE *f = NULL;
1470 ExecCommand *c;
1471 size_t size = 0;
1472
1473 if (n == 0)
1474 *exec_command = exec_command_free_list(*exec_command);
1475
1476 f = open_memstream_unlocked(&buf, &size);
1477 if (!f)
1478 return -ENOMEM;
1479
1480 fprintf(f, "%s=\n", name);
1481
1482 LIST_FOREACH(command, c, *exec_command) {
1483 _cleanup_free_ char *a = NULL, *exec_chars = NULL;
1484
1485 exec_chars = exec_command_flags_to_exec_chars(c->flags);
1486 if (!exec_chars)
1487 return -ENOMEM;
1488
1489 a = unit_concat_strv(c->argv, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS);
1490 if (!a)
1491 return -ENOMEM;
1492
1493 if (streq_ptr(c->path, c->argv ? c->argv[0] : NULL))
1494 fprintf(f, "%s=%s%s\n", name, exec_chars, a);
1495 else {
1496 _cleanup_free_ char *t = NULL;
1497 const char *p;
1498
1499 p = unit_escape_setting(c->path, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS, &t);
1500 if (!p)
1501 return -ENOMEM;
1502
1503 fprintf(f, "%s=%s@%s %s\n", name, exec_chars, p, a);
1504 }
1505 }
1506
1507 r = fflush_and_check(f);
1508 if (r < 0)
1509 return r;
1510
1511 unit_write_setting(u, flags, name, buf);
1512 }
1513
1514 return 1;
1515 }
1516
1517 static int parse_personality(const char *s, unsigned long *p) {
1518 unsigned long v;
1519
1520 assert(p);
1521
1522 v = personality_from_string(s);
1523 if (v == PERSONALITY_INVALID)
1524 return -EINVAL;
1525
1526 *p = v;
1527 return 0;
1528 }
1529
1530 static const char* mount_propagation_flags_to_string_with_check(unsigned long n) {
1531 if (!IN_SET(n, 0, MS_SHARED, MS_PRIVATE, MS_SLAVE))
1532 return NULL;
1533
1534 return mount_propagation_flags_to_string(n);
1535 }
1536
1537 static BUS_DEFINE_SET_TRANSIENT(nsec, "t", uint64_t, nsec_t, NSEC_FMT);
1538 static BUS_DEFINE_SET_TRANSIENT_IS_VALID(log_level, "i", int32_t, int, "%" PRIi32, log_level_is_valid);
1539 #if HAVE_SECCOMP
1540 static BUS_DEFINE_SET_TRANSIENT_IS_VALID(errno, "i", int32_t, int, "%" PRIi32, seccomp_errno_or_action_is_valid);
1541 #endif
1542 static BUS_DEFINE_SET_TRANSIENT_PARSE(std_input, ExecInput, exec_input_from_string);
1543 static BUS_DEFINE_SET_TRANSIENT_PARSE(std_output, ExecOutput, exec_output_from_string);
1544 static BUS_DEFINE_SET_TRANSIENT_PARSE(utmp_mode, ExecUtmpMode, exec_utmp_mode_from_string);
1545 static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_system, ProtectSystem, protect_system_from_string);
1546 static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_home, ProtectHome, protect_home_from_string);
1547 static BUS_DEFINE_SET_TRANSIENT_PARSE(keyring_mode, ExecKeyringMode, exec_keyring_mode_from_string);
1548 static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_proc, ProtectProc, protect_proc_from_string);
1549 static BUS_DEFINE_SET_TRANSIENT_PARSE(proc_subset, ProcSubset, proc_subset_from_string);
1550 static BUS_DEFINE_SET_TRANSIENT_PARSE(preserve_mode, ExecPreserveMode, exec_preserve_mode_from_string);
1551 static BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(personality, unsigned long, parse_personality);
1552 static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(secure_bits, "i", int32_t, int, "%" PRIi32, secure_bits_to_string_alloc_with_check);
1553 static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(capability, "t", uint64_t, uint64_t, "%" PRIu64, capability_set_to_string_alloc);
1554 static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flags_to_string);
1555 static BUS_DEFINE_SET_TRANSIENT_TO_STRING(mount_flags, "t", uint64_t, unsigned long, "%" PRIu64, mount_propagation_flags_to_string_with_check);
1556
1557 int bus_exec_context_set_transient_property(
1558 Unit *u,
1559 ExecContext *c,
1560 const char *name,
1561 sd_bus_message *message,
1562 UnitWriteFlags flags,
1563 sd_bus_error *error) {
1564
1565 const char *suffix;
1566 int r;
1567
1568 assert(u);
1569 assert(c);
1570 assert(name);
1571 assert(message);
1572
1573 flags |= UNIT_PRIVATE;
1574
1575 if (streq(name, "User"))
1576 return bus_set_transient_user_relaxed(u, name, &c->user, message, flags, error);
1577
1578 if (streq(name, "Group"))
1579 return bus_set_transient_user_relaxed(u, name, &c->group, message, flags, error);
1580
1581 if (streq(name, "TTYPath"))
1582 return bus_set_transient_path(u, name, &c->tty_path, message, flags, error);
1583
1584 if (streq(name, "RootImage"))
1585 return bus_set_transient_path(u, name, &c->root_image, message, flags, error);
1586
1587 if (streq(name, "RootImageOptions")) {
1588 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
1589 _cleanup_free_ char *format_str = NULL;
1590
1591 r = bus_read_mount_options(message, error, &options, &format_str, " ");
1592 if (r < 0)
1593 return r;
1594
1595 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1596 if (LIST_IS_EMPTY(options)) {
1597 c->root_image_options = mount_options_free_all(c->root_image_options);
1598 unit_write_settingf(u, flags, name, "%s=", name);
1599 } else {
1600 LIST_JOIN(mount_options, c->root_image_options, options);
1601 unit_write_settingf(
1602 u, flags|UNIT_ESCAPE_SPECIFIERS, name,
1603 "%s=%s",
1604 name,
1605 format_str);
1606 }
1607 }
1608
1609 return 1;
1610 }
1611
1612 if (streq(name, "RootHash")) {
1613 const void *roothash_decoded;
1614 size_t roothash_decoded_size;
1615
1616 r = sd_bus_message_read_array(message, 'y', &roothash_decoded, &roothash_decoded_size);
1617 if (r < 0)
1618 return r;
1619
1620 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1621 _cleanup_free_ char *encoded = NULL;
1622
1623 if (roothash_decoded_size == 0) {
1624 c->root_hash_path = mfree(c->root_hash_path);
1625 c->root_hash = mfree(c->root_hash);
1626 c->root_hash_size = 0;
1627
1628 unit_write_settingf(u, flags, name, "RootHash=");
1629 } else {
1630 _cleanup_free_ void *p;
1631
1632 encoded = hexmem(roothash_decoded, roothash_decoded_size);
1633 if (!encoded)
1634 return -ENOMEM;
1635
1636 p = memdup(roothash_decoded, roothash_decoded_size);
1637 if (!p)
1638 return -ENOMEM;
1639
1640 free_and_replace(c->root_hash, p);
1641 c->root_hash_size = roothash_decoded_size;
1642 c->root_hash_path = mfree(c->root_hash_path);
1643
1644 unit_write_settingf(u, flags, name, "RootHash=%s", encoded);
1645 }
1646 }
1647
1648 return 1;
1649 }
1650
1651 if (streq(name, "RootHashPath")) {
1652 c->root_hash_size = 0;
1653 c->root_hash = mfree(c->root_hash);
1654
1655 return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
1656 }
1657
1658 if (streq(name, "RootHashSignature")) {
1659 const void *roothash_sig_decoded;
1660 size_t roothash_sig_decoded_size;
1661
1662 r = sd_bus_message_read_array(message, 'y', &roothash_sig_decoded, &roothash_sig_decoded_size);
1663 if (r < 0)
1664 return r;
1665
1666 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1667 _cleanup_free_ char *encoded = NULL;
1668
1669 if (roothash_sig_decoded_size == 0) {
1670 c->root_hash_sig_path = mfree(c->root_hash_sig_path);
1671 c->root_hash_sig = mfree(c->root_hash_sig);
1672 c->root_hash_sig_size = 0;
1673
1674 unit_write_settingf(u, flags, name, "RootHashSignature=");
1675 } else {
1676 _cleanup_free_ void *p;
1677 ssize_t len;
1678
1679 len = base64mem(roothash_sig_decoded, roothash_sig_decoded_size, &encoded);
1680 if (len < 0)
1681 return -ENOMEM;
1682
1683 p = memdup(roothash_sig_decoded, roothash_sig_decoded_size);
1684 if (!p)
1685 return -ENOMEM;
1686
1687 free_and_replace(c->root_hash_sig, p);
1688 c->root_hash_sig_size = roothash_sig_decoded_size;
1689 c->root_hash_sig_path = mfree(c->root_hash_sig_path);
1690
1691 unit_write_settingf(u, flags, name, "RootHashSignature=base64:%s", encoded);
1692 }
1693 }
1694
1695 return 1;
1696 }
1697
1698 if (streq(name, "RootHashSignaturePath")) {
1699 c->root_hash_sig_size = 0;
1700 c->root_hash_sig = mfree(c->root_hash_sig);
1701
1702 return bus_set_transient_path(u, "RootHashSignature", &c->root_hash_sig_path, message, flags, error);
1703 }
1704
1705 if (streq(name, "RootVerity"))
1706 return bus_set_transient_path(u, name, &c->root_verity, message, flags, error);
1707
1708 if (streq(name, "RootDirectory"))
1709 return bus_set_transient_path(u, name, &c->root_directory, message, flags, error);
1710
1711 if (streq(name, "SyslogIdentifier"))
1712 return bus_set_transient_string(u, name, &c->syslog_identifier, message, flags, error);
1713
1714 if (streq(name, "LogLevelMax"))
1715 return bus_set_transient_log_level(u, name, &c->log_level_max, message, flags, error);
1716
1717 if (streq(name, "LogRateLimitIntervalUSec"))
1718 return bus_set_transient_usec(u, name, &c->log_ratelimit_interval_usec, message, flags, error);
1719
1720 if (streq(name, "LogRateLimitBurst"))
1721 return bus_set_transient_unsigned(u, name, &c->log_ratelimit_burst, message, flags, error);
1722
1723 if (streq(name, "Personality"))
1724 return bus_set_transient_personality(u, name, &c->personality, message, flags, error);
1725
1726 if (streq(name, "StandardInput"))
1727 return bus_set_transient_std_input(u, name, &c->std_input, message, flags, error);
1728
1729 if (streq(name, "StandardOutput"))
1730 return bus_set_transient_std_output(u, name, &c->std_output, message, flags, error);
1731
1732 if (streq(name, "StandardError"))
1733 return bus_set_transient_std_output(u, name, &c->std_error, message, flags, error);
1734
1735 if (streq(name, "IgnoreSIGPIPE"))
1736 return bus_set_transient_bool(u, name, &c->ignore_sigpipe, message, flags, error);
1737
1738 if (streq(name, "TTYVHangup"))
1739 return bus_set_transient_bool(u, name, &c->tty_vhangup, message, flags, error);
1740
1741 if (streq(name, "TTYReset"))
1742 return bus_set_transient_bool(u, name, &c->tty_reset, message, flags, error);
1743
1744 if (streq(name, "TTYVTDisallocate"))
1745 return bus_set_transient_bool(u, name, &c->tty_vt_disallocate, message, flags, error);
1746
1747 if (streq(name, "PrivateTmp"))
1748 return bus_set_transient_bool(u, name, &c->private_tmp, message, flags, error);
1749
1750 if (streq(name, "PrivateDevices"))
1751 return bus_set_transient_bool(u, name, &c->private_devices, message, flags, error);
1752
1753 if (streq(name, "PrivateMounts"))
1754 return bus_set_transient_bool(u, name, &c->private_mounts, message, flags, error);
1755
1756 if (streq(name, "PrivateNetwork"))
1757 return bus_set_transient_bool(u, name, &c->private_network, message, flags, error);
1758
1759 if (streq(name, "PrivateIPC"))
1760 return bus_set_transient_bool(u, name, &c->private_ipc, message, flags, error);
1761
1762 if (streq(name, "PrivateUsers"))
1763 return bus_set_transient_bool(u, name, &c->private_users, message, flags, error);
1764
1765 if (streq(name, "NoNewPrivileges"))
1766 return bus_set_transient_bool(u, name, &c->no_new_privileges, message, flags, error);
1767
1768 if (streq(name, "SyslogLevelPrefix"))
1769 return bus_set_transient_bool(u, name, &c->syslog_level_prefix, message, flags, error);
1770
1771 if (streq(name, "MemoryDenyWriteExecute"))
1772 return bus_set_transient_bool(u, name, &c->memory_deny_write_execute, message, flags, error);
1773
1774 if (streq(name, "RestrictRealtime"))
1775 return bus_set_transient_bool(u, name, &c->restrict_realtime, message, flags, error);
1776
1777 if (streq(name, "RestrictSUIDSGID"))
1778 return bus_set_transient_bool(u, name, &c->restrict_suid_sgid, message, flags, error);
1779
1780 if (streq(name, "DynamicUser"))
1781 return bus_set_transient_bool(u, name, &c->dynamic_user, message, flags, error);
1782
1783 if (streq(name, "RemoveIPC"))
1784 return bus_set_transient_bool(u, name, &c->remove_ipc, message, flags, error);
1785
1786 if (streq(name, "ProtectKernelTunables"))
1787 return bus_set_transient_bool(u, name, &c->protect_kernel_tunables, message, flags, error);
1788
1789 if (streq(name, "ProtectKernelModules"))
1790 return bus_set_transient_bool(u, name, &c->protect_kernel_modules, message, flags, error);
1791
1792 if (streq(name, "ProtectKernelLogs"))
1793 return bus_set_transient_bool(u, name, &c->protect_kernel_logs, message, flags, error);
1794
1795 if (streq(name, "ProtectClock"))
1796 return bus_set_transient_bool(u, name, &c->protect_clock, message, flags, error);
1797
1798 if (streq(name, "ProtectControlGroups"))
1799 return bus_set_transient_bool(u, name, &c->protect_control_groups, message, flags, error);
1800
1801 if (streq(name, "CPUSchedulingResetOnFork"))
1802 return bus_set_transient_bool(u, name, &c->cpu_sched_reset_on_fork, message, flags, error);
1803
1804 if (streq(name, "NonBlocking"))
1805 return bus_set_transient_bool(u, name, &c->non_blocking, message, flags, error);
1806
1807 if (streq(name, "LockPersonality"))
1808 return bus_set_transient_bool(u, name, &c->lock_personality, message, flags, error);
1809
1810 if (streq(name, "ProtectHostname"))
1811 return bus_set_transient_bool(u, name, &c->protect_hostname, message, flags, error);
1812
1813 if (streq(name, "UtmpIdentifier"))
1814 return bus_set_transient_string(u, name, &c->utmp_id, message, flags, error);
1815
1816 if (streq(name, "UtmpMode"))
1817 return bus_set_transient_utmp_mode(u, name, &c->utmp_mode, message, flags, error);
1818
1819 if (streq(name, "PAMName"))
1820 return bus_set_transient_string(u, name, &c->pam_name, message, flags, error);
1821
1822 if (streq(name, "TimerSlackNSec"))
1823 return bus_set_transient_nsec(u, name, &c->timer_slack_nsec, message, flags, error);
1824
1825 if (streq(name, "ProtectSystem"))
1826 return bus_set_transient_protect_system(u, name, &c->protect_system, message, flags, error);
1827
1828 if (streq(name, "ProtectHome"))
1829 return bus_set_transient_protect_home(u, name, &c->protect_home, message, flags, error);
1830
1831 if (streq(name, "KeyringMode"))
1832 return bus_set_transient_keyring_mode(u, name, &c->keyring_mode, message, flags, error);
1833
1834 if (streq(name, "ProtectProc"))
1835 return bus_set_transient_protect_proc(u, name, &c->protect_proc, message, flags, error);
1836
1837 if (streq(name, "ProcSubset"))
1838 return bus_set_transient_proc_subset(u, name, &c->proc_subset, message, flags, error);
1839
1840 if (streq(name, "RuntimeDirectoryPreserve"))
1841 return bus_set_transient_preserve_mode(u, name, &c->runtime_directory_preserve_mode, message, flags, error);
1842
1843 if (streq(name, "UMask"))
1844 return bus_set_transient_mode_t(u, name, &c->umask, message, flags, error);
1845
1846 if (streq(name, "RuntimeDirectoryMode"))
1847 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_RUNTIME].mode, message, flags, error);
1848
1849 if (streq(name, "StateDirectoryMode"))
1850 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_STATE].mode, message, flags, error);
1851
1852 if (streq(name, "CacheDirectoryMode"))
1853 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_CACHE].mode, message, flags, error);
1854
1855 if (streq(name, "LogsDirectoryMode"))
1856 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_LOGS].mode, message, flags, error);
1857
1858 if (streq(name, "ConfigurationDirectoryMode"))
1859 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_CONFIGURATION].mode, message, flags, error);
1860
1861 if (streq(name, "SELinuxContext"))
1862 return bus_set_transient_string(u, name, &c->selinux_context, message, flags, error);
1863
1864 if (streq(name, "SecureBits"))
1865 return bus_set_transient_secure_bits(u, name, &c->secure_bits, message, flags, error);
1866
1867 if (streq(name, "CapabilityBoundingSet"))
1868 return bus_set_transient_capability(u, name, &c->capability_bounding_set, message, flags, error);
1869
1870 if (streq(name, "AmbientCapabilities"))
1871 return bus_set_transient_capability(u, name, &c->capability_ambient_set, message, flags, error);
1872
1873 if (streq(name, "RestrictNamespaces"))
1874 return bus_set_transient_namespace_flag(u, name, &c->restrict_namespaces, message, flags, error);
1875
1876 if (streq(name, "MountFlags"))
1877 return bus_set_transient_mount_flags(u, name, &c->mount_flags, message, flags, error);
1878
1879 if (streq(name, "NetworkNamespacePath"))
1880 return bus_set_transient_path(u, name, &c->network_namespace_path, message, flags, error);
1881
1882 if (streq(name, "IPCNamespacePath"))
1883 return bus_set_transient_path(u, name, &c->ipc_namespace_path, message, flags, error);
1884
1885 if (streq(name, "SupplementaryGroups")) {
1886 _cleanup_strv_free_ char **l = NULL;
1887 char **p;
1888
1889 r = sd_bus_message_read_strv(message, &l);
1890 if (r < 0)
1891 return r;
1892
1893 STRV_FOREACH(p, l)
1894 if (!isempty(*p) && !valid_user_group_name(*p, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN))
1895 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
1896 "Invalid supplementary group names");
1897
1898 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1899 if (strv_isempty(l)) {
1900 c->supplementary_groups = strv_free(c->supplementary_groups);
1901 unit_write_settingf(u, flags, name, "%s=", name);
1902 } else {
1903 _cleanup_free_ char *joined = NULL;
1904
1905 r = strv_extend_strv(&c->supplementary_groups, l, true);
1906 if (r < 0)
1907 return -ENOMEM;
1908
1909 joined = strv_join(c->supplementary_groups, " ");
1910 if (!joined)
1911 return -ENOMEM;
1912
1913 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, joined);
1914 }
1915 }
1916
1917 return 1;
1918
1919 } else if (streq(name, "SetCredential")) {
1920 bool isempty = true;
1921
1922 r = sd_bus_message_enter_container(message, 'a', "(say)");
1923 if (r < 0)
1924 return r;
1925
1926 for (;;) {
1927 const char *id;
1928 const void *p;
1929 size_t sz;
1930
1931 r = sd_bus_message_enter_container(message, 'r', "say");
1932 if (r < 0)
1933 return r;
1934 if (r == 0)
1935 break;
1936
1937 r = sd_bus_message_read(message, "s", &id);
1938 if (r < 0)
1939 return r;
1940
1941 r = sd_bus_message_read_array(message, 'y', &p, &sz);
1942 if (r < 0)
1943 return r;
1944
1945 r = sd_bus_message_exit_container(message);
1946 if (r < 0)
1947 return r;
1948
1949 if (!credential_name_valid(id))
1950 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential ID is invalid: %s", id);
1951
1952 isempty = false;
1953
1954 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1955 _cleanup_free_ char *a = NULL, *b = NULL;
1956 _cleanup_free_ void *copy = NULL;
1957 ExecSetCredential *old;
1958
1959 copy = memdup(p, sz);
1960 if (!copy)
1961 return -ENOMEM;
1962
1963 old = hashmap_get(c->set_credentials, id);
1964 if (old) {
1965 free_and_replace(old->data, copy);
1966 old->size = sz;
1967 } else {
1968 _cleanup_(exec_set_credential_freep) ExecSetCredential *sc = NULL;
1969
1970 sc = new0(ExecSetCredential, 1);
1971 if (!sc)
1972 return -ENOMEM;
1973
1974 sc->id = strdup(id);
1975 if (!sc->id)
1976 return -ENOMEM;
1977
1978 sc->data = TAKE_PTR(copy);
1979 sc->size = sz;
1980
1981 r = hashmap_ensure_put(&c->set_credentials, &exec_set_credential_hash_ops, sc->id, sc);
1982 if (r < 0)
1983 return r;
1984
1985 TAKE_PTR(sc);
1986 }
1987
1988 a = specifier_escape(id);
1989 if (!a)
1990 return -ENOMEM;
1991
1992 b = cescape_length(p, sz);
1993 if (!b)
1994 return -ENOMEM;
1995
1996 (void) unit_write_settingf(u, flags, name, "%s=%s:%s", name, a, b);
1997 }
1998 }
1999
2000 r = sd_bus_message_exit_container(message);
2001 if (r < 0)
2002 return r;
2003
2004 if (!UNIT_WRITE_FLAGS_NOOP(flags) && isempty) {
2005 c->set_credentials = hashmap_free(c->set_credentials);
2006 (void) unit_write_settingf(u, flags, name, "%s=", name);
2007 }
2008
2009 return 1;
2010
2011 } else if (streq(name, "LoadCredential")) {
2012 bool isempty = true;
2013
2014 r = sd_bus_message_enter_container(message, 'a', "(ss)");
2015 if (r < 0)
2016 return r;
2017
2018 for (;;) {
2019 const char *id, *source;
2020
2021 r = sd_bus_message_read(message, "(ss)", &id, &source);
2022 if (r < 0)
2023 return r;
2024 if (r == 0)
2025 break;
2026
2027 if (!credential_name_valid(id))
2028 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential ID is invalid: %s", id);
2029
2030 if (!(path_is_absolute(source) ? path_is_normalized(source) : credential_name_valid(source)))
2031 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential source is invalid: %s", source);
2032
2033 isempty = false;
2034
2035 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2036 r = strv_extend_strv(&c->load_credentials, STRV_MAKE(id, source), /* filter_duplicates = */ false);
2037 if (r < 0)
2038 return r;
2039
2040 (void) unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s:%s", name, id, source);
2041 }
2042 }
2043
2044 r = sd_bus_message_exit_container(message);
2045 if (r < 0)
2046 return r;
2047
2048 if (!UNIT_WRITE_FLAGS_NOOP(flags) && isempty) {
2049 c->load_credentials = strv_free(c->load_credentials);
2050 (void) unit_write_settingf(u, flags, name, "%s=", name);
2051 }
2052
2053 return 1;
2054
2055 } else if (streq(name, "SyslogLevel")) {
2056 int32_t level;
2057
2058 r = sd_bus_message_read(message, "i", &level);
2059 if (r < 0)
2060 return r;
2061
2062 if (!log_level_is_valid(level))
2063 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
2064
2065 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2066 c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
2067 unit_write_settingf(u, flags, name, "SyslogLevel=%i", level);
2068 }
2069
2070 return 1;
2071
2072 } else if (streq(name, "SyslogFacility")) {
2073 int32_t facility;
2074
2075 r = sd_bus_message_read(message, "i", &facility);
2076 if (r < 0)
2077 return r;
2078
2079 if (!log_facility_unshifted_is_valid(facility))
2080 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
2081
2082 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2083 c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
2084 unit_write_settingf(u, flags, name, "SyslogFacility=%i", facility);
2085 }
2086
2087 return 1;
2088
2089 } else if (streq(name, "LogNamespace")) {
2090 const char *n;
2091
2092 r = sd_bus_message_read(message, "s", &n);
2093 if (r < 0)
2094 return r;
2095
2096 if (!isempty(n) && !log_namespace_name_valid(n))
2097 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log namespace name not valid");
2098
2099 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2100
2101 if (isempty(n)) {
2102 c->log_namespace = mfree(c->log_namespace);
2103 unit_write_settingf(u, flags, name, "%s=", name);
2104 } else {
2105 r = free_and_strdup(&c->log_namespace, n);
2106 if (r < 0)
2107 return r;
2108
2109 unit_write_settingf(u, flags, name, "%s=%s", name, n);
2110 }
2111 }
2112
2113 return 1;
2114
2115 } else if (streq(name, "LogExtraFields")) {
2116 size_t n = 0;
2117
2118 r = sd_bus_message_enter_container(message, 'a', "ay");
2119 if (r < 0)
2120 return r;
2121
2122 for (;;) {
2123 _cleanup_free_ void *copy = NULL;
2124 struct iovec *t;
2125 const char *eq;
2126 const void *p;
2127 size_t sz;
2128
2129 /* Note that we expect a byte array for each field, instead of a string. That's because on the
2130 * lower-level journal fields can actually contain binary data and are not restricted to text,
2131 * and we should not "lose precision" in our types on the way. That said, I am pretty sure
2132 * actually encoding binary data as unit metadata is not a good idea. Hence we actually refuse
2133 * any actual binary data, and only accept UTF-8. This allows us to eventually lift this
2134 * limitation, should a good, valid usecase arise. */
2135
2136 r = sd_bus_message_read_array(message, 'y', &p, &sz);
2137 if (r < 0)
2138 return r;
2139 if (r == 0)
2140 break;
2141
2142 if (memchr(p, 0, sz))
2143 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field contains zero byte");
2144
2145 eq = memchr(p, '=', sz);
2146 if (!eq)
2147 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field contains no '=' character");
2148 if (!journal_field_valid(p, eq - (const char*) p, false))
2149 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field invalid");
2150
2151 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2152 t = reallocarray(c->log_extra_fields, c->n_log_extra_fields+1, sizeof(struct iovec));
2153 if (!t)
2154 return -ENOMEM;
2155 c->log_extra_fields = t;
2156 }
2157
2158 copy = malloc(sz + 1);
2159 if (!copy)
2160 return -ENOMEM;
2161
2162 memcpy(copy, p, sz);
2163 ((uint8_t*) copy)[sz] = 0;
2164
2165 if (!utf8_is_valid(copy))
2166 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field is not valid UTF-8");
2167
2168 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2169 c->log_extra_fields[c->n_log_extra_fields++] = IOVEC_MAKE(copy, sz);
2170 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_C, name, "LogExtraFields=%s", (char*) copy);
2171
2172 copy = NULL;
2173 }
2174
2175 n++;
2176 }
2177
2178 r = sd_bus_message_exit_container(message);
2179 if (r < 0)
2180 return r;
2181
2182 if (!UNIT_WRITE_FLAGS_NOOP(flags) && n == 0) {
2183 exec_context_free_log_extra_fields(c);
2184 unit_write_setting(u, flags, name, "LogExtraFields=");
2185 }
2186
2187 return 1;
2188 }
2189
2190 #if HAVE_SECCOMP
2191
2192 if (streq(name, "SystemCallErrorNumber"))
2193 return bus_set_transient_errno(u, name, &c->syscall_errno, message, flags, error);
2194
2195 if (streq(name, "SystemCallFilter")) {
2196 int allow_list;
2197 _cleanup_strv_free_ char **l = NULL;
2198
2199 r = sd_bus_message_enter_container(message, 'r', "bas");
2200 if (r < 0)
2201 return r;
2202
2203 r = sd_bus_message_read(message, "b", &allow_list);
2204 if (r < 0)
2205 return r;
2206
2207 r = sd_bus_message_read_strv(message, &l);
2208 if (r < 0)
2209 return r;
2210
2211 r = sd_bus_message_exit_container(message);
2212 if (r < 0)
2213 return r;
2214
2215 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2216 _cleanup_free_ char *joined = NULL;
2217 SeccompParseFlags invert_flag = allow_list ? 0 : SECCOMP_PARSE_INVERT;
2218 char **s;
2219
2220 if (strv_isempty(l)) {
2221 c->syscall_allow_list = false;
2222 c->syscall_filter = hashmap_free(c->syscall_filter);
2223
2224 unit_write_settingf(u, flags, name, "SystemCallFilter=");
2225 return 1;
2226 }
2227
2228 if (!c->syscall_filter) {
2229 c->syscall_filter = hashmap_new(NULL);
2230 if (!c->syscall_filter)
2231 return log_oom();
2232
2233 c->syscall_allow_list = allow_list;
2234
2235 if (c->syscall_allow_list) {
2236 r = seccomp_parse_syscall_filter("@default",
2237 -1,
2238 c->syscall_filter,
2239 SECCOMP_PARSE_PERMISSIVE |
2240 SECCOMP_PARSE_ALLOW_LIST | invert_flag,
2241 u->id,
2242 NULL, 0);
2243 if (r < 0)
2244 return r;
2245 }
2246 }
2247
2248 STRV_FOREACH(s, l) {
2249 _cleanup_free_ char *n = NULL;
2250 int e;
2251
2252 r = parse_syscall_and_errno(*s, &n, &e);
2253 if (r < 0)
2254 return r;
2255
2256 if (allow_list && e >= 0)
2257 return -EINVAL;
2258
2259 r = seccomp_parse_syscall_filter(n,
2260 e,
2261 c->syscall_filter,
2262 SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE |
2263 invert_flag |
2264 (c->syscall_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
2265 u->id,
2266 NULL, 0);
2267 if (r < 0)
2268 return r;
2269 }
2270
2271 joined = strv_join(l, " ");
2272 if (!joined)
2273 return -ENOMEM;
2274
2275 unit_write_settingf(u, flags, name, "SystemCallFilter=%s%s", allow_list ? "" : "~", joined);
2276 }
2277
2278 return 1;
2279
2280 } else if (streq(name, "SystemCallLog")) {
2281 int allow_list;
2282 _cleanup_strv_free_ char **l = NULL;
2283
2284 r = sd_bus_message_enter_container(message, 'r', "bas");
2285 if (r < 0)
2286 return r;
2287
2288 r = sd_bus_message_read(message, "b", &allow_list);
2289 if (r < 0)
2290 return r;
2291
2292 r = sd_bus_message_read_strv(message, &l);
2293 if (r < 0)
2294 return r;
2295
2296 r = sd_bus_message_exit_container(message);
2297 if (r < 0)
2298 return r;
2299
2300 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2301 _cleanup_free_ char *joined = NULL;
2302 SeccompParseFlags invert_flag = allow_list ? 0 : SECCOMP_PARSE_INVERT;
2303 char **s;
2304
2305 if (strv_isempty(l)) {
2306 c->syscall_log_allow_list = false;
2307 c->syscall_log = hashmap_free(c->syscall_log);
2308
2309 unit_write_settingf(u, flags, name, "SystemCallLog=");
2310 return 1;
2311 }
2312
2313 if (!c->syscall_log) {
2314 c->syscall_log = hashmap_new(NULL);
2315 if (!c->syscall_log)
2316 return log_oom();
2317
2318 c->syscall_log_allow_list = allow_list;
2319 }
2320
2321 STRV_FOREACH(s, l) {
2322 r = seccomp_parse_syscall_filter(*s,
2323 -1, /* errno not used */
2324 c->syscall_log,
2325 SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE |
2326 invert_flag |
2327 (c->syscall_log_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
2328 u->id,
2329 NULL, 0);
2330 if (r < 0)
2331 return r;
2332 }
2333
2334 joined = strv_join(l, " ");
2335 if (!joined)
2336 return -ENOMEM;
2337
2338 unit_write_settingf(u, flags, name, "SystemCallLog=%s%s", allow_list ? "" : "~", joined);
2339 }
2340
2341 return 1;
2342
2343 } else if (streq(name, "SystemCallArchitectures")) {
2344 _cleanup_strv_free_ char **l = NULL;
2345
2346 r = sd_bus_message_read_strv(message, &l);
2347 if (r < 0)
2348 return r;
2349
2350 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2351 _cleanup_free_ char *joined = NULL;
2352
2353 if (strv_isempty(l))
2354 c->syscall_archs = set_free(c->syscall_archs);
2355 else {
2356 char **s;
2357
2358 STRV_FOREACH(s, l) {
2359 uint32_t a;
2360
2361 r = seccomp_arch_from_string(*s, &a);
2362 if (r < 0)
2363 return r;
2364
2365 r = set_ensure_put(&c->syscall_archs, NULL, UINT32_TO_PTR(a + 1));
2366 if (r < 0)
2367 return r;
2368 }
2369
2370 }
2371
2372 joined = strv_join(l, " ");
2373 if (!joined)
2374 return -ENOMEM;
2375
2376 unit_write_settingf(u, flags, name, "%s=%s", name, joined);
2377 }
2378
2379 return 1;
2380
2381 } else if (streq(name, "RestrictAddressFamilies")) {
2382 int allow_list;
2383 _cleanup_strv_free_ char **l = NULL;
2384
2385 r = sd_bus_message_enter_container(message, 'r', "bas");
2386 if (r < 0)
2387 return r;
2388
2389 r = sd_bus_message_read(message, "b", &allow_list);
2390 if (r < 0)
2391 return r;
2392
2393 r = sd_bus_message_read_strv(message, &l);
2394 if (r < 0)
2395 return r;
2396
2397 r = sd_bus_message_exit_container(message);
2398 if (r < 0)
2399 return r;
2400
2401 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2402 _cleanup_free_ char *joined = NULL;
2403 char **s;
2404
2405 if (strv_isempty(l)) {
2406 c->address_families_allow_list = false;
2407 c->address_families = set_free(c->address_families);
2408
2409 unit_write_settingf(u, flags, name, "RestrictAddressFamilies=");
2410 return 1;
2411 }
2412
2413 if (!c->address_families) {
2414 c->address_families = set_new(NULL);
2415 if (!c->address_families)
2416 return log_oom();
2417
2418 c->address_families_allow_list = allow_list;
2419 }
2420
2421 STRV_FOREACH(s, l) {
2422 int af;
2423
2424 af = af_from_name(*s);
2425 if (af < 0)
2426 return af;
2427
2428 if (allow_list == c->address_families_allow_list) {
2429 r = set_put(c->address_families, INT_TO_PTR(af));
2430 if (r < 0)
2431 return r;
2432 } else
2433 (void) set_remove(c->address_families, INT_TO_PTR(af));
2434 }
2435
2436 joined = strv_join(l, " ");
2437 if (!joined)
2438 return -ENOMEM;
2439
2440 unit_write_settingf(u, flags, name, "RestrictAddressFamilies=%s%s", allow_list ? "" : "~", joined);
2441 }
2442
2443 return 1;
2444 }
2445 #endif
2446 if (STR_IN_SET(name, "CPUAffinity", "NUMAMask")) {
2447 const void *a;
2448 size_t n;
2449 bool affinity = streq(name, "CPUAffinity");
2450 _cleanup_(cpu_set_reset) CPUSet set = {};
2451
2452 r = sd_bus_message_read_array(message, 'y', &a, &n);
2453 if (r < 0)
2454 return r;
2455
2456 r = cpu_set_from_dbus(a, n, &set);
2457 if (r < 0)
2458 return r;
2459
2460 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2461 if (n == 0) {
2462 cpu_set_reset(affinity ? &c->cpu_set : &c->numa_policy.nodes);
2463 unit_write_settingf(u, flags, name, "%s=", name);
2464 } else {
2465 _cleanup_free_ char *str = NULL;
2466
2467 str = cpu_set_to_string(&set);
2468 if (!str)
2469 return -ENOMEM;
2470
2471 /* We forego any optimizations here, and always create the structure using
2472 * cpu_set_add_all(), because we don't want to care if the existing size we
2473 * got over dbus is appropriate. */
2474 r = cpu_set_add_all(affinity ? &c->cpu_set : &c->numa_policy.nodes, &set);
2475 if (r < 0)
2476 return r;
2477
2478 unit_write_settingf(u, flags, name, "%s=%s", name, str);
2479 }
2480 }
2481
2482 return 1;
2483
2484 } else if (streq(name, "CPUAffinityFromNUMA")) {
2485 int q;
2486
2487 r = sd_bus_message_read_basic(message, 'b', &q);
2488 if (r < 0)
2489 return r;
2490
2491 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2492 c->cpu_affinity_from_numa = q;
2493 unit_write_settingf(u, flags, name, "%s=%s", "CPUAffinity", "numa");
2494 }
2495
2496 return 1;
2497
2498 } else if (streq(name, "NUMAPolicy")) {
2499 int32_t type;
2500
2501 r = sd_bus_message_read(message, "i", &type);
2502 if (r < 0)
2503 return r;
2504
2505 if (!mpol_is_valid(type))
2506 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NUMAPolicy value: %i", type);
2507
2508 if (!UNIT_WRITE_FLAGS_NOOP(flags))
2509 c->numa_policy.type = type;
2510
2511 return 1;
2512
2513 } else if (streq(name, "Nice")) {
2514 int32_t q;
2515
2516 r = sd_bus_message_read(message, "i", &q);
2517 if (r < 0)
2518 return r;
2519
2520 if (!nice_is_valid(q))
2521 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Nice value: %i", q);
2522
2523 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2524 c->nice = q;
2525 c->nice_set = true;
2526
2527 unit_write_settingf(u, flags, name, "Nice=%i", q);
2528 }
2529
2530 return 1;
2531
2532 } else if (streq(name, "CPUSchedulingPolicy")) {
2533 int32_t q;
2534
2535 r = sd_bus_message_read(message, "i", &q);
2536 if (r < 0)
2537 return r;
2538
2539 if (!sched_policy_is_valid(q))
2540 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling policy: %i", q);
2541
2542 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2543 _cleanup_free_ char *s = NULL;
2544
2545 r = sched_policy_to_string_alloc(q, &s);
2546 if (r < 0)
2547 return r;
2548
2549 c->cpu_sched_policy = q;
2550 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(q), sched_get_priority_max(q));
2551 c->cpu_sched_set = true;
2552
2553 unit_write_settingf(u, flags, name, "CPUSchedulingPolicy=%s", s);
2554 }
2555
2556 return 1;
2557
2558 } else if (streq(name, "CPUSchedulingPriority")) {
2559 int32_t p, min, max;
2560
2561 r = sd_bus_message_read(message, "i", &p);
2562 if (r < 0)
2563 return r;
2564
2565 min = sched_get_priority_min(c->cpu_sched_policy);
2566 max = sched_get_priority_max(c->cpu_sched_policy);
2567 if (p < min || p > max)
2568 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling priority: %i", p);
2569
2570 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2571 c->cpu_sched_priority = p;
2572 c->cpu_sched_set = true;
2573
2574 unit_write_settingf(u, flags, name, "CPUSchedulingPriority=%i", p);
2575 }
2576
2577 return 1;
2578
2579 } else if (streq(name, "IOSchedulingClass")) {
2580 int32_t q;
2581
2582 r = sd_bus_message_read(message, "i", &q);
2583 if (r < 0)
2584 return r;
2585
2586 if (!ioprio_class_is_valid(q))
2587 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid IO scheduling class: %i", q);
2588
2589 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2590 _cleanup_free_ char *s = NULL;
2591
2592 r = ioprio_class_to_string_alloc(q, &s);
2593 if (r < 0)
2594 return r;
2595
2596 c->ioprio = IOPRIO_PRIO_VALUE(q, IOPRIO_PRIO_DATA(c->ioprio));
2597 c->ioprio_set = true;
2598
2599 unit_write_settingf(u, flags, name, "IOSchedulingClass=%s", s);
2600 }
2601
2602 return 1;
2603
2604 } else if (streq(name, "IOSchedulingPriority")) {
2605 int32_t p;
2606
2607 r = sd_bus_message_read(message, "i", &p);
2608 if (r < 0)
2609 return r;
2610
2611 if (!ioprio_priority_is_valid(p))
2612 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid IO scheduling priority: %i", p);
2613
2614 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2615 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), p);
2616 c->ioprio_set = true;
2617
2618 unit_write_settingf(u, flags, name, "IOSchedulingPriority=%i", p);
2619 }
2620
2621 return 1;
2622
2623 } else if (streq(name, "MountAPIVFS")) {
2624 bool b;
2625
2626 r = bus_set_transient_bool(u, name, &b, message, flags, error);
2627 if (r < 0)
2628 return r;
2629
2630 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2631 c->mount_apivfs = b;
2632 c->mount_apivfs_set = true;
2633 }
2634
2635 return 1;
2636
2637 } else if (streq(name, "WorkingDirectory")) {
2638 const char *s;
2639 bool missing_ok;
2640
2641 r = sd_bus_message_read(message, "s", &s);
2642 if (r < 0)
2643 return r;
2644
2645 if (s[0] == '-') {
2646 missing_ok = true;
2647 s++;
2648 } else
2649 missing_ok = false;
2650
2651 if (!isempty(s) && !streq(s, "~") && !path_is_absolute(s))
2652 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
2653
2654 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2655 if (streq(s, "~")) {
2656 c->working_directory = mfree(c->working_directory);
2657 c->working_directory_home = true;
2658 } else {
2659 r = free_and_strdup(&c->working_directory, empty_to_null(s));
2660 if (r < 0)
2661 return r;
2662
2663 c->working_directory_home = false;
2664 }
2665
2666 c->working_directory_missing_ok = missing_ok;
2667 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s);
2668 }
2669
2670 return 1;
2671
2672 } else if (STR_IN_SET(name,
2673 "StandardInputFileDescriptorName", "StandardOutputFileDescriptorName", "StandardErrorFileDescriptorName")) {
2674 const char *s;
2675
2676 r = sd_bus_message_read(message, "s", &s);
2677 if (r < 0)
2678 return r;
2679
2680 if (!isempty(s) && !fdname_is_valid(s))
2681 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid file descriptor name");
2682
2683 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2684
2685 if (streq(name, "StandardInputFileDescriptorName")) {
2686 r = free_and_strdup(c->stdio_fdname + STDIN_FILENO, empty_to_null(s));
2687 if (r < 0)
2688 return r;
2689
2690 c->std_input = EXEC_INPUT_NAMED_FD;
2691 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=fd:%s", exec_context_fdname(c, STDIN_FILENO));
2692
2693 } else if (streq(name, "StandardOutputFileDescriptorName")) {
2694 r = free_and_strdup(c->stdio_fdname + STDOUT_FILENO, empty_to_null(s));
2695 if (r < 0)
2696 return r;
2697
2698 c->std_output = EXEC_OUTPUT_NAMED_FD;
2699 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=fd:%s", exec_context_fdname(c, STDOUT_FILENO));
2700
2701 } else {
2702 assert(streq(name, "StandardErrorFileDescriptorName"));
2703
2704 r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], empty_to_null(s));
2705 if (r < 0)
2706 return r;
2707
2708 c->std_error = EXEC_OUTPUT_NAMED_FD;
2709 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=fd:%s", exec_context_fdname(c, STDERR_FILENO));
2710 }
2711 }
2712
2713 return 1;
2714
2715 } else if (STR_IN_SET(name,
2716 "StandardInputFile",
2717 "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate",
2718 "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate")) {
2719 const char *s;
2720
2721 r = sd_bus_message_read(message, "s", &s);
2722 if (r < 0)
2723 return r;
2724
2725 if (!isempty(s)) {
2726 if (!path_is_absolute(s))
2727 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute", s);
2728 if (!path_is_normalized(s))
2729 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not normalized", s);
2730 }
2731
2732 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2733
2734 if (streq(name, "StandardInputFile")) {
2735 r = free_and_strdup(&c->stdio_file[STDIN_FILENO], empty_to_null(s));
2736 if (r < 0)
2737 return r;
2738
2739 c->std_input = EXEC_INPUT_FILE;
2740 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s);
2741
2742 } else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate")) {
2743 r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], empty_to_null(s));
2744 if (r < 0)
2745 return r;
2746
2747 if (streq(name, "StandardOutputFile")) {
2748 c->std_output = EXEC_OUTPUT_FILE;
2749 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
2750 } else if (streq(name, "StandardOutputFileToAppend")) {
2751 c->std_output = EXEC_OUTPUT_FILE_APPEND;
2752 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s);
2753 } else {
2754 assert(streq(name, "StandardOutputFileToTruncate"));
2755 c->std_output = EXEC_OUTPUT_FILE_TRUNCATE;
2756 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=truncate:%s", s);
2757 }
2758 } else {
2759 assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate"));
2760
2761 r = free_and_strdup(&c->stdio_file[STDERR_FILENO], empty_to_null(s));
2762 if (r < 0)
2763 return r;
2764
2765 if (streq(name, "StandardErrorFile")) {
2766 c->std_error = EXEC_OUTPUT_FILE;
2767 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=file:%s", s);
2768 } else if (streq(name, "StandardErrorFileToAppend")) {
2769 c->std_error = EXEC_OUTPUT_FILE_APPEND;
2770 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=append:%s", s);
2771 } else {
2772 assert(streq(name, "StandardErrorFileToTruncate"));
2773 c->std_error = EXEC_OUTPUT_FILE_TRUNCATE;
2774 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=truncate:%s", s);
2775 }
2776 }
2777 }
2778
2779 return 1;
2780
2781 } else if (streq(name, "StandardInputData")) {
2782 const void *p;
2783 size_t sz;
2784
2785 r = sd_bus_message_read_array(message, 'y', &p, &sz);
2786 if (r < 0)
2787 return r;
2788
2789 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2790 _cleanup_free_ char *encoded = NULL;
2791
2792 if (sz == 0) {
2793 c->stdin_data = mfree(c->stdin_data);
2794 c->stdin_data_size = 0;
2795
2796 unit_write_settingf(u, flags, name, "StandardInputData=");
2797 } else {
2798 void *q;
2799 ssize_t n;
2800
2801 if (c->stdin_data_size + sz < c->stdin_data_size || /* check for overflow */
2802 c->stdin_data_size + sz > EXEC_STDIN_DATA_MAX)
2803 return -E2BIG;
2804
2805 n = base64mem(p, sz, &encoded);
2806 if (n < 0)
2807 return (int) n;
2808
2809 q = realloc(c->stdin_data, c->stdin_data_size + sz);
2810 if (!q)
2811 return -ENOMEM;
2812
2813 memcpy((uint8_t*) q + c->stdin_data_size, p, sz);
2814
2815 c->stdin_data = q;
2816 c->stdin_data_size += sz;
2817
2818 unit_write_settingf(u, flags, name, "StandardInputData=%s", encoded);
2819 }
2820 }
2821
2822 return 1;
2823
2824 } else if (streq(name, "Environment")) {
2825
2826 _cleanup_strv_free_ char **l = NULL;
2827
2828 r = sd_bus_message_read_strv(message, &l);
2829 if (r < 0)
2830 return r;
2831
2832 if (!strv_env_is_valid(l))
2833 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
2834
2835 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2836 if (strv_isempty(l)) {
2837 c->environment = strv_free(c->environment);
2838 unit_write_setting(u, flags, name, "Environment=");
2839 } else {
2840 _cleanup_free_ char *joined = NULL;
2841 char **e;
2842
2843 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_C);
2844 if (!joined)
2845 return -ENOMEM;
2846
2847 e = strv_env_merge(2, c->environment, l);
2848 if (!e)
2849 return -ENOMEM;
2850
2851 strv_free_and_replace(c->environment, e);
2852 unit_write_settingf(u, flags, name, "Environment=%s", joined);
2853 }
2854 }
2855
2856 return 1;
2857
2858 } else if (streq(name, "UnsetEnvironment")) {
2859
2860 _cleanup_strv_free_ char **l = NULL;
2861
2862 r = sd_bus_message_read_strv(message, &l);
2863 if (r < 0)
2864 return r;
2865
2866 if (!strv_env_name_or_assignment_is_valid(l))
2867 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UnsetEnvironment= list.");
2868
2869 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2870 if (strv_isempty(l)) {
2871 c->unset_environment = strv_free(c->unset_environment);
2872 unit_write_setting(u, flags, name, "UnsetEnvironment=");
2873 } else {
2874 _cleanup_free_ char *joined = NULL;
2875 char **e;
2876
2877 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_C);
2878 if (!joined)
2879 return -ENOMEM;
2880
2881 e = strv_env_merge(2, c->unset_environment, l);
2882 if (!e)
2883 return -ENOMEM;
2884
2885 strv_free_and_replace(c->unset_environment, e);
2886 unit_write_settingf(u, flags, name, "UnsetEnvironment=%s", joined);
2887 }
2888 }
2889
2890 return 1;
2891
2892 } else if (streq(name, "OOMScoreAdjust")) {
2893 int oa;
2894
2895 r = sd_bus_message_read(message, "i", &oa);
2896 if (r < 0)
2897 return r;
2898
2899 if (!oom_score_adjust_is_valid(oa))
2900 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
2901
2902 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2903 c->oom_score_adjust = oa;
2904 c->oom_score_adjust_set = true;
2905 unit_write_settingf(u, flags, name, "OOMScoreAdjust=%i", oa);
2906 }
2907
2908 return 1;
2909
2910 } else if (streq(name, "CoredumpFilter")) {
2911 uint64_t f;
2912
2913 r = sd_bus_message_read(message, "t", &f);
2914 if (r < 0)
2915 return r;
2916
2917 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2918 c->coredump_filter = f;
2919 c->coredump_filter_set = true;
2920 unit_write_settingf(u, flags, name, "CoredumpFilter=0x%"PRIx64, f);
2921 }
2922
2923 return 1;
2924
2925 } else if (streq(name, "EnvironmentFiles")) {
2926
2927 _cleanup_free_ char *joined = NULL;
2928 _cleanup_fclose_ FILE *f = NULL;
2929 _cleanup_strv_free_ char **l = NULL;
2930 size_t size = 0;
2931 char **i;
2932
2933 r = sd_bus_message_enter_container(message, 'a', "(sb)");
2934 if (r < 0)
2935 return r;
2936
2937 f = open_memstream_unlocked(&joined, &size);
2938 if (!f)
2939 return -ENOMEM;
2940
2941 fputs("EnvironmentFile=\n", f);
2942
2943 STRV_FOREACH(i, c->environment_files) {
2944 _cleanup_free_ char *q = NULL;
2945
2946 q = specifier_escape(*i);
2947 if (!q)
2948 return -ENOMEM;
2949
2950 fprintf(f, "EnvironmentFile=%s\n", q);
2951 }
2952
2953 while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) {
2954 const char *path;
2955 int b;
2956
2957 r = sd_bus_message_read(message, "sb", &path, &b);
2958 if (r < 0)
2959 return r;
2960
2961 r = sd_bus_message_exit_container(message);
2962 if (r < 0)
2963 return r;
2964
2965 if (!path_is_absolute(path))
2966 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
2967
2968 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2969 _cleanup_free_ char *q = NULL, *buf = NULL;
2970
2971 buf = strjoin(b ? "-" : "", path);
2972 if (!buf)
2973 return -ENOMEM;
2974
2975 q = specifier_escape(buf);
2976 if (!q)
2977 return -ENOMEM;
2978
2979 fprintf(f, "EnvironmentFile=%s\n", q);
2980
2981 r = strv_consume(&l, TAKE_PTR(buf));
2982 if (r < 0)
2983 return r;
2984 }
2985 }
2986 if (r < 0)
2987 return r;
2988
2989 r = sd_bus_message_exit_container(message);
2990 if (r < 0)
2991 return r;
2992
2993 r = fflush_and_check(f);
2994 if (r < 0)
2995 return r;
2996
2997 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2998 if (strv_isempty(l)) {
2999 c->environment_files = strv_free(c->environment_files);
3000 unit_write_setting(u, flags, name, "EnvironmentFile=");
3001 } else {
3002 r = strv_extend_strv(&c->environment_files, l, true);
3003 if (r < 0)
3004 return r;
3005
3006 unit_write_setting(u, flags, name, joined);
3007 }
3008 }
3009
3010 return 1;
3011
3012 } else if (streq(name, "PassEnvironment")) {
3013
3014 _cleanup_strv_free_ char **l = NULL;
3015
3016 r = sd_bus_message_read_strv(message, &l);
3017 if (r < 0)
3018 return r;
3019
3020 if (!strv_env_name_is_valid(l))
3021 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment= block.");
3022
3023 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3024 if (strv_isempty(l)) {
3025 c->pass_environment = strv_free(c->pass_environment);
3026 unit_write_setting(u, flags, name, "PassEnvironment=");
3027 } else {
3028 _cleanup_free_ char *joined = NULL;
3029
3030 r = strv_extend_strv(&c->pass_environment, l, true);
3031 if (r < 0)
3032 return r;
3033
3034 /* We write just the new settings out to file, with unresolved specifiers. */
3035 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
3036 if (!joined)
3037 return -ENOMEM;
3038
3039 unit_write_settingf(u, flags, name, "PassEnvironment=%s", joined);
3040 }
3041 }
3042
3043 return 1;
3044
3045 } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
3046 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths", "ExecPaths", "NoExecPaths")) {
3047 _cleanup_strv_free_ char **l = NULL;
3048 char ***dirs;
3049 char **p;
3050
3051 r = sd_bus_message_read_strv(message, &l);
3052 if (r < 0)
3053 return r;
3054
3055 STRV_FOREACH(p, l) {
3056 char *i = *p;
3057 size_t offset;
3058
3059 offset = i[0] == '-';
3060 offset += i[offset] == '+';
3061 if (!path_is_absolute(i + offset))
3062 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
3063
3064 path_simplify(i + offset, false);
3065 }
3066
3067 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3068 if (STR_IN_SET(name, "ReadWriteDirectories", "ReadWritePaths"))
3069 dirs = &c->read_write_paths;
3070 else if (STR_IN_SET(name, "ReadOnlyDirectories", "ReadOnlyPaths"))
3071 dirs = &c->read_only_paths;
3072 else if (streq(name, "ExecPaths"))
3073 dirs = &c->exec_paths;
3074 else if (streq(name, "NoExecPaths"))
3075 dirs = &c->no_exec_paths;
3076 else /* "InaccessiblePaths" */
3077 dirs = &c->inaccessible_paths;
3078
3079 if (strv_isempty(l)) {
3080 *dirs = strv_free(*dirs);
3081 unit_write_settingf(u, flags, name, "%s=", name);
3082 } else {
3083 _cleanup_free_ char *joined = NULL;
3084
3085 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
3086 if (!joined)
3087 return -ENOMEM;
3088
3089 r = strv_extend_strv(dirs, l, true);
3090 if (r < 0)
3091 return -ENOMEM;
3092
3093 unit_write_settingf(u, flags, name, "%s=%s", name, joined);
3094 }
3095 }
3096
3097 return 1;
3098
3099 } else if (STR_IN_SET(name, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) {
3100 _cleanup_strv_free_ char **l = NULL;
3101 char **p;
3102
3103 r = sd_bus_message_read_strv(message, &l);
3104 if (r < 0)
3105 return r;
3106
3107 STRV_FOREACH(p, l) {
3108 if (!path_is_normalized(*p))
3109 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is not normalized: %s", name, *p);
3110
3111 if (path_is_absolute(*p))
3112 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is absolute: %s", name, *p);
3113
3114 if (path_startswith(*p, "private"))
3115 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path can't be 'private': %s", name, *p);
3116 }
3117
3118 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3119 ExecDirectoryType i;
3120 ExecDirectory *d;
3121
3122 assert_se((i = exec_directory_type_from_string(name)) >= 0);
3123 d = c->directories + i;
3124
3125 if (strv_isempty(l)) {
3126 d->paths = strv_free(d->paths);
3127 unit_write_settingf(u, flags, name, "%s=", name);
3128 } else {
3129 _cleanup_free_ char *joined = NULL;
3130
3131 r = strv_extend_strv(&d->paths, l, true);
3132 if (r < 0)
3133 return r;
3134
3135 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
3136 if (!joined)
3137 return -ENOMEM;
3138
3139 unit_write_settingf(u, flags, name, "%s=%s", name, joined);
3140 }
3141 }
3142
3143 return 1;
3144
3145 } else if (STR_IN_SET(name, "AppArmorProfile", "SmackProcessLabel")) {
3146 int ignore;
3147 const char *s;
3148
3149 r = sd_bus_message_read(message, "(bs)", &ignore, &s);
3150 if (r < 0)
3151 return r;
3152
3153 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3154 char **p;
3155 bool *b;
3156
3157 if (streq(name, "AppArmorProfile")) {
3158 p = &c->apparmor_profile;
3159 b = &c->apparmor_profile_ignore;
3160 } else { /* "SmackProcessLabel" */
3161 p = &c->smack_process_label;
3162 b = &c->smack_process_label_ignore;
3163 }
3164
3165 if (isempty(s)) {
3166 *p = mfree(*p);
3167 *b = false;
3168 } else {
3169 if (free_and_strdup(p, s) < 0)
3170 return -ENOMEM;
3171 *b = ignore;
3172 }
3173
3174 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s%s", name, ignore ? "-" : "", strempty(s));
3175 }
3176
3177 return 1;
3178
3179 } else if (STR_IN_SET(name, "BindPaths", "BindReadOnlyPaths")) {
3180 char *source, *destination;
3181 int ignore_enoent;
3182 uint64_t mount_flags;
3183 bool empty = true;
3184
3185 r = sd_bus_message_enter_container(message, 'a', "(ssbt)");
3186 if (r < 0)
3187 return r;
3188
3189 while ((r = sd_bus_message_read(message, "(ssbt)", &source, &destination, &ignore_enoent, &mount_flags)) > 0) {
3190
3191 if (!path_is_absolute(source))
3192 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source);
3193 if (!path_is_absolute(destination))
3194 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not absolute.", destination);
3195 if (!IN_SET(mount_flags, 0, MS_REC))
3196 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mount flags.");
3197
3198 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3199 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
3200 &(BindMount) {
3201 .source = source,
3202 .destination = destination,
3203 .read_only = !!strstr(name, "ReadOnly"),
3204 .recursive = !!(mount_flags & MS_REC),
3205 .ignore_enoent = ignore_enoent,
3206 });
3207 if (r < 0)
3208 return r;
3209
3210 unit_write_settingf(
3211 u, flags|UNIT_ESCAPE_SPECIFIERS, name,
3212 "%s=%s%s:%s:%s",
3213 name,
3214 ignore_enoent ? "-" : "",
3215 source,
3216 destination,
3217 (mount_flags & MS_REC) ? "rbind" : "norbind");
3218 }
3219
3220 empty = false;
3221 }
3222 if (r < 0)
3223 return r;
3224
3225 r = sd_bus_message_exit_container(message);
3226 if (r < 0)
3227 return r;
3228
3229 if (empty) {
3230 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
3231 c->bind_mounts = NULL;
3232 c->n_bind_mounts = 0;
3233
3234 unit_write_settingf(u, flags, name, "%s=", name);
3235 }
3236
3237 return 1;
3238
3239 } else if (streq(name, "TemporaryFileSystem")) {
3240 const char *path, *options;
3241 bool empty = true;
3242
3243 r = sd_bus_message_enter_container(message, 'a', "(ss)");
3244 if (r < 0)
3245 return r;
3246
3247 while ((r = sd_bus_message_read(message, "(ss)", &path, &options)) > 0) {
3248
3249 if (!path_is_absolute(path))
3250 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Mount point %s is not absolute.", path);
3251
3252 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3253 r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, path, options);
3254 if (r < 0)
3255 return r;
3256
3257 unit_write_settingf(
3258 u, flags|UNIT_ESCAPE_SPECIFIERS, name,
3259 "%s=%s:%s",
3260 name,
3261 path,
3262 options);
3263 }
3264
3265 empty = false;
3266 }
3267 if (r < 0)
3268 return r;
3269
3270 r = sd_bus_message_exit_container(message);
3271 if (r < 0)
3272 return r;
3273
3274 if (empty) {
3275 temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
3276 c->temporary_filesystems = NULL;
3277 c->n_temporary_filesystems = 0;
3278
3279 unit_write_settingf(u, flags, name, "%s=", name);
3280 }
3281
3282 return 1;
3283
3284 } else if ((suffix = startswith(name, "Limit"))) {
3285 const char *soft = NULL;
3286 int ri;
3287
3288 ri = rlimit_from_string(suffix);
3289 if (ri < 0) {
3290 soft = endswith(suffix, "Soft");
3291 if (soft) {
3292 const char *n;
3293
3294 n = strndupa(suffix, soft - suffix);
3295 ri = rlimit_from_string(n);
3296 if (ri >= 0)
3297 name = strjoina("Limit", n);
3298 }
3299 }
3300
3301 if (ri >= 0) {
3302 uint64_t rl;
3303 rlim_t x;
3304
3305 r = sd_bus_message_read(message, "t", &rl);
3306 if (r < 0)
3307 return r;
3308
3309 if (rl == UINT64_MAX)
3310 x = RLIM_INFINITY;
3311 else {
3312 x = (rlim_t) rl;
3313
3314 if ((uint64_t) x != rl)
3315 return -ERANGE;
3316 }
3317
3318 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3319 _cleanup_free_ char *f = NULL;
3320 struct rlimit nl;
3321
3322 if (c->rlimit[ri]) {
3323 nl = *c->rlimit[ri];
3324
3325 if (soft)
3326 nl.rlim_cur = x;
3327 else
3328 nl.rlim_max = x;
3329 } else
3330 /* When the resource limit is not initialized yet, then assign the value to both fields */
3331 nl = (struct rlimit) {
3332 .rlim_cur = x,
3333 .rlim_max = x,
3334 };
3335
3336 r = rlimit_format(&nl, &f);
3337 if (r < 0)
3338 return r;
3339
3340 if (c->rlimit[ri])
3341 *c->rlimit[ri] = nl;
3342 else {
3343 c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
3344 if (!c->rlimit[ri])
3345 return -ENOMEM;
3346 }
3347
3348 unit_write_settingf(u, flags, name, "%s=%s", name, f);
3349 }
3350
3351 return 1;
3352 }
3353
3354 } else if (streq(name, "MountImages")) {
3355 _cleanup_free_ char *format_str = NULL;
3356 MountImage *mount_images = NULL;
3357 size_t n_mount_images = 0;
3358 char *source, *destination;
3359 int permissive;
3360
3361 r = sd_bus_message_enter_container(message, 'a', "(ssba(ss))");
3362 if (r < 0)
3363 return r;
3364
3365 for (;;) {
3366 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
3367 _cleanup_free_ char *source_escaped = NULL, *destination_escaped = NULL;
3368 char *tuple;
3369
3370 r = sd_bus_message_enter_container(message, 'r', "ssba(ss)");
3371 if (r < 0)
3372 return r;
3373
3374 r = sd_bus_message_read(message, "ssb", &source, &destination, &permissive);
3375 if (r <= 0)
3376 break;
3377
3378 if (!path_is_absolute(source))
3379 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source);
3380 if (!path_is_normalized(source))
3381 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not normalized.", source);
3382 if (!path_is_absolute(destination))
3383 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not absolute.", destination);
3384 if (!path_is_normalized(destination))
3385 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not normalized.", destination);
3386
3387 /* Need to store them in the unit with the escapes, so that they can be parsed again */
3388 source_escaped = shell_escape(source, ":");
3389 if (!source_escaped)
3390 return -ENOMEM;
3391 destination_escaped = shell_escape(destination, ":");
3392 if (!destination_escaped)
3393 return -ENOMEM;
3394
3395 tuple = strjoin(format_str,
3396 format_str ? " " : "",
3397 permissive ? "-" : "",
3398 source_escaped,
3399 ":",
3400 destination_escaped);
3401 if (!tuple)
3402 return -ENOMEM;
3403 free_and_replace(format_str, tuple);
3404
3405 r = bus_read_mount_options(message, error, &options, &format_str, ":");
3406 if (r < 0)
3407 return r;
3408
3409 r = sd_bus_message_exit_container(message);
3410 if (r < 0)
3411 return r;
3412
3413 r = mount_image_add(&mount_images, &n_mount_images,
3414 &(MountImage) {
3415 .source = source,
3416 .destination = destination,
3417 .mount_options = options,
3418 .ignore_enoent = permissive,
3419 .type = MOUNT_IMAGE_DISCRETE,
3420 });
3421 if (r < 0)
3422 return r;
3423 }
3424 if (r < 0)
3425 return r;
3426
3427 r = sd_bus_message_exit_container(message);
3428 if (r < 0)
3429 return r;
3430
3431 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3432 if (n_mount_images == 0) {
3433 c->mount_images = mount_image_free_many(c->mount_images, &c->n_mount_images);
3434
3435 unit_write_settingf(u, flags, name, "%s=", name);
3436 } else {
3437 for (size_t i = 0; i < n_mount_images; ++i) {
3438 r = mount_image_add(&c->mount_images, &c->n_mount_images, &mount_images[i]);
3439 if (r < 0)
3440 return r;
3441 }
3442
3443 unit_write_settingf(u, flags|UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS,
3444 name,
3445 "%s=%s",
3446 name,
3447 format_str);
3448 }
3449 }
3450
3451 mount_images = mount_image_free_many(mount_images, &n_mount_images);
3452
3453 return 1;
3454 } else if (streq(name, "ExtensionImages")) {
3455 _cleanup_free_ char *format_str = NULL;
3456 MountImage *extension_images = NULL;
3457 size_t n_extension_images = 0;
3458
3459 r = sd_bus_message_enter_container(message, 'a', "(sba(ss))");
3460 if (r < 0)
3461 return r;
3462
3463 for (;;) {
3464 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
3465 _cleanup_free_ char *source_escaped = NULL;
3466 char *source, *tuple;
3467 int permissive;
3468
3469 r = sd_bus_message_enter_container(message, 'r', "sba(ss)");
3470 if (r < 0)
3471 return r;
3472
3473 r = sd_bus_message_read(message, "sb", &source, &permissive);
3474 if (r <= 0)
3475 break;
3476
3477 if (!path_is_absolute(source))
3478 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source);
3479 if (!path_is_normalized(source))
3480 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not normalized.", source);
3481
3482 /* Need to store them in the unit with the escapes, so that they can be parsed again */
3483 source_escaped = shell_escape(source, ":");
3484 if (!source_escaped)
3485 return -ENOMEM;
3486
3487 tuple = strjoin(format_str,
3488 format_str ? " " : "",
3489 permissive ? "-" : "",
3490 source_escaped);
3491 if (!tuple)
3492 return -ENOMEM;
3493 free_and_replace(format_str, tuple);
3494
3495 r = bus_read_mount_options(message, error, &options, &format_str, ":");
3496 if (r < 0)
3497 return r;
3498
3499 r = sd_bus_message_exit_container(message);
3500 if (r < 0)
3501 return r;
3502
3503 r = mount_image_add(&extension_images, &n_extension_images,
3504 &(MountImage) {
3505 .source = source,
3506 .mount_options = options,
3507 .ignore_enoent = permissive,
3508 .type = MOUNT_IMAGE_EXTENSION,
3509 });
3510 if (r < 0)
3511 return r;
3512 }
3513 if (r < 0)
3514 return r;
3515
3516 r = sd_bus_message_exit_container(message);
3517 if (r < 0)
3518 return r;
3519
3520 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3521 if (n_extension_images == 0) {
3522 c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
3523
3524 unit_write_settingf(u, flags, name, "%s=", name);
3525 } else {
3526 for (size_t i = 0; i < n_extension_images; ++i) {
3527 r = mount_image_add(&c->extension_images, &c->n_extension_images, &extension_images[i]);
3528 if (r < 0)
3529 return r;
3530 }
3531
3532 unit_write_settingf(u, flags|UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS,
3533 name,
3534 "%s=%s",
3535 name,
3536 format_str);
3537 }
3538 }
3539
3540 extension_images = mount_image_free_many(extension_images, &n_extension_images);
3541
3542 return 1;
3543 }
3544
3545 return 0;
3546 }