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