1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
9 #include "bus-common-errors.h"
10 #include "bus-error.h"
11 #include "bus-locator.h"
12 #include "bus-unit-util.h"
15 #include "cgroup-setup.h"
16 #include "cgroup-util.h"
17 #include "condition.h"
18 #include "constants.h"
19 #include "coredump-util.h"
20 #include "cpu-set-util.h"
22 #include "exec-util.h"
23 #include "exit-status.h"
24 #include "extract-word.h"
25 #include "firewall-util.h"
26 #include "hexdecoct.h"
27 #include "hostname-util.h"
28 #include "in-addr-util.h"
30 #include "ioprio-util.h"
31 #include "ip-protocol-list.h"
33 #include "mountpoint-util.h"
35 #include "numa-util.h"
36 #include "open-file.h"
37 #include "parse-helpers.h"
38 #include "parse-util.h"
39 #include "path-util.h"
40 #include "percent-util.h"
42 #include "process-util.h"
43 #include "rlimit-util.h"
44 #include "seccomp-util.h"
45 #include "securebits-util.h"
46 #include "signal-util.h"
47 #include "socket-util.h"
48 #include "string-util.h"
49 #include "syslog-util.h"
50 #include "time-util.h"
53 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
59 return sd_bus_message_read(
74 static int warn_deprecated(const char *field
, const char *eq
) {
75 log_warning("D-Bus property %s is deprecated, ignoring assignment: %s=%s", field
, field
, eq
);
79 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
80 static int bus_append_##parse_func( \
87 r = parse_func(eq, &val); \
89 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
91 r = sd_bus_message_append(m, "(sv)", field, \
92 bus_type, (cast_type) val); \
94 return bus_log_create_error(r); \
99 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
100 static int bus_append_##parse_func( \
106 r = parse_func(eq); \
108 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
110 r = sd_bus_message_append(m, "(sv)", field, \
111 bus_type, (int32_t) r); \
113 return bus_log_create_error(r); \
118 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
119 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
120 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
121 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
122 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
123 DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action
);
124 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
125 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
126 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
127 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
128 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
129 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
130 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
131 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
132 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
133 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse
);
134 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flag_from_string
);
135 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
136 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
137 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
138 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
139 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
141 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
144 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
146 return bus_log_create_error(r
);
151 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, const char *separator
, ExtractFlags flags
) {
157 r
= sd_bus_message_open_container(m
, 'r', "sv");
159 return bus_log_create_error(r
);
161 r
= sd_bus_message_append_basic(m
, 's', field
);
163 return bus_log_create_error(r
);
165 r
= sd_bus_message_open_container(m
, 'v', "as");
167 return bus_log_create_error(r
);
169 r
= sd_bus_message_open_container(m
, 'a', "s");
171 return bus_log_create_error(r
);
173 for (const char *p
= eq
;;) {
174 _cleanup_free_
char *word
= NULL
;
176 r
= extract_first_word(&p
, &word
, separator
, flags
);
180 return log_error_errno(r
, "Invalid syntax: %s", eq
);
184 r
= sd_bus_message_append_basic(m
, 's', word
);
186 return bus_log_create_error(r
);
189 r
= sd_bus_message_close_container(m
);
191 return bus_log_create_error(r
);
193 r
= sd_bus_message_close_container(m
);
195 return bus_log_create_error(r
);
197 r
= sd_bus_message_close_container(m
);
199 return bus_log_create_error(r
);
204 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
207 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
209 return bus_log_create_error(r
);
211 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
213 return bus_log_create_error(r
);
215 r
= sd_bus_message_open_container(m
, 'v', "ay");
217 return bus_log_create_error(r
);
219 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
221 return bus_log_create_error(r
);
223 r
= sd_bus_message_close_container(m
);
225 return bus_log_create_error(r
);
227 r
= sd_bus_message_close_container(m
);
229 return bus_log_create_error(r
);
234 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
240 r
= parse_sec(eq
, &t
);
242 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
245 n
= newa(char, l
+ 2);
246 /* Change suffix Sec → USec */
247 strcpy(mempcpy(n
, field
, l
- 3), "USec");
249 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
251 return bus_log_create_error(r
);
256 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
260 r
= parse_size(eq
, base
, &v
);
262 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
264 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
266 return bus_log_create_error(r
);
271 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
272 bool explicit_path
= false, done
= false, ambient_hack
= false;
273 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
274 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
275 ExecCommandFlags flags
= 0;
276 bool is_ex_prop
= endswith(field
, "Ex");
283 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
286 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
295 explicit_path
= true;
301 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
304 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
310 if ((flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
)) != 0 || ambient_hack
)
313 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
319 if (FLAGS_SET(flags
, EXEC_COMMAND_FULLY_PRIVILEGED
) || ambient_hack
)
321 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
322 /* Compatibility with the old !! ambient caps hack (removed in v258). Since
323 * we don't support that anymore and !! was a noop on non-supporting systems,
324 * we'll just turn off the EXEC_COMMAND_NO_SETUID flag again and be done with
326 flags
&= ~EXEC_COMMAND_NO_SETUID
;
330 log_notice("!! modifier for %s= fields is no longer supported and is now ignored.", field
);
332 flags
|= EXEC_COMMAND_NO_SETUID
;
338 if (FLAGS_SET(flags
, EXEC_COMMAND_VIA_SHELL
))
341 flags
|= EXEC_COMMAND_VIA_SHELL
;
351 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_VIA_SHELL
))) {
352 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
355 upgraded_name
= strjoin(field
, "Ex");
358 field
= upgraded_name
;
362 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
364 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
367 if (FLAGS_SET(flags
, EXEC_COMMAND_VIA_SHELL
)) {
368 path
= strdup(_PATH_BSHELL
);
372 } else if (explicit_path
) {
373 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
375 return log_error_errno(r
, "Failed to parse path: %m");
377 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "No executable path specified, refusing.");
379 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Got empty command line, refusing.");
382 r
= strv_split_full(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
384 return log_error_errno(r
, "Failed to parse command line: %m");
386 if (FLAGS_SET(flags
, EXEC_COMMAND_VIA_SHELL
)) {
387 r
= strv_prepend(&l
, explicit_path
? "-sh" : "sh");
392 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
394 return bus_log_create_error(r
);
396 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
398 return bus_log_create_error(r
);
400 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
402 return bus_log_create_error(r
);
404 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
406 return bus_log_create_error(r
);
408 if (!strv_isempty(l
)) {
410 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
412 return bus_log_create_error(r
);
414 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
416 return bus_log_create_error(r
);
418 r
= sd_bus_message_append_strv(m
, l
);
420 return bus_log_create_error(r
);
422 r
= is_ex_prop
? sd_bus_message_append_strv(m
, ex_opts
) : sd_bus_message_append(m
, "b", FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
));
424 return bus_log_create_error(r
);
426 r
= sd_bus_message_close_container(m
);
428 return bus_log_create_error(r
);
431 r
= sd_bus_message_close_container(m
);
433 return bus_log_create_error(r
);
435 r
= sd_bus_message_close_container(m
);
437 return bus_log_create_error(r
);
439 r
= sd_bus_message_close_container(m
);
441 return bus_log_create_error(r
);
446 static int bus_append_open_file(sd_bus_message
*m
, const char *field
, const char *eq
) {
447 _cleanup_(open_file_freep
) OpenFile
*of
= NULL
;
452 r
= open_file_parse(eq
, &of
);
454 return log_error_errno(r
, "Failed to parse OpenFile= setting: %m");
456 r
= sd_bus_message_append(m
, "(sv)", field
, "a(sst)", (size_t) 1, of
->path
, of
->fdname
, of
->flags
);
458 return bus_log_create_error(r
);
463 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
469 r
= sd_bus_message_open_container(m
, 'r', "iayu");
473 r
= sd_bus_message_append(m
, "i", family
);
477 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
481 r
= sd_bus_message_append(m
, "u", prefixlen
);
485 return sd_bus_message_close_container(m
);
488 static int bus_append_nft_set(sd_bus_message
*m
, const char *field
, const char *eq
) {
496 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iiss)", 0);
498 return bus_log_create_error(r
);
503 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
505 return bus_log_create_error(r
);
507 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
509 return bus_log_create_error(r
);
511 r
= sd_bus_message_open_container(m
, 'v', "a(iiss)");
513 return bus_log_create_error(r
);
515 r
= sd_bus_message_open_container(m
, 'a', "(iiss)");
517 return bus_log_create_error(r
);
519 for (const char *p
= eq
;;) {
520 _cleanup_free_
char *tuple
= NULL
, *source_str
= NULL
, *nfproto_str
= NULL
, *table
= NULL
, *set
= NULL
;
521 const char *q
= NULL
;
524 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
528 return log_error_errno(r
, "Failed to parse %s: %m", field
);
532 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse %s.", field
);
535 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
, &source_str
, &nfproto_str
, &table
, &set
);
538 if (r
!= 4 || !isempty(q
))
539 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse %s.", field
);
546 source
= nft_set_source_from_string(source_str
);
547 if (!IN_SET(source
, NFT_SET_SOURCE_CGROUP
, NFT_SET_SOURCE_USER
, NFT_SET_SOURCE_GROUP
))
548 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse %s.", field
);
550 nfproto
= nfproto_from_string(nfproto_str
);
551 if (nfproto
< 0 || !nft_identifier_valid(table
) || !nft_identifier_valid(set
))
552 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse %s.", field
);
554 r
= sd_bus_message_append(m
, "(iiss)", source
, nfproto
, table
, set
);
556 return bus_log_create_error(r
);
558 r
= sd_bus_message_close_container(m
);
560 return bus_log_create_error(r
);
562 r
= sd_bus_message_close_container(m
);
564 return bus_log_create_error(r
);
566 r
= sd_bus_message_close_container(m
);
568 return bus_log_create_error(r
);
573 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
576 if (STR_IN_SET(field
, "DevicePolicy",
579 "ManagedOOMMemoryPressure",
580 "ManagedOOMPreference",
581 "MemoryPressureWatch",
583 return bus_append_string(m
, field
, eq
);
585 if (STR_IN_SET(field
, "ManagedOOMMemoryPressureLimit")) {
586 r
= parse_permyriad(eq
);
588 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
590 /* Pass around scaled to 2^32-1 == 100% */
591 r
= sd_bus_message_append(m
, "(sv)", field
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
593 return bus_log_create_error(r
);
598 if (STR_IN_SET(field
, "MemoryAccounting",
599 "MemoryZSwapWriteback",
604 return bus_append_parse_boolean(m
, field
, eq
);
606 if (STR_IN_SET(field
, "CPUWeight",
608 return bus_append_cg_cpu_weight_parse(m
, field
, eq
);
610 if (STR_IN_SET(field
, "IOWeight",
612 return bus_append_cg_weight_parse(m
, field
, eq
);
614 if (STR_IN_SET(field
, "AllowedCPUs",
615 "StartupAllowedCPUs",
616 "AllowedMemoryNodes",
617 "StartupAllowedMemoryNodes")) {
619 _cleanup_(cpu_set_done
) CPUSet cpuset
= {};
620 _cleanup_free_
uint8_t *array
= NULL
;
623 r
= parse_cpu_set(eq
, &cpuset
);
625 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
627 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
629 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
631 return bus_append_byte_array(m
, field
, array
, allocated
);
634 if (streq(field
, "DisableControllers"))
635 return bus_append_strv(m
, "DisableControllers", eq
, /* separator= */ NULL
, EXTRACT_UNQUOTE
);
637 if (streq(field
, "Delegate")) {
638 r
= parse_boolean(eq
);
640 return bus_append_strv(m
, "DelegateControllers", eq
, /* separator= */ NULL
, EXTRACT_UNQUOTE
);
642 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
644 return bus_log_create_error(r
);
649 if (STR_IN_SET(field
, "MemoryMin",
659 if (streq(eq
, "infinity")) {
660 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
662 return bus_log_create_error(r
);
664 } else if (isempty(eq
)) {
665 uint64_t empty_value
= STR_IN_SET(field
,
673 r
= sd_bus_message_append(m
, "(sv)", field
, "t", empty_value
);
675 return bus_log_create_error(r
);
679 r
= parse_permyriad(eq
);
683 /* When this is a percentage we'll convert this into a relative value in the range
684 * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related ones). This
685 * way the physical memory size can be determined server-side. */
687 n
= strjoina(field
, "Scale");
688 r
= sd_bus_message_append(m
, "(sv)", n
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
690 return bus_log_create_error(r
);
695 if (streq(field
, "TasksMax"))
696 return bus_append_safe_atou64(m
, field
, eq
);
698 return bus_append_parse_size(m
, field
, eq
, 1024);
701 if (streq(field
, "CPUQuota")) {
703 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
705 r
= parse_permyriad_unbounded(eq
);
707 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
), "CPU quota too small.");
709 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
711 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 10000U));
715 return bus_log_create_error(r
);
720 if (streq(field
, "CPUQuotaPeriodSec")) {
721 usec_t u
= USEC_INFINITY
;
723 r
= parse_sec_def_infinity(eq
, &u
);
725 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
727 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
729 return bus_log_create_error(r
);
734 if (streq(field
, "DeviceAllow")) {
736 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
738 const char *path
= eq
, *rwm
= NULL
, *e
;
742 path
= strndupa_safe(eq
, e
- eq
);
746 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
750 return bus_log_create_error(r
);
755 if (cgroup_io_limit_type_from_string(field
) >= 0) {
758 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
760 const char *path
, *bandwidth
, *e
;
765 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
766 "Failed to parse %s value %s.",
769 path
= strndupa_safe(eq
, e
- eq
);
772 if (streq(bandwidth
, "infinity"))
773 bytes
= CGROUP_LIMIT_MAX
;
775 r
= parse_size(bandwidth
, 1000, &bytes
);
777 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
780 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
784 return bus_log_create_error(r
);
789 if (streq(field
, "IODeviceWeight")) {
791 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
793 const char *path
, *weight
, *e
;
798 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
799 "Failed to parse %s value %s.",
802 path
= strndupa_safe(eq
, e
- eq
);
805 r
= safe_atou64(weight
, &u
);
807 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
809 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
813 return bus_log_create_error(r
);
818 if (streq(field
, "IODeviceLatencyTargetSec")) {
819 const char *field_usec
= "IODeviceLatencyTargetUSec";
822 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
824 const char *path
, *target
, *e
;
829 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
830 "Failed to parse %s value %s.",
833 path
= strndupa_safe(eq
, e
- eq
);
836 r
= parse_sec(target
, &usec
);
838 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
840 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
844 return bus_log_create_error(r
);
849 if (STR_IN_SET(field
, "IPAddressAllow",
851 unsigned char prefixlen
;
852 union in_addr_union prefix
= {};
856 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
858 return bus_log_create_error(r
);
863 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
865 return bus_log_create_error(r
);
867 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
869 return bus_log_create_error(r
);
871 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
873 return bus_log_create_error(r
);
875 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
877 return bus_log_create_error(r
);
879 if (streq(eq
, "any")) {
880 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
882 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
884 return bus_log_create_error(r
);
886 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
888 return bus_log_create_error(r
);
890 } else if (is_localhost(eq
)) {
891 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
893 prefix
.in
.s_addr
= htobe32(0x7f000000);
894 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
896 return bus_log_create_error(r
);
898 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
899 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
903 } else if (streq(eq
, "link-local")) {
904 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
906 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
907 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
909 return bus_log_create_error(r
);
911 prefix
.in6
= (struct in6_addr
) {
912 .s6_addr32
[0] = htobe32(0xfe800000)
914 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
916 return bus_log_create_error(r
);
918 } else if (streq(eq
, "multicast")) {
919 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
921 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
922 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
924 return bus_log_create_error(r
);
926 prefix
.in6
= (struct in6_addr
) {
927 .s6_addr32
[0] = htobe32(0xff000000)
929 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
931 return bus_log_create_error(r
);
935 _cleanup_free_
char *word
= NULL
;
937 r
= extract_first_word(&eq
, &word
, NULL
, 0);
943 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
945 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
947 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
949 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
951 return bus_log_create_error(r
);
955 r
= sd_bus_message_close_container(m
);
957 return bus_log_create_error(r
);
959 r
= sd_bus_message_close_container(m
);
961 return bus_log_create_error(r
);
963 r
= sd_bus_message_close_container(m
);
965 return bus_log_create_error(r
);
970 if (STR_IN_SET(field
, "IPIngressFilterPath",
971 "IPEgressFilterPath")) {
973 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
975 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
978 return bus_log_create_error(r
);
983 if (streq(field
, "BPFProgram")) {
985 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
987 _cleanup_free_
char *word
= NULL
;
989 r
= extract_first_word(&eq
, &word
, ":", 0);
993 return log_error_errno(r
, "Failed to parse %s: %m", field
);
995 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, word
, eq
);
998 return bus_log_create_error(r
);
1003 if (STR_IN_SET(field
, "SocketBindAllow",
1004 "SocketBindDeny")) {
1006 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iiqq)", 0);
1008 int32_t family
, ip_protocol
;
1009 uint16_t nr_ports
, port_min
;
1011 r
= parse_socket_bind_item(eq
, &family
, &ip_protocol
, &nr_ports
, &port_min
);
1015 return log_error_errno(r
, "Failed to parse %s", field
);
1017 r
= sd_bus_message_append(
1018 m
, "(sv)", field
, "a(iiqq)", 1, family
, ip_protocol
, nr_ports
, port_min
);
1021 return bus_log_create_error(r
);
1026 if (streq(field
, "MemoryPressureThresholdSec"))
1027 return bus_append_parse_sec_rename(m
, field
, eq
);
1029 if (streq(field
, "NFTSet"))
1030 return bus_append_nft_set(m
, field
, eq
);
1032 if (streq(field
, "ManagedOOMMemoryPressureDurationSec"))
1033 /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which
1034 * means use the default memory pressure duration from oomd.conf. */
1035 return bus_append_parse_sec_rename(m
, field
, isempty(eq
) ? "infinity" : eq
);
1037 if (STR_IN_SET(field
,
1041 "BlockIOAccounting",
1043 "StartupBlockIOWeight",
1044 "BlockIODeviceWeight",
1045 "BlockIOReadBandwidth",
1046 "BlockIOWriteBandwidth",
1048 return warn_deprecated(field
, eq
);
1053 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1054 if (STR_IN_SET(field
, "Where",
1056 return bus_append_string(m
, field
, eq
);
1058 if (streq(field
, "DirectoryMode"))
1059 return bus_append_parse_mode(m
, field
, eq
);
1061 if (streq(field
, "TimeoutIdleSec"))
1062 return bus_append_parse_sec_rename(m
, field
, eq
);
1067 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1071 if (STR_IN_SET(field
, "User",
1084 "ProtectControlGroupsEx",
1088 "RuntimeDirectoryPreserve",
1093 "NetworkNamespacePath",
1098 "ExtensionImagePolicy",
1100 return bus_append_string(m
, field
, eq
);
1102 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
1113 "SyslogLevelPrefix",
1114 "MemoryDenyWriteExecute",
1118 "ProtectKernelTunables",
1119 "ProtectKernelModules",
1120 "ProtectKernelLogs",
1122 "ProtectControlGroups",
1125 "CPUSchedulingResetOnFork",
1131 "SetLoginEnvironment"))
1132 return bus_append_parse_boolean(m
, field
, eq
);
1134 if (STR_IN_SET(field
, "ReadWriteDirectories",
1135 "ReadOnlyDirectories",
1136 "InaccessibleDirectories",
1139 "InaccessiblePaths",
1143 "ExtensionDirectories",
1144 "ConfigurationDirectory",
1145 "SupplementaryGroups",
1146 "SystemCallArchitectures"))
1147 return bus_append_strv(m
, field
, eq
, /* separator= */ NULL
, EXTRACT_UNQUOTE
);
1149 if (STR_IN_SET(field
, "SyslogLevel",
1151 return bus_append_log_level_from_string(m
, field
, eq
);
1153 if (streq(field
, "SyslogFacility"))
1154 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
1156 if (streq(field
, "SecureBits"))
1157 return bus_append_secure_bits_from_string(m
, field
, eq
);
1159 if (streq(field
, "CPUSchedulingPolicy"))
1160 return bus_append_sched_policy_from_string(m
, field
, eq
);
1162 if (STR_IN_SET(field
, "CPUSchedulingPriority",
1164 return bus_append_safe_atoi(m
, field
, eq
);
1166 if (streq(field
, "CoredumpFilter"))
1167 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
1169 if (streq(field
, "Nice"))
1170 return bus_append_parse_nice(m
, field
, eq
);
1172 if (streq(field
, "SystemCallErrorNumber"))
1173 return bus_append_seccomp_parse_errno_or_action(m
, field
, eq
);
1175 if (streq(field
, "IOSchedulingClass"))
1176 return bus_append_ioprio_class_from_string(m
, field
, eq
);
1178 if (streq(field
, "IOSchedulingPriority"))
1179 return bus_append_ioprio_parse_priority(m
, field
, eq
);
1181 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
1182 "StateDirectoryMode",
1183 "CacheDirectoryMode",
1184 "LogsDirectoryMode",
1185 "ConfigurationDirectoryMode",
1187 return bus_append_parse_mode(m
, field
, eq
);
1189 if (streq(field
, "TimerSlackNSec"))
1190 return bus_append_parse_nsec(m
, field
, eq
);
1192 if (streq(field
, "LogRateLimitIntervalSec"))
1193 return bus_append_parse_sec_rename(m
, field
, eq
);
1195 if (STR_IN_SET(field
, "LogRateLimitBurst",
1198 return bus_append_safe_atou(m
, field
, eq
);
1200 if (streq(field
, "MountFlags"))
1201 return bus_append_mount_propagation_flag_from_string(m
, field
, eq
);
1203 if (STR_IN_SET(field
, "Environment",
1206 return bus_append_strv(m
, field
, eq
, /* separator= */ NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
1208 if (streq(field
, "EnvironmentFile")) {
1210 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1212 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1213 eq
[0] == '-' ? eq
+ 1 : eq
,
1216 return bus_log_create_error(r
);
1221 if (STR_IN_SET(field
, "SetCredential", "SetCredentialEncrypted")) {
1222 r
= sd_bus_message_open_container(m
, 'r', "sv");
1224 return bus_log_create_error(r
);
1226 r
= sd_bus_message_append_basic(m
, 's', field
);
1228 return bus_log_create_error(r
);
1230 r
= sd_bus_message_open_container(m
, 'v', "a(say)");
1232 return bus_log_create_error(r
);
1235 r
= sd_bus_message_append(m
, "a(say)", 0);
1237 _cleanup_free_
char *word
= NULL
;
1240 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1244 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1246 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1248 r
= sd_bus_message_open_container(m
, 'a', "(say)");
1250 return bus_log_create_error(r
);
1252 r
= sd_bus_message_open_container(m
, 'r', "say");
1254 return bus_log_create_error(r
);
1256 r
= sd_bus_message_append(m
, "s", word
);
1258 return bus_log_create_error(r
);
1260 if (streq(field
, "SetCredentialEncrypted")) {
1261 _cleanup_free_
void *decoded
= NULL
;
1262 size_t decoded_size
;
1264 r
= unbase64mem(p
, &decoded
, &decoded_size
);
1266 return log_error_errno(r
, "Failed to base64 decode encrypted credential: %m");
1268 r
= sd_bus_message_append_array(m
, 'y', decoded
, decoded_size
);
1270 _cleanup_free_
char *unescaped
= NULL
;
1273 l
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &unescaped
);
1275 return log_error_errno(l
, "Failed to unescape %s= value: %s", field
, p
);
1277 r
= sd_bus_message_append_array(m
, 'y', unescaped
, l
);
1280 return bus_log_create_error(r
);
1282 r
= sd_bus_message_close_container(m
);
1284 return bus_log_create_error(r
);
1286 r
= sd_bus_message_close_container(m
);
1289 return bus_log_create_error(r
);
1291 r
= sd_bus_message_close_container(m
);
1293 return bus_log_create_error(r
);
1295 r
= sd_bus_message_close_container(m
);
1297 return bus_log_create_error(r
);
1302 if (STR_IN_SET(field
, "LoadCredential", "LoadCredentialEncrypted")) {
1303 r
= sd_bus_message_open_container(m
, 'r', "sv");
1305 return bus_log_create_error(r
);
1307 r
= sd_bus_message_append_basic(m
, 's', field
);
1309 return bus_log_create_error(r
);
1311 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1313 return bus_log_create_error(r
);
1316 r
= sd_bus_message_append(m
, "a(ss)", 0);
1318 _cleanup_free_
char *word
= NULL
;
1321 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1325 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1327 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1329 if (isempty(p
)) /* If only one field is specified, then this means "inherit from above" */
1332 r
= sd_bus_message_append(m
, "a(ss)", 1, word
, p
);
1335 return bus_log_create_error(r
);
1337 r
= sd_bus_message_close_container(m
);
1339 return bus_log_create_error(r
);
1341 r
= sd_bus_message_close_container(m
);
1343 return bus_log_create_error(r
);
1348 if (streq(field
, "ImportCredential")) {
1350 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
1352 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
1354 return bus_log_create_error(r
);
1359 if (streq(field
, "ImportCredentialEx")) {
1360 r
= sd_bus_message_open_container(m
, 'r', "sv");
1362 return bus_log_create_error(r
);
1364 r
= sd_bus_message_append_basic(m
, 's', field
);
1366 return bus_log_create_error(r
);
1368 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1370 return bus_log_create_error(r
);
1373 r
= sd_bus_message_append(m
, "a(ss)", 0);
1375 _cleanup_free_
char *word
= NULL
;
1378 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1382 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1384 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1386 r
= sd_bus_message_append(m
, "a(ss)", 1, word
, p
);
1389 return bus_log_create_error(r
);
1391 r
= sd_bus_message_close_container(m
);
1393 return bus_log_create_error(r
);
1395 r
= sd_bus_message_close_container(m
);
1397 return bus_log_create_error(r
);
1402 if (streq(field
, "LogExtraFields")) {
1403 r
= sd_bus_message_open_container(m
, 'r', "sv");
1405 return bus_log_create_error(r
);
1407 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
1409 return bus_log_create_error(r
);
1411 r
= sd_bus_message_open_container(m
, 'v', "aay");
1413 return bus_log_create_error(r
);
1415 r
= sd_bus_message_open_container(m
, 'a', "ay");
1417 return bus_log_create_error(r
);
1419 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
1421 return bus_log_create_error(r
);
1423 r
= sd_bus_message_close_container(m
);
1425 return bus_log_create_error(r
);
1427 r
= sd_bus_message_close_container(m
);
1429 return bus_log_create_error(r
);
1431 r
= sd_bus_message_close_container(m
);
1433 return bus_log_create_error(r
);
1438 if (streq(field
, "LogFilterPatterns")) {
1439 r
= sd_bus_message_append(m
, "(sv)", "LogFilterPatterns", "a(bs)", 1,
1441 eq
[0] != '~' ? eq
: eq
+ 1);
1443 return bus_log_create_error(r
);
1448 if (STR_IN_SET(field
, "StandardInput",
1451 const char *n
, *appended
;
1453 if ((n
= startswith(eq
, "fd:"))) {
1454 appended
= strjoina(field
, "FileDescriptorName");
1455 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1456 } else if ((n
= startswith(eq
, "file:"))) {
1457 appended
= strjoina(field
, "File");
1458 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1459 } else if ((n
= startswith(eq
, "append:"))) {
1460 appended
= strjoina(field
, "FileToAppend");
1461 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1462 } else if ((n
= startswith(eq
, "truncate:"))) {
1463 appended
= strjoina(field
, "FileToTruncate");
1464 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1466 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1468 return bus_log_create_error(r
);
1473 if (streq(field
, "StandardInputText")) {
1474 _cleanup_free_
char *unescaped
= NULL
;
1477 l
= cunescape(eq
, 0, &unescaped
);
1479 return log_error_errno(l
, "Failed to unescape text '%s': %m", eq
);
1481 if (!strextend(&unescaped
, "\n"))
1484 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1485 * programmatic interface anyway */
1487 return bus_append_byte_array(m
, field
, unescaped
, l
+ 1);
1490 if (streq(field
, "StandardInputData")) {
1491 _cleanup_free_
void *decoded
= NULL
;
1494 r
= unbase64mem(eq
, &decoded
, &sz
);
1496 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1498 return bus_append_byte_array(m
, field
, decoded
, sz
);
1501 if ((suffix
= startswith(field
, "Limit"))) {
1504 rl
= rlimit_from_string(suffix
);
1509 r
= rlimit_parse(rl
, eq
, &l
);
1511 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1513 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) l
.rlim_max
);
1515 return bus_log_create_error(r
);
1517 sn
= strjoina(field
, "Soft");
1518 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", (uint64_t) l
.rlim_cur
);
1520 return bus_log_create_error(r
);
1526 if (STR_IN_SET(field
, "AppArmorProfile",
1527 "SmackProcessLabel")) {
1536 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1538 return bus_log_create_error(r
);
1543 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1544 "AmbientCapabilities")) {
1546 bool invert
= false;
1554 r
= capability_set_from_string(p
, &sum
);
1556 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1558 sum
= invert
? ~sum
: sum
;
1560 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1562 return bus_log_create_error(r
);
1567 if (streq(field
, "CPUAffinity")) {
1568 _cleanup_(cpu_set_done
) CPUSet cpuset
= {};
1569 _cleanup_free_
uint8_t *array
= NULL
;
1572 if (eq
&& streq(eq
, "numa")) {
1573 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1575 return bus_log_create_error(r
);
1579 r
= parse_cpu_set(eq
, &cpuset
);
1581 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1583 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1585 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1587 return bus_append_byte_array(m
, field
, array
, allocated
);
1590 if (streq(field
, "NUMAPolicy")) {
1591 r
= mpol_from_string(eq
);
1593 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1595 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1597 return bus_log_create_error(r
);
1602 if (streq(field
, "NUMAMask")) {
1603 _cleanup_(cpu_set_done
) CPUSet nodes
= {};
1604 _cleanup_free_
uint8_t *array
= NULL
;
1607 if (eq
&& streq(eq
, "all")) {
1608 r
= numa_mask_add_all(&nodes
);
1610 return log_error_errno(r
, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1612 r
= parse_cpu_set(eq
, &nodes
);
1614 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1617 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1619 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1621 return bus_append_byte_array(m
, field
, array
, allocated
);
1624 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1625 "RestrictFileSystems",
1628 "RestrictNetworkInterfaces")) {
1637 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1639 return bus_log_create_error(r
);
1641 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1643 return bus_log_create_error(r
);
1645 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1647 return bus_log_create_error(r
);
1649 r
= sd_bus_message_open_container(m
, 'r', "bas");
1651 return bus_log_create_error(r
);
1653 r
= sd_bus_message_append_basic(m
, 'b', &allow_list
);
1655 return bus_log_create_error(r
);
1657 r
= sd_bus_message_open_container(m
, 'a', "s");
1659 return bus_log_create_error(r
);
1662 _cleanup_free_
char *word
= NULL
;
1664 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1670 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1672 r
= sd_bus_message_append_basic(m
, 's', word
);
1674 return bus_log_create_error(r
);
1677 r
= sd_bus_message_close_container(m
);
1679 return bus_log_create_error(r
);
1681 r
= sd_bus_message_close_container(m
);
1683 return bus_log_create_error(r
);
1685 r
= sd_bus_message_close_container(m
);
1687 return bus_log_create_error(r
);
1689 r
= sd_bus_message_close_container(m
);
1691 return bus_log_create_error(r
);
1696 if (STR_IN_SET(field
, "RestrictNamespaces",
1697 "DelegateNamespaces")) {
1698 bool invert
= false;
1699 unsigned long all
= UPDATE_FLAG(NAMESPACE_FLAGS_ALL
, CLONE_NEWUSER
, !streq(field
, "DelegateNamespaces"));
1700 unsigned long flags
;
1702 r
= parse_boolean(eq
);
1704 /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
1705 * namespaces which are retained), so RestrictNamespaces=true means we retain no
1706 * access to any namespaces and vice-versa. */
1707 flags
= streq(field
, "RestrictNamespaces") ? 0 : all
;
1709 flags
= streq(field
, "RestrictNamespaces") ? all
: 0;
1716 r
= namespace_flags_from_string(eq
, &flags
);
1718 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1722 flags
= (~flags
) & all
;
1724 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1726 return bus_log_create_error(r
);
1731 if (STR_IN_SET(field
, "BindPaths",
1732 "BindReadOnlyPaths")) {
1735 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1737 return bus_log_create_error(r
);
1739 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1741 return bus_log_create_error(r
);
1743 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1745 return bus_log_create_error(r
);
1747 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1749 return bus_log_create_error(r
);
1752 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1753 char *s
= NULL
, *d
= NULL
;
1754 bool ignore_enoent
= false;
1755 uint64_t flags
= MS_REC
;
1757 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1759 return log_error_errno(r
, "Failed to parse argument: %m");
1765 ignore_enoent
= true;
1769 if (p
&& p
[-1] == ':') {
1770 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1772 return log_error_errno(r
, "Failed to parse argument: %m");
1774 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1775 "Missing argument after ':': %s",
1780 if (p
&& p
[-1] == ':') {
1781 _cleanup_free_
char *options
= NULL
;
1783 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1785 return log_error_errno(r
, "Failed to parse argument: %m");
1787 if (isempty(options
) || streq(options
, "rbind"))
1789 else if (streq(options
, "norbind"))
1792 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1793 "Unknown options: %s",
1799 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1801 return bus_log_create_error(r
);
1804 r
= sd_bus_message_close_container(m
);
1806 return bus_log_create_error(r
);
1808 r
= sd_bus_message_close_container(m
);
1810 return bus_log_create_error(r
);
1812 r
= sd_bus_message_close_container(m
);
1814 return bus_log_create_error(r
);
1819 if (streq(field
, "TemporaryFileSystem")) {
1822 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1824 return bus_log_create_error(r
);
1826 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1828 return bus_log_create_error(r
);
1830 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1832 return bus_log_create_error(r
);
1834 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1836 return bus_log_create_error(r
);
1839 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1842 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1844 return log_error_errno(r
, "Failed to parse argument: %m");
1849 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1851 return log_error_errno(r
, "Failed to parse argument: %m");
1853 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1854 "Failed to parse argument: %s",
1857 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1859 return bus_log_create_error(r
);
1862 r
= sd_bus_message_close_container(m
);
1864 return bus_log_create_error(r
);
1866 r
= sd_bus_message_close_container(m
);
1868 return bus_log_create_error(r
);
1870 r
= sd_bus_message_close_container(m
);
1872 return bus_log_create_error(r
);
1877 if (streq(field
, "RootHash")) {
1878 _cleanup_free_
void *roothash_decoded
= NULL
;
1879 size_t roothash_decoded_size
= 0;
1881 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1882 if (path_is_absolute(eq
))
1883 return bus_append_string(m
, "RootHashPath", eq
);
1885 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1886 r
= unhexmem(eq
, &roothash_decoded
, &roothash_decoded_size
);
1888 return log_error_errno(r
, "Failed to decode RootHash= '%s': %m", eq
);
1889 if (roothash_decoded_size
< sizeof(sd_id128_t
))
1890 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "RootHash= '%s' is too short.", eq
);
1892 return bus_append_byte_array(m
, field
, roothash_decoded
, roothash_decoded_size
);
1895 if (streq(field
, "RootHashSignature")) {
1896 _cleanup_free_
void *roothash_sig_decoded
= NULL
;
1898 size_t roothash_sig_decoded_size
= 0;
1900 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1901 if (path_is_absolute(eq
))
1902 return bus_append_string(m
, "RootHashSignaturePath", eq
);
1904 if (!(value
= startswith(eq
, "base64:")))
1905 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:'.", eq
);
1907 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1908 r
= unbase64mem(value
, &roothash_sig_decoded
, &roothash_sig_decoded_size
);
1910 return log_error_errno(r
, "Failed to decode RootHashSignature= '%s': %m", eq
);
1912 return bus_append_byte_array(m
, field
, roothash_sig_decoded
, roothash_sig_decoded_size
);
1915 if (streq(field
, "RootImageOptions")) {
1916 _cleanup_strv_free_
char **l
= NULL
;
1919 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1921 return bus_log_create_error(r
);
1923 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1925 return bus_log_create_error(r
);
1927 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1929 return bus_log_create_error(r
);
1931 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1933 return bus_log_create_error(r
);
1935 r
= strv_split_colon_pairs(&l
, p
);
1937 return log_error_errno(r
, "Failed to parse argument: %m");
1939 STRV_FOREACH_PAIR(first
, second
, l
) {
1940 r
= sd_bus_message_append(m
, "(ss)",
1941 !isempty(*second
) ? *first
: "root",
1942 !isempty(*second
) ? *second
: *first
);
1944 return bus_log_create_error(r
);
1947 r
= sd_bus_message_close_container(m
);
1949 return bus_log_create_error(r
);
1951 r
= sd_bus_message_close_container(m
);
1953 return bus_log_create_error(r
);
1955 r
= sd_bus_message_close_container(m
);
1957 return bus_log_create_error(r
);
1962 if (streq(field
, "MountImages")) {
1965 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1967 return bus_log_create_error(r
);
1969 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1971 return bus_log_create_error(r
);
1973 r
= sd_bus_message_open_container(m
, 'v', "a(ssba(ss))");
1975 return bus_log_create_error(r
);
1977 r
= sd_bus_message_open_container(m
, 'a', "(ssba(ss))");
1979 return bus_log_create_error(r
);
1982 _cleanup_free_
char *first
= NULL
, *second
= NULL
, *tuple
= NULL
;
1983 const char *q
= NULL
, *source
= NULL
;
1984 bool permissive
= false;
1986 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1988 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1993 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &first
, &second
);
1995 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
2000 if (source
[0] == '-') {
2005 if (isempty(second
))
2006 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2007 "Missing argument after ':': %s",
2010 r
= sd_bus_message_open_container(m
, 'r', "ssba(ss)");
2012 return bus_log_create_error(r
);
2014 r
= sd_bus_message_append(m
, "ssb", source
, second
, permissive
);
2016 return bus_log_create_error(r
);
2018 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
2020 return bus_log_create_error(r
);
2023 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
2025 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
);
2027 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
2030 /* Single set of options, applying to the root partition/single filesystem */
2032 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
2034 return bus_log_create_error(r
);
2039 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
2041 return bus_log_create_error(r
);
2044 r
= sd_bus_message_close_container(m
);
2046 return bus_log_create_error(r
);
2048 r
= sd_bus_message_close_container(m
);
2050 return bus_log_create_error(r
);
2053 r
= sd_bus_message_close_container(m
);
2055 return bus_log_create_error(r
);
2057 r
= sd_bus_message_close_container(m
);
2059 return bus_log_create_error(r
);
2061 r
= sd_bus_message_close_container(m
);
2063 return bus_log_create_error(r
);
2068 if (streq(field
, "ExtensionImages")) {
2071 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2073 return bus_log_create_error(r
);
2075 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2077 return bus_log_create_error(r
);
2079 r
= sd_bus_message_open_container(m
, 'v', "a(sba(ss))");
2081 return bus_log_create_error(r
);
2083 r
= sd_bus_message_open_container(m
, 'a', "(sba(ss))");
2085 return bus_log_create_error(r
);
2088 _cleanup_free_
char *source
= NULL
, *tuple
= NULL
;
2089 const char *q
= NULL
, *s
= NULL
;
2090 bool permissive
= false;
2092 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
2094 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
2099 r
= extract_first_word(&q
, &source
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
);
2101 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
2111 r
= sd_bus_message_open_container(m
, 'r', "sba(ss)");
2113 return bus_log_create_error(r
);
2115 r
= sd_bus_message_append(m
, "sb", s
, permissive
);
2117 return bus_log_create_error(r
);
2119 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
2121 return bus_log_create_error(r
);
2124 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
2126 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
);
2128 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
2131 /* Single set of options, applying to the root partition/single filesystem */
2133 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
2135 return bus_log_create_error(r
);
2140 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
2142 return bus_log_create_error(r
);
2145 r
= sd_bus_message_close_container(m
);
2147 return bus_log_create_error(r
);
2149 r
= sd_bus_message_close_container(m
);
2151 return bus_log_create_error(r
);
2154 r
= sd_bus_message_close_container(m
);
2156 return bus_log_create_error(r
);
2158 r
= sd_bus_message_close_container(m
);
2160 return bus_log_create_error(r
);
2162 r
= sd_bus_message_close_container(m
);
2164 return bus_log_create_error(r
);
2169 if (STR_IN_SET(field
, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
2170 _cleanup_strv_free_
char **symlinks
= NULL
, **symlinks_ro
= NULL
, **sources
= NULL
, **sources_ro
= NULL
;
2173 /* Adding new directories is supported from both *DirectorySymlink methods and the
2174 * older ones, so first parse the input, and if we are given a new-style src:dst
2175 * tuple use the new method, else use the old one. */
2178 _cleanup_free_
char *tuple
= NULL
, *source
= NULL
, *dest
= NULL
, *flags
= NULL
;
2180 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
);
2182 return log_error_errno(r
, "Failed to parse argument: %m");
2186 const char *t
= tuple
;
2187 r
= extract_many_words(&t
, ":", EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
, &source
, &dest
, &flags
);
2189 return log_error_errno(r
?: SYNTHETIC_ERRNO(EINVAL
), "Failed to parse argument: %m");
2191 path_simplify(source
);
2193 if (isempty(dest
) && isempty(flags
)) {
2194 r
= strv_consume(&sources
, TAKE_PTR(source
));
2196 return bus_log_create_error(r
);
2197 } else if (isempty(flags
)) {
2198 path_simplify(dest
);
2199 r
= strv_consume_pair(&symlinks
, TAKE_PTR(source
), TAKE_PTR(dest
));
2203 ExecDirectoryFlags exec_directory_flags
= exec_directory_flags_from_string(flags
);
2204 if (exec_directory_flags
< 0 || (exec_directory_flags
& ~_EXEC_DIRECTORY_FLAGS_PUBLIC
) != 0)
2205 return log_error_errno(r
, "Failed to parse flags: %s", flags
);
2207 if (!isempty(dest
)) {
2208 path_simplify(dest
);
2209 r
= strv_consume_pair(&symlinks_ro
, TAKE_PTR(source
), TAKE_PTR(dest
));
2211 r
= strv_consume(&sources_ro
, TAKE_PTR(source
));
2217 if (!strv_isempty(sources
)) {
2218 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2220 return bus_log_create_error(r
);
2222 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2224 return bus_log_create_error(r
);
2226 r
= sd_bus_message_open_container(m
, 'v', "as");
2228 return bus_log_create_error(r
);
2230 r
= sd_bus_message_append_strv(m
, sources
);
2232 return bus_log_create_error(r
);
2234 r
= sd_bus_message_close_container(m
);
2236 return bus_log_create_error(r
);
2238 r
= sd_bus_message_close_container(m
);
2240 return bus_log_create_error(r
);
2243 /* For State and Runtime directories we support an optional destination parameter, which
2244 * will be used to create a symlink to the source. But it is new so we cannot change the
2245 * old DBUS signatures, so append a new message type. */
2246 if (!strv_isempty(symlinks
) || !strv_isempty(symlinks_ro
) || !strv_isempty(sources_ro
)) {
2247 const char *symlink_field
;
2249 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2251 return bus_log_create_error(r
);
2253 if (streq(field
, "StateDirectory"))
2254 symlink_field
= "StateDirectorySymlink";
2255 else if (streq(field
, "RuntimeDirectory"))
2256 symlink_field
= "RuntimeDirectorySymlink";
2257 else if (streq(field
, "CacheDirectory"))
2258 symlink_field
= "CacheDirectorySymlink";
2259 else if (streq(field
, "LogsDirectory"))
2260 symlink_field
= "LogsDirectorySymlink";
2262 assert_not_reached();
2264 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, symlink_field
);
2266 return bus_log_create_error(r
);
2268 r
= sd_bus_message_open_container(m
, 'v', "a(sst)");
2270 return bus_log_create_error(r
);
2272 r
= sd_bus_message_open_container(m
, 'a', "(sst)");
2274 return bus_log_create_error(r
);
2276 STRV_FOREACH_PAIR(source
, destination
, symlinks
) {
2277 r
= sd_bus_message_append(m
, "(sst)", *source
, *destination
, UINT64_C(0));
2279 return bus_log_create_error(r
);
2282 STRV_FOREACH_PAIR(source
, destination
, symlinks_ro
) {
2283 r
= sd_bus_message_append(m
, "(sst)", *source
, *destination
, (uint64_t) EXEC_DIRECTORY_READ_ONLY
);
2285 return bus_log_create_error(r
);
2288 STRV_FOREACH(source
, sources_ro
) {
2289 r
= sd_bus_message_append(m
, "(sst)", *source
, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY
);
2291 return bus_log_create_error(r
);
2294 r
= sd_bus_message_close_container(m
);
2296 return bus_log_create_error(r
);
2298 r
= sd_bus_message_close_container(m
);
2300 return bus_log_create_error(r
);
2302 r
= sd_bus_message_close_container(m
);
2304 return bus_log_create_error(r
);
2310 if (streq(field
, "ProtectHostnameEx")) {
2311 const char *colon
= strchr(eq
, ':');
2313 if (isempty(colon
+ 1))
2314 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse argument: %s=%s", field
, eq
);
2316 _cleanup_free_
char *p
= strndup(eq
, colon
- eq
);
2320 r
= sd_bus_message_append(m
, "(sv)", field
, "(ss)", p
, colon
+ 1);
2322 r
= sd_bus_message_append(m
, "(sv)", field
, "(ss)", eq
, NULL
);
2324 return bus_log_create_error(r
);
2331 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2332 if (streq(field
, "KillMode"))
2333 return bus_append_string(m
, field
, eq
);
2335 if (STR_IN_SET(field
, "SendSIGHUP",
2337 return bus_append_parse_boolean(m
, field
, eq
);
2339 if (STR_IN_SET(field
, "KillSignal",
2340 "RestartKillSignal",
2344 return bus_append_signal_from_string(m
, field
, eq
);
2349 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2351 if (STR_IN_SET(field
, "What",
2355 return bus_append_string(m
, field
, eq
);
2357 if (streq(field
, "TimeoutSec"))
2358 return bus_append_parse_sec_rename(m
, field
, eq
);
2360 if (streq(field
, "DirectoryMode"))
2361 return bus_append_parse_mode(m
, field
, eq
);
2363 if (STR_IN_SET(field
, "SloppyOptions",
2367 return bus_append_parse_boolean(m
, field
, eq
);
2372 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2375 if (streq(field
, "MakeDirectory"))
2376 return bus_append_parse_boolean(m
, field
, eq
);
2378 if (streq(field
, "DirectoryMode"))
2379 return bus_append_parse_mode(m
, field
, eq
);
2381 if (STR_IN_SET(field
, "PathExists",
2385 "DirectoryNotEmpty")) {
2387 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
2389 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
2391 return bus_log_create_error(r
);
2396 if (STR_IN_SET(field
, "TriggerLimitBurst", "PollLimitBurst"))
2397 return bus_append_safe_atou(m
, field
, eq
);
2399 if (STR_IN_SET(field
, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
2400 return bus_append_parse_sec_rename(m
, field
, eq
);
2405 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2406 if (streq(field
, "RuntimeMaxSec"))
2407 return bus_append_parse_sec_rename(m
, field
, eq
);
2409 if (streq(field
, "RuntimeRandomizedExtraSec"))
2410 return bus_append_parse_sec_rename(m
, field
, eq
);
2412 if (streq(field
, "TimeoutStopSec"))
2413 return bus_append_parse_sec_rename(m
, field
, eq
);
2415 /* Scope units don't have execution context but we still want to allow setting these two,
2416 * so let's handle them separately. */
2417 if (STR_IN_SET(field
, "User", "Group"))
2418 return bus_append_string(m
, field
, eq
);
2420 if (streq(field
, "OOMPolicy"))
2421 return bus_append_string(m
, field
, eq
);
2426 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2429 if (STR_IN_SET(field
, "PIDFile",
2436 "USBFunctionDescriptors",
2437 "USBFunctionStrings",
2439 "TimeoutStartFailureMode",
2440 "TimeoutStopFailureMode",
2441 "FileDescriptorStorePreserve"))
2442 return bus_append_string(m
, field
, eq
);
2444 if (STR_IN_SET(field
, "PermissionsStartOnly",
2445 "RootDirectoryStartOnly",
2448 return bus_append_parse_boolean(m
, field
, eq
);
2450 if (STR_IN_SET(field
, "RestartSec",
2451 "RestartMaxDelaySec",
2456 "RuntimeRandomizedExtraSec",
2458 return bus_append_parse_sec_rename(m
, field
, eq
);
2460 if (streq(field
, "TimeoutSec")) {
2461 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
2465 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
2468 if (STR_IN_SET(field
, "FileDescriptorStoreMax",
2470 return bus_append_safe_atou(m
, field
, eq
);
2472 if (STR_IN_SET(field
, "ExecCondition",
2486 return bus_append_exec_command(m
, field
, eq
);
2488 if (STR_IN_SET(field
, "RestartPreventExitStatus",
2489 "RestartForceExitStatus",
2490 "SuccessExitStatus")) {
2491 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
2492 size_t n_status
= 0, n_signal
= 0;
2496 _cleanup_free_
char *word
= NULL
;
2498 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
2504 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
2506 /* We need to call exit_status_from_string() first, because we want
2507 * to parse numbers as exit statuses, not signals. */
2509 r
= exit_status_from_string(word
);
2511 assert(r
>= 0 && r
< 256);
2513 if (!GREEDY_REALLOC(status
, n_status
+ 1))
2516 status
[n_status
++] = r
;
2518 } else if ((r
= signal_from_string(word
)) >= 0) {
2519 if (!GREEDY_REALLOC(signal
, n_signal
+ 1))
2522 signal
[n_signal
++] = r
;
2525 /* original r from exit_status_to_string() */
2526 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
2530 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2532 return bus_log_create_error(r
);
2534 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2536 return bus_log_create_error(r
);
2538 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
2540 return bus_log_create_error(r
);
2542 r
= sd_bus_message_open_container(m
, 'r', "aiai");
2544 return bus_log_create_error(r
);
2546 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
2548 return bus_log_create_error(r
);
2550 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
2552 return bus_log_create_error(r
);
2554 r
= sd_bus_message_close_container(m
);
2556 return bus_log_create_error(r
);
2558 r
= sd_bus_message_close_container(m
);
2560 return bus_log_create_error(r
);
2562 r
= sd_bus_message_close_container(m
);
2564 return bus_log_create_error(r
);
2569 if (streq(field
, "OpenFile"))
2570 return bus_append_open_file(m
, field
, eq
);
2575 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2578 if (STR_IN_SET(field
, "Accept",
2590 "AcceptFileDescriptors",
2593 "PassFileDescriptorsToExec",
2594 "SELinuxContextFromNet"))
2595 return bus_append_parse_boolean(m
, field
, eq
);
2597 if (STR_IN_SET(field
, "Priority",
2600 return bus_append_safe_atoi(m
, field
, eq
);
2602 if (streq(field
, "IPTOS"))
2603 return bus_append_ip_tos_from_string(m
, field
, eq
);
2605 if (STR_IN_SET(field
, "Backlog",
2607 "MaxConnectionsPerSource",
2609 "TriggerLimitBurst",
2611 return bus_append_safe_atou(m
, field
, eq
);
2613 if (STR_IN_SET(field
, "SocketMode",
2615 return bus_append_parse_mode(m
, field
, eq
);
2617 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
2618 "MessageQueueMessageSize"))
2619 return bus_append_safe_atoi64(m
, field
, eq
);
2621 if (STR_IN_SET(field
, "TimeoutSec",
2623 "KeepAliveIntervalSec",
2625 "TriggerLimitIntervalSec",
2626 "PollLimitIntervalSec"))
2627 return bus_append_parse_sec_rename(m
, field
, eq
);
2629 if (STR_IN_SET(field
, "ReceiveBuffer",
2632 return bus_append_parse_size(m
, field
, eq
, 1024);
2634 if (STR_IN_SET(field
, "ExecStartPre",
2638 return bus_append_exec_command(m
, field
, eq
);
2640 if (STR_IN_SET(field
, "SmackLabel",
2646 "FileDescriptorName",
2650 return bus_append_string(m
, field
, eq
);
2652 if (streq(field
, "Symlinks"))
2653 return bus_append_strv(m
, field
, eq
, /* separator= */ NULL
, EXTRACT_UNQUOTE
);
2655 if (streq(field
, "SocketProtocol"))
2656 return bus_append_parse_ip_protocol(m
, field
, eq
);
2658 if (STR_IN_SET(field
, "ListenStream",
2660 "ListenSequentialPacket",
2663 "ListenMessageQueue",
2665 "ListenUSBFunction")) {
2667 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
2669 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
2671 return bus_log_create_error(r
);
2678 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2681 if (STR_IN_SET(field
, "WakeSystem",
2682 "RemainAfterElapse",
2687 "DeferReactivation"))
2688 return bus_append_parse_boolean(m
, field
, eq
);
2690 if (STR_IN_SET(field
, "AccuracySec",
2691 "RandomizedDelaySec",
2692 "RandomizedOffsetSec"))
2693 return bus_append_parse_sec_rename(m
, field
, eq
);
2695 if (STR_IN_SET(field
, "OnActiveSec",
2699 "OnUnitInactiveSec")) {
2701 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
2704 r
= parse_sec(eq
, &t
);
2706 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
2708 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
2711 return bus_log_create_error(r
);
2716 if (streq(field
, "OnCalendar")) {
2718 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
2720 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
2722 return bus_log_create_error(r
);
2730 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2731 ConditionType t
= _CONDITION_TYPE_INVALID
;
2732 bool is_condition
= false;
2735 if (STR_IN_SET(field
, "Description",
2739 "JobTimeoutRebootArgument",
2745 return bus_append_string(m
, field
, eq
);
2747 if (STR_IN_SET(field
, "StopWhenUnneeded",
2748 "RefuseManualStart",
2752 "SurviveFinalKillSignal",
2753 "DefaultDependencies"))
2754 return bus_append_parse_boolean(m
, field
, eq
);
2756 if (STR_IN_SET(field
, "JobTimeoutSec",
2757 "JobRunningTimeoutSec",
2758 "StartLimitIntervalSec"))
2759 return bus_append_parse_sec_rename(m
, field
, eq
);
2761 if (streq(field
, "StartLimitBurst"))
2762 return bus_append_safe_atou(m
, field
, eq
);
2764 if (STR_IN_SET(field
, "SuccessActionExitStatus",
2765 "FailureActionExitStatus")) {
2767 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
2771 r
= safe_atou8(eq
, &u
);
2773 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
2775 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
2778 return bus_log_create_error(r
);
2783 if (unit_dependency_from_string(field
) >= 0 ||
2784 STR_IN_SET(field
, "Documentation",
2785 "RequiresMountsFor",
2788 return bus_append_strv(m
, field
, eq
, /* separator= */ NULL
, EXTRACT_UNQUOTE
);
2790 t
= condition_type_from_string(field
);
2792 is_condition
= true;
2794 t
= assert_type_from_string(field
);
2797 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
2800 int trigger
, negate
;
2802 trigger
= *p
== '|';
2810 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
2811 field
, trigger
, negate
, p
);
2814 return bus_log_create_error(r
);
2822 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
2823 const char *eq
, *field
;
2829 eq
= strchr(assignment
, '=');
2831 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2832 "Not an assignment: %s", assignment
);
2834 field
= strndupa_safe(assignment
, eq
- assignment
);
2839 r
= bus_append_cgroup_property(m
, field
, eq
);
2843 r
= bus_append_execute_property(m
, field
, eq
);
2847 r
= bus_append_kill_property(m
, field
, eq
);
2851 r
= bus_append_service_property(m
, field
, eq
);
2857 r
= bus_append_cgroup_property(m
, field
, eq
);
2861 r
= bus_append_execute_property(m
, field
, eq
);
2865 r
= bus_append_kill_property(m
, field
, eq
);
2869 r
= bus_append_socket_property(m
, field
, eq
);
2875 r
= bus_append_timer_property(m
, field
, eq
);
2881 r
= bus_append_path_property(m
, field
, eq
);
2887 r
= bus_append_cgroup_property(m
, field
, eq
);
2893 r
= bus_append_cgroup_property(m
, field
, eq
);
2897 r
= bus_append_kill_property(m
, field
, eq
);
2901 r
= bus_append_scope_property(m
, field
, eq
);
2907 r
= bus_append_cgroup_property(m
, field
, eq
);
2911 r
= bus_append_execute_property(m
, field
, eq
);
2915 r
= bus_append_kill_property(m
, field
, eq
);
2919 r
= bus_append_mount_property(m
, field
, eq
);
2925 case UNIT_AUTOMOUNT
:
2926 r
= bus_append_automount_property(m
, field
, eq
);
2938 assert_not_reached();
2941 r
= bus_append_unit_property(m
, field
, eq
);
2945 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2946 "Unknown assignment: %s", assignment
);
2949 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char * const *l
) {
2954 STRV_FOREACH(i
, l
) {
2955 r
= bus_append_unit_property_assignment(m
, t
, *i
);
2963 int bus_append_scope_pidref(sd_bus_message
*m
, const PidRef
*pidref
, bool allow_pidfd
) {
2966 if (!pidref_is_set(pidref
))
2969 if (pidref
->fd
>= 0 && allow_pidfd
)
2970 return sd_bus_message_append(
2972 "PIDFDs", "ah", 1, pidref
->fd
);
2974 return sd_bus_message_append(
2976 "PIDs", "au", 1, pidref
->pid
);
2979 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
) {
2980 const char *type
, *path
, *source
;
2981 InstallChange
*changes
= NULL
;
2982 size_t n_changes
= 0;
2985 CLEANUP_ARRAY(changes
, n_changes
, install_changes_free
);
2987 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2989 return bus_log_parse_error(r
);
2991 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2992 InstallChangeType t
;
2994 /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2996 t
= install_change_type_from_string(type
);
2998 log_notice_errno(t
, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
3003 r
= install_changes_add(&changes
, &n_changes
, t
, path
, source
);
3008 return bus_log_parse_error(r
);
3010 r
= sd_bus_message_exit_container(m
);
3012 return bus_log_parse_error(r
);
3014 install_changes_dump(0, NULL
, changes
, n_changes
, quiet
);
3019 int unit_load_state(sd_bus
*bus
, const char *name
, char **ret
) {
3020 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
3021 _cleanup_free_
char *path
= NULL
;
3024 path
= unit_dbus_path_from_name(name
);
3028 /* This function warns on its own, because otherwise it'd be awkward to pass
3029 * the dbus error message around. */
3031 r
= sd_bus_get_property_string(
3033 "org.freedesktop.systemd1",
3035 "org.freedesktop.systemd1.Unit",
3040 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));
3045 int unit_info_compare(const UnitInfo
*a
, const UnitInfo
*b
) {
3048 /* First, order by machine */
3049 r
= strcasecmp_ptr(a
->machine
, b
->machine
);
3053 /* Second, order by unit type */
3054 r
= strcasecmp_ptr(strrchr(a
->id
, '.'), strrchr(b
->id
, '.'));
3058 /* Third, order by name */
3059 return strcasecmp(a
->id
, b
->id
);
3062 int bus_service_manager_reload(sd_bus
*bus
) {
3063 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
3064 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
3069 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "Reload");
3071 return bus_log_create_error(r
);
3073 /* Reloading the daemon may take long, hence set a longer timeout here */
3074 r
= sd_bus_call(bus
, m
, DAEMON_RELOAD_TIMEOUT_SEC
, &error
, NULL
);
3076 return log_error_errno(r
, "Failed to reload service manager: %s", bus_error_message(&error
, r
));
3081 typedef struct UnitFreezer
{
3086 /* Wait for 60 seconds at maximum for freezer operation */
3087 #define FREEZE_BUS_CALL_TIMEOUT (60 * USEC_PER_SEC)
3089 UnitFreezer
* unit_freezer_free(UnitFreezer
*f
) {
3094 sd_bus_flush_close_unref(f
->bus
);
3099 int unit_freezer_new(const char *name
, UnitFreezer
**ret
) {
3100 _cleanup_(unit_freezer_freep
) UnitFreezer
*f
= NULL
;
3106 f
= new(UnitFreezer
, 1);
3110 *f
= (UnitFreezer
) {
3111 .name
= strdup(name
),
3116 r
= bus_connect_system_systemd(&f
->bus
);
3118 return log_error_errno(r
, "Failed to open connection to systemd: %m");
3120 (void) sd_bus_set_method_call_timeout(f
->bus
, FREEZE_BUS_CALL_TIMEOUT
);
3126 static int unit_freezer_action(UnitFreezer
*f
, bool freeze
) {
3127 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
3134 r
= bus_call_method(f
->bus
, bus_systemd_mgr
,
3135 freeze
? "FreezeUnit" : "ThawUnit",
3137 /* ret_reply = */ NULL
,
3141 if (sd_bus_error_has_names(&error
,
3142 BUS_ERROR_NO_SUCH_UNIT
,
3143 BUS_ERROR_UNIT_INACTIVE
,
3144 SD_BUS_ERROR_NOT_SUPPORTED
)) {
3146 log_debug_errno(r
, "Skipping freezer for '%s': %s", f
->name
, bus_error_message(&error
, r
));
3150 return log_error_errno(r
, "Failed to %s unit '%s': %s",
3151 freeze
? "freeze" : "thaw", f
->name
, bus_error_message(&error
, r
));
3154 log_info("Successfully %s unit '%s'.", freeze
? "froze" : "thawed", f
->name
);
3158 int unit_freezer_freeze(UnitFreezer
*f
) {
3159 return unit_freezer_action(f
, true);
3162 int unit_freezer_thaw(UnitFreezer
*f
) {
3163 return unit_freezer_action(f
, false);
3166 ExecDirectoryFlags
exec_directory_flags_from_string(const char *s
) {
3171 return EXEC_DIRECTORY_READ_ONLY
;
3173 return _EXEC_DIRECTORY_FLAGS_INVALID
;