1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "alloc-util.h"
6 #include "bus-unit-util.h"
9 #include "cgroup-setup.h"
10 #include "cgroup-util.h"
11 #include "condition.h"
12 #include "coredump-util.h"
13 #include "cpu-set-util.h"
14 #include "dissect-image.h"
16 #include "exec-util.h"
17 #include "exit-status.h"
19 #include "hexdecoct.h"
20 #include "hostname-util.h"
21 #include "in-addr-util.h"
22 #include "ioprio-util.h"
23 #include "ip-protocol-list.h"
24 #include "libmount-util.h"
25 #include "locale-util.h"
28 #include "missing_fs.h"
29 #include "mountpoint-util.h"
31 #include "numa-util.h"
32 #include "open-file.h"
33 #include "parse-helpers.h"
34 #include "parse-util.h"
35 #include "path-util.h"
36 #include "percent-util.h"
37 #include "process-util.h"
38 #include "rlimit-util.h"
40 #include "seccomp-util.h"
42 #include "securebits-util.h"
43 #include "signal-util.h"
44 #include "socket-util.h"
45 #include "sort-util.h"
46 #include "stdio-util.h"
47 #include "string-util.h"
48 #include "syslog-util.h"
49 #include "terminal-util.h"
51 #include "user-util.h"
54 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
60 return sd_bus_message_read(
75 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
76 static int bus_append_##parse_func( \
83 r = parse_func(eq, &val); \
85 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
87 r = sd_bus_message_append(m, "(sv)", field, \
88 bus_type, (cast_type) val); \
90 return bus_log_create_error(r); \
95 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
96 static int bus_append_##parse_func( \
102 r = parse_func(eq); \
104 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
106 r = sd_bus_message_append(m, "(sv)", field, \
107 bus_type, (int32_t) r); \
109 return bus_log_create_error(r); \
114 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
115 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
116 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
117 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
118 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
120 static inline int seccomp_parse_errno_or_action(const char *eq
) { return -EINVAL
; }
122 DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action
);
123 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
124 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
125 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
126 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
127 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
128 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
129 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
130 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
131 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
132 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
133 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
134 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse
);
135 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flag_from_string
);
136 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
137 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
138 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
139 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
140 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
142 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
145 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
147 return bus_log_create_error(r
);
152 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
156 r
= sd_bus_message_open_container(m
, 'r', "sv");
158 return bus_log_create_error(r
);
160 r
= sd_bus_message_append_basic(m
, 's', field
);
162 return bus_log_create_error(r
);
164 r
= sd_bus_message_open_container(m
, 'v', "as");
166 return bus_log_create_error(r
);
168 r
= sd_bus_message_open_container(m
, 'a', "s");
170 return bus_log_create_error(r
);
173 _cleanup_free_
char *word
= NULL
;
175 r
= extract_first_word(&p
, &word
, NULL
, flags
);
181 return log_error_errno(r
, "Invalid syntax: %s", eq
);
183 r
= sd_bus_message_append_basic(m
, 's', word
);
185 return bus_log_create_error(r
);
188 r
= sd_bus_message_close_container(m
);
190 return bus_log_create_error(r
);
192 r
= sd_bus_message_close_container(m
);
194 return bus_log_create_error(r
);
196 r
= sd_bus_message_close_container(m
);
198 return bus_log_create_error(r
);
203 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
206 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
208 return bus_log_create_error(r
);
210 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
212 return bus_log_create_error(r
);
214 r
= sd_bus_message_open_container(m
, 'v', "ay");
216 return bus_log_create_error(r
);
218 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
220 return bus_log_create_error(r
);
222 r
= sd_bus_message_close_container(m
);
224 return bus_log_create_error(r
);
226 r
= sd_bus_message_close_container(m
);
228 return bus_log_create_error(r
);
233 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
239 r
= parse_sec(eq
, &t
);
241 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
244 n
= newa(char, l
+ 2);
245 /* Change suffix Sec → USec */
246 strcpy(mempcpy(n
, field
, l
- 3), "USec");
248 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
250 return bus_log_create_error(r
);
255 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
259 r
= parse_size(eq
, base
, &v
);
261 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
263 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
265 return bus_log_create_error(r
);
270 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
271 bool explicit_path
= false, done
= false;
272 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
273 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
274 ExecCommandFlags flags
= 0;
275 bool is_ex_prop
= endswith(field
, "Ex");
282 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
285 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
294 explicit_path
= true;
300 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
303 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
309 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
312 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
318 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
320 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
321 flags
&= ~EXEC_COMMAND_NO_SETUID
;
322 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
325 flags
|= EXEC_COMMAND_NO_SETUID
;
336 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
337 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
339 upgraded_name
= strjoin(field
, "Ex");
345 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
347 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
351 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
353 return log_error_errno(r
, "Failed to parse path: %m");
356 r
= strv_split_full(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
358 return log_error_errno(r
, "Failed to parse command line: %m");
360 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
362 return bus_log_create_error(r
);
364 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
366 return bus_log_create_error(r
);
368 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
370 return bus_log_create_error(r
);
372 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
374 return bus_log_create_error(r
);
376 if (!strv_isempty(l
)) {
378 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
380 return bus_log_create_error(r
);
382 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
384 return bus_log_create_error(r
);
386 r
= sd_bus_message_append_strv(m
, l
);
388 return bus_log_create_error(r
);
390 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
));
392 return bus_log_create_error(r
);
394 r
= sd_bus_message_close_container(m
);
396 return bus_log_create_error(r
);
399 r
= sd_bus_message_close_container(m
);
401 return bus_log_create_error(r
);
403 r
= sd_bus_message_close_container(m
);
405 return bus_log_create_error(r
);
407 r
= sd_bus_message_close_container(m
);
409 return bus_log_create_error(r
);
414 static int bus_append_open_file(sd_bus_message
*m
, const char *field
, const char *eq
) {
415 _cleanup_(open_file_freep
) OpenFile
*of
= NULL
;
420 r
= open_file_parse(eq
, &of
);
422 return log_error_errno(r
, "Failed to parse OpenFile= setting: %m");
424 r
= sd_bus_message_append(m
, "(sv)", field
, "a(sst)", (size_t) 1, of
->path
, of
->fdname
, of
->flags
);
426 return bus_log_create_error(r
);
431 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
437 r
= sd_bus_message_open_container(m
, 'r', "iayu");
441 r
= sd_bus_message_append(m
, "i", family
);
445 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
449 r
= sd_bus_message_append(m
, "u", prefixlen
);
453 return sd_bus_message_close_container(m
);
456 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
459 if (STR_IN_SET(field
, "DevicePolicy",
462 "ManagedOOMMemoryPressure",
463 "ManagedOOMPreference",
464 "MemoryPressureWatch",
466 return bus_append_string(m
, field
, eq
);
468 if (STR_IN_SET(field
, "ManagedOOMMemoryPressureLimit")) {
469 r
= parse_permyriad(eq
);
471 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
473 /* Pass around scaled to 2^32-1 == 100% */
474 r
= sd_bus_message_append(m
, "(sv)", field
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
476 return bus_log_create_error(r
);
481 if (STR_IN_SET(field
, "CPUAccounting",
487 return bus_append_parse_boolean(m
, field
, eq
);
489 if (STR_IN_SET(field
, "CPUWeight",
491 return bus_append_cg_cpu_weight_parse(m
, field
, eq
);
493 if (STR_IN_SET(field
, "IOWeight",
495 return bus_append_cg_weight_parse(m
, field
, eq
);
497 if (STR_IN_SET(field
, "CPUShares",
499 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
501 if (STR_IN_SET(field
, "AllowedCPUs",
502 "StartupAllowedCPUs",
503 "AllowedMemoryNodes",
504 "StartupAllowedMemoryNodes")) {
505 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
506 _cleanup_free_
uint8_t *array
= NULL
;
509 r
= parse_cpu_set(eq
, &cpuset
);
511 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
513 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
515 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
517 return bus_append_byte_array(m
, field
, array
, allocated
);
520 if (STR_IN_SET(field
, "BlockIOWeight",
521 "StartupBlockIOWeight"))
522 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
524 if (streq(field
, "DisableControllers"))
525 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
527 if (streq(field
, "Delegate")) {
528 r
= parse_boolean(eq
);
530 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
532 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
534 return bus_log_create_error(r
);
539 if (STR_IN_SET(field
, "MemoryMin",
550 if (streq(eq
, "infinity")) {
551 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
553 return bus_log_create_error(r
);
555 } else if (isempty(eq
)) {
556 uint64_t empty_value
= STR_IN_SET(field
,
564 r
= sd_bus_message_append(m
, "(sv)", field
, "t", empty_value
);
566 return bus_log_create_error(r
);
570 r
= parse_permyriad(eq
);
574 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
575 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
576 * size can be determined server-side. */
578 n
= strjoina(field
, "Scale");
579 r
= sd_bus_message_append(m
, "(sv)", n
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
581 return bus_log_create_error(r
);
586 if (streq(field
, "TasksMax"))
587 return bus_append_safe_atou64(m
, field
, eq
);
589 return bus_append_parse_size(m
, field
, eq
, 1024);
592 if (streq(field
, "CPUQuota")) {
594 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
596 r
= parse_permyriad_unbounded(eq
);
598 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
599 "CPU quota too small.");
601 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
603 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 10000U));
607 return bus_log_create_error(r
);
612 if (streq(field
, "CPUQuotaPeriodSec")) {
613 usec_t u
= USEC_INFINITY
;
615 r
= parse_sec_def_infinity(eq
, &u
);
617 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
619 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
621 return bus_log_create_error(r
);
626 if (streq(field
, "DeviceAllow")) {
628 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
630 const char *path
= eq
, *rwm
= NULL
, *e
;
634 path
= strndupa_safe(eq
, e
- eq
);
638 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
642 return bus_log_create_error(r
);
647 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
649 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
651 const char *path
, *bandwidth
, *e
;
656 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
657 "Failed to parse %s value %s.",
660 path
= strndupa_safe(eq
, e
- eq
);
663 if (streq(bandwidth
, "infinity"))
664 bytes
= CGROUP_LIMIT_MAX
;
666 r
= parse_size(bandwidth
, 1000, &bytes
);
668 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
671 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
675 return bus_log_create_error(r
);
680 if (STR_IN_SET(field
, "IODeviceWeight",
681 "BlockIODeviceWeight")) {
683 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
685 const char *path
, *weight
, *e
;
690 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
691 "Failed to parse %s value %s.",
694 path
= strndupa_safe(eq
, e
- eq
);
697 r
= safe_atou64(weight
, &u
);
699 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
701 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
705 return bus_log_create_error(r
);
710 if (streq(field
, "IODeviceLatencyTargetSec")) {
711 const char *field_usec
= "IODeviceLatencyTargetUSec";
714 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
716 const char *path
, *target
, *e
;
721 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
722 "Failed to parse %s value %s.",
725 path
= strndupa_safe(eq
, e
- eq
);
728 r
= parse_sec(target
, &usec
);
730 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
732 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
736 return bus_log_create_error(r
);
741 if (STR_IN_SET(field
, "IPAddressAllow",
743 unsigned char prefixlen
;
744 union in_addr_union prefix
= {};
748 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
750 return bus_log_create_error(r
);
755 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
757 return bus_log_create_error(r
);
759 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
761 return bus_log_create_error(r
);
763 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
765 return bus_log_create_error(r
);
767 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
769 return bus_log_create_error(r
);
771 if (streq(eq
, "any")) {
772 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
774 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
776 return bus_log_create_error(r
);
778 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
780 return bus_log_create_error(r
);
782 } else if (is_localhost(eq
)) {
783 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
785 prefix
.in
.s_addr
= htobe32(0x7f000000);
786 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
788 return bus_log_create_error(r
);
790 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
791 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
795 } else if (streq(eq
, "link-local")) {
796 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
798 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
799 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
801 return bus_log_create_error(r
);
803 prefix
.in6
= (struct in6_addr
) {
804 .s6_addr32
[0] = htobe32(0xfe800000)
806 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
808 return bus_log_create_error(r
);
810 } else if (streq(eq
, "multicast")) {
811 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
813 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
814 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
816 return bus_log_create_error(r
);
818 prefix
.in6
= (struct in6_addr
) {
819 .s6_addr32
[0] = htobe32(0xff000000)
821 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
823 return bus_log_create_error(r
);
827 _cleanup_free_
char *word
= NULL
;
829 r
= extract_first_word(&eq
, &word
, NULL
, 0);
835 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
837 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
839 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
841 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
843 return bus_log_create_error(r
);
847 r
= sd_bus_message_close_container(m
);
849 return bus_log_create_error(r
);
851 r
= sd_bus_message_close_container(m
);
853 return bus_log_create_error(r
);
855 r
= sd_bus_message_close_container(m
);
857 return bus_log_create_error(r
);
862 if (STR_IN_SET(field
, "IPIngressFilterPath",
863 "IPEgressFilterPath")) {
865 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
867 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
870 return bus_log_create_error(r
);
875 if (streq(field
, "BPFProgram")) {
877 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
879 _cleanup_free_
char *word
= NULL
;
881 r
= extract_first_word(&eq
, &word
, ":", 0);
885 return log_error_errno(r
, "Failed to parse %s: %m", field
);
887 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, word
, eq
);
890 return bus_log_create_error(r
);
895 if (STR_IN_SET(field
, "SocketBindAllow",
898 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iiqq)", 0);
900 int32_t family
, ip_protocol
;
901 uint16_t nr_ports
, port_min
;
903 r
= parse_socket_bind_item(eq
, &family
, &ip_protocol
, &nr_ports
, &port_min
);
907 return log_error_errno(r
, "Failed to parse %s", field
);
909 r
= sd_bus_message_append(
910 m
, "(sv)", field
, "a(iiqq)", 1, family
, ip_protocol
, nr_ports
, port_min
);
913 return bus_log_create_error(r
);
918 if (streq(field
, "MemoryPressureThresholdSec"))
919 return bus_append_parse_sec_rename(m
, field
, eq
);
924 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
925 if (STR_IN_SET(field
, "Where",
927 return bus_append_string(m
, field
, eq
);
929 if (streq(field
, "DirectoryMode"))
930 return bus_append_parse_mode(m
, field
, eq
);
932 if (streq(field
, "TimeoutIdleSec"))
933 return bus_append_parse_sec_rename(m
, field
, eq
);
938 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
942 if (STR_IN_SET(field
, "User",
956 "RuntimeDirectoryPreserve",
961 "NetworkNamespacePath",
966 "ExtensionImagePolicy"))
967 return bus_append_string(m
, field
, eq
);
969 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
981 "MemoryDenyWriteExecute",
985 "ProtectKernelTunables",
986 "ProtectKernelModules",
989 "ProtectControlGroups",
991 "CPUSchedulingResetOnFork",
996 return bus_append_parse_boolean(m
, field
, eq
);
998 if (STR_IN_SET(field
, "ReadWriteDirectories",
999 "ReadOnlyDirectories",
1000 "InaccessibleDirectories",
1003 "InaccessiblePaths",
1007 "ExtensionDirectories",
1008 "ConfigurationDirectory",
1009 "SupplementaryGroups",
1010 "SystemCallArchitectures"))
1011 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1013 if (STR_IN_SET(field
, "SyslogLevel",
1015 return bus_append_log_level_from_string(m
, field
, eq
);
1017 if (streq(field
, "SyslogFacility"))
1018 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
1020 if (streq(field
, "SecureBits"))
1021 return bus_append_secure_bits_from_string(m
, field
, eq
);
1023 if (streq(field
, "CPUSchedulingPolicy"))
1024 return bus_append_sched_policy_from_string(m
, field
, eq
);
1026 if (STR_IN_SET(field
, "CPUSchedulingPriority",
1028 return bus_append_safe_atoi(m
, field
, eq
);
1030 if (streq(field
, "CoredumpFilter"))
1031 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
1033 if (streq(field
, "Nice"))
1034 return bus_append_parse_nice(m
, field
, eq
);
1036 if (streq(field
, "SystemCallErrorNumber"))
1037 return bus_append_seccomp_parse_errno_or_action(m
, field
, eq
);
1039 if (streq(field
, "IOSchedulingClass"))
1040 return bus_append_ioprio_class_from_string(m
, field
, eq
);
1042 if (streq(field
, "IOSchedulingPriority"))
1043 return bus_append_ioprio_parse_priority(m
, field
, eq
);
1045 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
1046 "StateDirectoryMode",
1047 "CacheDirectoryMode",
1048 "LogsDirectoryMode",
1049 "ConfigurationDirectoryMode",
1051 return bus_append_parse_mode(m
, field
, eq
);
1053 if (streq(field
, "TimerSlackNSec"))
1054 return bus_append_parse_nsec(m
, field
, eq
);
1056 if (streq(field
, "LogRateLimitIntervalSec"))
1057 return bus_append_parse_sec_rename(m
, field
, eq
);
1059 if (STR_IN_SET(field
, "LogRateLimitBurst",
1062 return bus_append_safe_atou(m
, field
, eq
);
1064 if (streq(field
, "MountFlags"))
1065 return bus_append_mount_propagation_flag_from_string(m
, field
, eq
);
1067 if (STR_IN_SET(field
, "Environment",
1070 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
1072 if (streq(field
, "EnvironmentFile")) {
1074 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1076 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1077 eq
[0] == '-' ? eq
+ 1 : eq
,
1080 return bus_log_create_error(r
);
1085 if (STR_IN_SET(field
, "SetCredential", "SetCredentialEncrypted")) {
1086 r
= sd_bus_message_open_container(m
, 'r', "sv");
1088 return bus_log_create_error(r
);
1090 r
= sd_bus_message_append_basic(m
, 's', field
);
1092 return bus_log_create_error(r
);
1094 r
= sd_bus_message_open_container(m
, 'v', "a(say)");
1096 return bus_log_create_error(r
);
1099 r
= sd_bus_message_append(m
, "a(say)", 0);
1101 _cleanup_free_
char *word
= NULL
;
1104 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1108 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1110 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1112 r
= sd_bus_message_open_container(m
, 'a', "(say)");
1114 return bus_log_create_error(r
);
1116 r
= sd_bus_message_open_container(m
, 'r', "say");
1118 return bus_log_create_error(r
);
1120 r
= sd_bus_message_append(m
, "s", word
);
1122 return bus_log_create_error(r
);
1124 if (streq(field
, "SetCredentialEncrypted")) {
1125 _cleanup_free_
void *decoded
= NULL
;
1126 size_t decoded_size
;
1128 r
= unbase64mem(p
, SIZE_MAX
, &decoded
, &decoded_size
);
1130 return log_error_errno(r
, "Failed to base64 decode encrypted credential: %m");
1132 r
= sd_bus_message_append_array(m
, 'y', decoded
, decoded_size
);
1134 _cleanup_free_
char *unescaped
= NULL
;
1137 l
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &unescaped
);
1139 return log_error_errno(l
, "Failed to unescape %s= value: %s", field
, p
);
1141 r
= sd_bus_message_append_array(m
, 'y', unescaped
, l
);
1144 return bus_log_create_error(r
);
1146 r
= sd_bus_message_close_container(m
);
1148 return bus_log_create_error(r
);
1150 r
= sd_bus_message_close_container(m
);
1153 return bus_log_create_error(r
);
1155 r
= sd_bus_message_close_container(m
);
1157 return bus_log_create_error(r
);
1159 r
= sd_bus_message_close_container(m
);
1161 return bus_log_create_error(r
);
1166 if (STR_IN_SET(field
, "LoadCredential", "LoadCredentialEncrypted")) {
1167 r
= sd_bus_message_open_container(m
, 'r', "sv");
1169 return bus_log_create_error(r
);
1171 r
= sd_bus_message_append_basic(m
, 's', field
);
1173 return bus_log_create_error(r
);
1175 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1177 return bus_log_create_error(r
);
1180 r
= sd_bus_message_append(m
, "a(ss)", 0);
1182 _cleanup_free_
char *word
= NULL
;
1185 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1189 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1191 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1193 if (isempty(p
)) /* If only one field is specified, then this means "inherit from above" */
1196 r
= sd_bus_message_append(m
, "a(ss)", 1, word
, p
);
1199 return bus_log_create_error(r
);
1201 r
= sd_bus_message_close_container(m
);
1203 return bus_log_create_error(r
);
1205 r
= sd_bus_message_close_container(m
);
1207 return bus_log_create_error(r
);
1212 if (streq(field
, "LogExtraFields")) {
1213 r
= sd_bus_message_open_container(m
, 'r', "sv");
1215 return bus_log_create_error(r
);
1217 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
1219 return bus_log_create_error(r
);
1221 r
= sd_bus_message_open_container(m
, 'v', "aay");
1223 return bus_log_create_error(r
);
1225 r
= sd_bus_message_open_container(m
, 'a', "ay");
1227 return bus_log_create_error(r
);
1229 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
1231 return bus_log_create_error(r
);
1233 r
= sd_bus_message_close_container(m
);
1235 return bus_log_create_error(r
);
1237 r
= sd_bus_message_close_container(m
);
1239 return bus_log_create_error(r
);
1241 r
= sd_bus_message_close_container(m
);
1243 return bus_log_create_error(r
);
1248 if (streq(field
, "LogFilterPatterns")) {
1249 r
= sd_bus_message_append(m
, "(sv)", "LogFilterPatterns", "a(bs)", 1,
1251 eq
[0] != '~' ? eq
: eq
+ 1);
1253 return bus_log_create_error(r
);
1258 if (STR_IN_SET(field
, "StandardInput",
1261 const char *n
, *appended
;
1263 if ((n
= startswith(eq
, "fd:"))) {
1264 appended
= strjoina(field
, "FileDescriptorName");
1265 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1266 } else if ((n
= startswith(eq
, "file:"))) {
1267 appended
= strjoina(field
, "File");
1268 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1269 } else if ((n
= startswith(eq
, "append:"))) {
1270 appended
= strjoina(field
, "FileToAppend");
1271 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1272 } else if ((n
= startswith(eq
, "truncate:"))) {
1273 appended
= strjoina(field
, "FileToTruncate");
1274 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1276 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1278 return bus_log_create_error(r
);
1283 if (streq(field
, "StandardInputText")) {
1284 _cleanup_free_
char *unescaped
= NULL
;
1287 l
= cunescape(eq
, 0, &unescaped
);
1289 return log_error_errno(l
, "Failed to unescape text '%s': %m", eq
);
1291 if (!strextend(&unescaped
, "\n"))
1294 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1295 * programmatic interface anyway */
1297 return bus_append_byte_array(m
, field
, unescaped
, l
+ 1);
1300 if (streq(field
, "StandardInputData")) {
1301 _cleanup_free_
void *decoded
= NULL
;
1304 r
= unbase64mem(eq
, SIZE_MAX
, &decoded
, &sz
);
1306 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1308 return bus_append_byte_array(m
, field
, decoded
, sz
);
1311 if ((suffix
= startswith(field
, "Limit"))) {
1314 rl
= rlimit_from_string(suffix
);
1319 r
= rlimit_parse(rl
, eq
, &l
);
1321 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1323 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
1325 return bus_log_create_error(r
);
1327 sn
= strjoina(field
, "Soft");
1328 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1330 return bus_log_create_error(r
);
1336 if (STR_IN_SET(field
, "AppArmorProfile",
1337 "SmackProcessLabel")) {
1346 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1348 return bus_log_create_error(r
);
1353 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1354 "AmbientCapabilities")) {
1356 bool invert
= false;
1364 r
= capability_set_from_string(p
, &sum
);
1366 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1368 sum
= invert
? ~sum
: sum
;
1370 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1372 return bus_log_create_error(r
);
1377 if (streq(field
, "CPUAffinity")) {
1378 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1379 _cleanup_free_
uint8_t *array
= NULL
;
1382 if (eq
&& streq(eq
, "numa")) {
1383 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1385 return bus_log_create_error(r
);
1389 r
= parse_cpu_set(eq
, &cpuset
);
1391 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1393 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1395 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1397 return bus_append_byte_array(m
, field
, array
, allocated
);
1400 if (streq(field
, "NUMAPolicy")) {
1401 r
= mpol_from_string(eq
);
1403 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1405 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1407 return bus_log_create_error(r
);
1412 if (streq(field
, "NUMAMask")) {
1413 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1414 _cleanup_free_
uint8_t *array
= NULL
;
1417 if (eq
&& streq(eq
, "all")) {
1418 r
= numa_mask_add_all(&nodes
);
1420 return log_error_errno(r
, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1422 r
= parse_cpu_set(eq
, &nodes
);
1424 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1427 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1429 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1431 return bus_append_byte_array(m
, field
, array
, allocated
);
1434 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1435 "RestrictFileSystems",
1438 "RestrictNetworkInterfaces")) {
1447 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1449 return bus_log_create_error(r
);
1451 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1453 return bus_log_create_error(r
);
1455 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1457 return bus_log_create_error(r
);
1459 r
= sd_bus_message_open_container(m
, 'r', "bas");
1461 return bus_log_create_error(r
);
1463 r
= sd_bus_message_append_basic(m
, 'b', &allow_list
);
1465 return bus_log_create_error(r
);
1467 r
= sd_bus_message_open_container(m
, 'a', "s");
1469 return bus_log_create_error(r
);
1472 _cleanup_free_
char *word
= NULL
;
1474 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1480 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1482 r
= sd_bus_message_append_basic(m
, 's', word
);
1484 return bus_log_create_error(r
);
1487 r
= sd_bus_message_close_container(m
);
1489 return bus_log_create_error(r
);
1491 r
= sd_bus_message_close_container(m
);
1493 return bus_log_create_error(r
);
1495 r
= sd_bus_message_close_container(m
);
1497 return bus_log_create_error(r
);
1499 r
= sd_bus_message_close_container(m
);
1501 return bus_log_create_error(r
);
1506 if (streq(field
, "RestrictNamespaces")) {
1507 bool invert
= false;
1508 unsigned long flags
;
1510 r
= parse_boolean(eq
);
1514 flags
= NAMESPACE_FLAGS_ALL
;
1521 r
= namespace_flags_from_string(eq
, &flags
);
1523 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1527 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1529 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1531 return bus_log_create_error(r
);
1536 if (STR_IN_SET(field
, "BindPaths",
1537 "BindReadOnlyPaths")) {
1540 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1542 return bus_log_create_error(r
);
1544 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1546 return bus_log_create_error(r
);
1548 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1550 return bus_log_create_error(r
);
1552 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1554 return bus_log_create_error(r
);
1557 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1558 char *s
= NULL
, *d
= NULL
;
1559 bool ignore_enoent
= false;
1560 uint64_t flags
= MS_REC
;
1562 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1564 return log_error_errno(r
, "Failed to parse argument: %m");
1570 ignore_enoent
= true;
1574 if (p
&& p
[-1] == ':') {
1575 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1577 return log_error_errno(r
, "Failed to parse argument: %m");
1579 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1580 "Missing argument after ':': %s",
1585 if (p
&& p
[-1] == ':') {
1586 _cleanup_free_
char *options
= NULL
;
1588 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1590 return log_error_errno(r
, "Failed to parse argument: %m");
1592 if (isempty(options
) || streq(options
, "rbind"))
1594 else if (streq(options
, "norbind"))
1597 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1598 "Unknown options: %s",
1604 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1606 return bus_log_create_error(r
);
1609 r
= sd_bus_message_close_container(m
);
1611 return bus_log_create_error(r
);
1613 r
= sd_bus_message_close_container(m
);
1615 return bus_log_create_error(r
);
1617 r
= sd_bus_message_close_container(m
);
1619 return bus_log_create_error(r
);
1624 if (streq(field
, "TemporaryFileSystem")) {
1627 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1629 return bus_log_create_error(r
);
1631 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1633 return bus_log_create_error(r
);
1635 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1637 return bus_log_create_error(r
);
1639 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1641 return bus_log_create_error(r
);
1644 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1647 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1649 return log_error_errno(r
, "Failed to parse argument: %m");
1654 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1656 return log_error_errno(r
, "Failed to parse argument: %m");
1658 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1659 "Failed to parse argument: %s",
1662 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1664 return bus_log_create_error(r
);
1667 r
= sd_bus_message_close_container(m
);
1669 return bus_log_create_error(r
);
1671 r
= sd_bus_message_close_container(m
);
1673 return bus_log_create_error(r
);
1675 r
= sd_bus_message_close_container(m
);
1677 return bus_log_create_error(r
);
1682 if (streq(field
, "RootHash")) {
1683 _cleanup_free_
void *roothash_decoded
= NULL
;
1684 size_t roothash_decoded_size
= 0;
1686 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1687 if (path_is_absolute(eq
))
1688 return bus_append_string(m
, "RootHashPath", eq
);
1690 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1691 r
= unhexmem(eq
, strlen(eq
), &roothash_decoded
, &roothash_decoded_size
);
1693 return log_error_errno(r
, "Failed to decode RootHash= '%s': %m", eq
);
1694 if (roothash_decoded_size
< sizeof(sd_id128_t
))
1695 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "RootHash= '%s' is too short: %m", eq
);
1697 return bus_append_byte_array(m
, field
, roothash_decoded
, roothash_decoded_size
);
1700 if (streq(field
, "RootHashSignature")) {
1701 _cleanup_free_
void *roothash_sig_decoded
= NULL
;
1703 size_t roothash_sig_decoded_size
= 0;
1705 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1706 if (path_is_absolute(eq
))
1707 return bus_append_string(m
, "RootHashSignaturePath", eq
);
1709 if (!(value
= startswith(eq
, "base64:")))
1710 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq
);
1712 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1713 r
= unbase64mem(value
, strlen(value
), &roothash_sig_decoded
, &roothash_sig_decoded_size
);
1715 return log_error_errno(r
, "Failed to decode RootHashSignature= '%s': %m", eq
);
1717 return bus_append_byte_array(m
, field
, roothash_sig_decoded
, roothash_sig_decoded_size
);
1720 if (streq(field
, "RootImageOptions")) {
1721 _cleanup_strv_free_
char **l
= NULL
;
1724 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1726 return bus_log_create_error(r
);
1728 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1730 return bus_log_create_error(r
);
1732 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1734 return bus_log_create_error(r
);
1736 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1738 return bus_log_create_error(r
);
1740 r
= strv_split_colon_pairs(&l
, p
);
1742 return log_error_errno(r
, "Failed to parse argument: %m");
1744 STRV_FOREACH_PAIR(first
, second
, l
) {
1745 r
= sd_bus_message_append(m
, "(ss)",
1746 !isempty(*second
) ? *first
: "root",
1747 !isempty(*second
) ? *second
: *first
);
1749 return bus_log_create_error(r
);
1752 r
= sd_bus_message_close_container(m
);
1754 return bus_log_create_error(r
);
1756 r
= sd_bus_message_close_container(m
);
1758 return bus_log_create_error(r
);
1760 r
= sd_bus_message_close_container(m
);
1762 return bus_log_create_error(r
);
1767 if (streq(field
, "MountImages")) {
1770 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1772 return bus_log_create_error(r
);
1774 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1776 return bus_log_create_error(r
);
1778 r
= sd_bus_message_open_container(m
, 'v', "a(ssba(ss))");
1780 return bus_log_create_error(r
);
1782 r
= sd_bus_message_open_container(m
, 'a', "(ssba(ss))");
1784 return bus_log_create_error(r
);
1787 _cleanup_free_
char *first
= NULL
, *second
= NULL
, *tuple
= NULL
;
1788 const char *q
= NULL
, *source
= NULL
;
1789 bool permissive
= false;
1791 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1793 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1798 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &first
, &second
, NULL
);
1800 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1805 if (source
[0] == '-') {
1810 if (isempty(second
))
1811 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1812 "Missing argument after ':': %s",
1815 r
= sd_bus_message_open_container(m
, 'r', "ssba(ss)");
1817 return bus_log_create_error(r
);
1819 r
= sd_bus_message_append(m
, "ssb", source
, second
, permissive
);
1821 return bus_log_create_error(r
);
1823 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1825 return bus_log_create_error(r
);
1828 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1830 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
1832 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1835 /* Single set of options, applying to the root partition/single filesystem */
1837 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1839 return bus_log_create_error(r
);
1844 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
1846 return bus_log_create_error(r
);
1849 r
= sd_bus_message_close_container(m
);
1851 return bus_log_create_error(r
);
1853 r
= sd_bus_message_close_container(m
);
1855 return bus_log_create_error(r
);
1858 r
= sd_bus_message_close_container(m
);
1860 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
);
1873 if (streq(field
, "ExtensionImages")) {
1876 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1878 return bus_log_create_error(r
);
1880 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1882 return bus_log_create_error(r
);
1884 r
= sd_bus_message_open_container(m
, 'v', "a(sba(ss))");
1886 return bus_log_create_error(r
);
1888 r
= sd_bus_message_open_container(m
, 'a', "(sba(ss))");
1890 return bus_log_create_error(r
);
1893 _cleanup_free_
char *source
= NULL
, *tuple
= NULL
;
1894 const char *q
= NULL
, *s
= NULL
;
1895 bool permissive
= false;
1897 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1899 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1904 r
= extract_first_word(&q
, &source
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
);
1906 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1916 r
= sd_bus_message_open_container(m
, 'r', "sba(ss)");
1918 return bus_log_create_error(r
);
1920 r
= sd_bus_message_append(m
, "sb", s
, permissive
);
1922 return bus_log_create_error(r
);
1924 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1926 return bus_log_create_error(r
);
1929 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1931 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
1933 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1936 /* Single set of options, applying to the root partition/single filesystem */
1938 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1940 return bus_log_create_error(r
);
1945 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
1947 return bus_log_create_error(r
);
1950 r
= sd_bus_message_close_container(m
);
1952 return bus_log_create_error(r
);
1954 r
= sd_bus_message_close_container(m
);
1956 return bus_log_create_error(r
);
1959 r
= sd_bus_message_close_container(m
);
1961 return bus_log_create_error(r
);
1963 r
= sd_bus_message_close_container(m
);
1965 return bus_log_create_error(r
);
1967 r
= sd_bus_message_close_container(m
);
1969 return bus_log_create_error(r
);
1974 if (STR_IN_SET(field
, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
1975 _cleanup_strv_free_
char **symlinks
= NULL
, **sources
= NULL
;
1978 /* Adding new directories is supported from both *DirectorySymlink methods and the
1979 * older ones, so first parse the input, and if we are given a new-style src:dst
1980 * tuple use the new method, else use the old one. */
1983 _cleanup_free_
char *tuple
= NULL
, *source
= NULL
, *destination
= NULL
;
1985 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
);
1987 return log_error_errno(r
, "Failed to parse argument: %m");
1991 const char *t
= tuple
;
1992 r
= extract_many_words(&t
, ":", EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
, &source
, &destination
, NULL
);
1994 return log_error_errno(r
?: SYNTHETIC_ERRNO(EINVAL
), "Failed to parse argument: %m");
1996 path_simplify(source
);
1998 if (isempty(destination
)) {
1999 r
= strv_consume(&sources
, TAKE_PTR(source
));
2001 return bus_log_create_error(r
);
2003 path_simplify(destination
);
2005 r
= strv_consume_pair(&symlinks
, TAKE_PTR(source
), TAKE_PTR(destination
));
2011 if (!strv_isempty(sources
)) {
2012 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2014 return bus_log_create_error(r
);
2016 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2018 return bus_log_create_error(r
);
2020 r
= sd_bus_message_open_container(m
, 'v', "as");
2022 return bus_log_create_error(r
);
2024 r
= sd_bus_message_append_strv(m
, sources
);
2026 return bus_log_create_error(r
);
2028 r
= sd_bus_message_close_container(m
);
2030 return bus_log_create_error(r
);
2032 r
= sd_bus_message_close_container(m
);
2034 return bus_log_create_error(r
);
2037 /* For State and Runtime directories we support an optional destination parameter, which
2038 * will be used to create a symlink to the source. But it is new so we cannot change the
2039 * old DBUS signatures, so append a new message type. */
2040 if (!strv_isempty(symlinks
)) {
2041 const char *symlink_field
;
2043 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2045 return bus_log_create_error(r
);
2047 if (streq(field
, "StateDirectory"))
2048 symlink_field
= "StateDirectorySymlink";
2049 else if (streq(field
, "RuntimeDirectory"))
2050 symlink_field
= "RuntimeDirectorySymlink";
2051 else if (streq(field
, "CacheDirectory"))
2052 symlink_field
= "CacheDirectorySymlink";
2053 else if (streq(field
, "LogsDirectory"))
2054 symlink_field
= "LogsDirectorySymlink";
2056 assert_not_reached();
2058 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, symlink_field
);
2060 return bus_log_create_error(r
);
2062 r
= sd_bus_message_open_container(m
, 'v', "a(sst)");
2064 return bus_log_create_error(r
);
2066 r
= sd_bus_message_open_container(m
, 'a', "(sst)");
2068 return bus_log_create_error(r
);
2070 STRV_FOREACH_PAIR(source
, destination
, symlinks
) {
2071 r
= sd_bus_message_append(m
, "(sst)", *source
, *destination
, 0);
2073 return bus_log_create_error(r
);
2076 r
= sd_bus_message_close_container(m
);
2078 return bus_log_create_error(r
);
2080 r
= sd_bus_message_close_container(m
);
2082 return bus_log_create_error(r
);
2084 r
= sd_bus_message_close_container(m
);
2086 return bus_log_create_error(r
);
2095 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2096 if (streq(field
, "KillMode"))
2097 return bus_append_string(m
, field
, eq
);
2099 if (STR_IN_SET(field
, "SendSIGHUP",
2101 return bus_append_parse_boolean(m
, field
, eq
);
2103 if (STR_IN_SET(field
, "KillSignal",
2104 "RestartKillSignal",
2108 return bus_append_signal_from_string(m
, field
, eq
);
2113 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2115 if (STR_IN_SET(field
, "What",
2119 return bus_append_string(m
, field
, eq
);
2121 if (streq(field
, "TimeoutSec"))
2122 return bus_append_parse_sec_rename(m
, field
, eq
);
2124 if (streq(field
, "DirectoryMode"))
2125 return bus_append_parse_mode(m
, field
, eq
);
2127 if (STR_IN_SET(field
, "SloppyOptions",
2131 return bus_append_parse_boolean(m
, field
, eq
);
2136 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2139 if (streq(field
, "MakeDirectory"))
2140 return bus_append_parse_boolean(m
, field
, eq
);
2142 if (streq(field
, "DirectoryMode"))
2143 return bus_append_parse_mode(m
, field
, eq
);
2145 if (STR_IN_SET(field
, "PathExists",
2149 "DirectoryNotEmpty")) {
2151 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
2153 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
2155 return bus_log_create_error(r
);
2160 if (streq(field
, "TriggerLimitBurst"))
2161 return bus_append_safe_atou(m
, field
, eq
);
2163 if (streq(field
, "TriggerLimitIntervalSec"))
2164 return bus_append_parse_sec_rename(m
, field
, eq
);
2169 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2170 if (streq(field
, "RuntimeMaxSec"))
2171 return bus_append_parse_sec_rename(m
, field
, eq
);
2173 if (streq(field
, "RuntimeRandomizedExtraSec"))
2174 return bus_append_parse_sec_rename(m
, field
, eq
);
2176 if (streq(field
, "TimeoutStopSec"))
2177 return bus_append_parse_sec_rename(m
, field
, eq
);
2179 /* Scope units don't have execution context but we still want to allow setting these two,
2180 * so let's handle them separately. */
2181 if (STR_IN_SET(field
, "User", "Group"))
2182 return bus_append_string(m
, field
, eq
);
2184 if (streq(field
, "OOMPolicy"))
2185 return bus_append_string(m
, field
, eq
);
2190 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2193 if (STR_IN_SET(field
, "PIDFile",
2199 "USBFunctionDescriptors",
2200 "USBFunctionStrings",
2202 "TimeoutStartFailureMode",
2203 "TimeoutStopFailureMode",
2204 "FileDescriptorStorePreserve"))
2205 return bus_append_string(m
, field
, eq
);
2207 if (STR_IN_SET(field
, "PermissionsStartOnly",
2208 "RootDirectoryStartOnly",
2211 return bus_append_parse_boolean(m
, field
, eq
);
2213 if (STR_IN_SET(field
, "RestartSec",
2214 "RestartMaxDelaySec",
2219 "RuntimeRandomizedExtraSec",
2221 return bus_append_parse_sec_rename(m
, field
, eq
);
2223 if (streq(field
, "TimeoutSec")) {
2224 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
2228 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
2231 if (STR_IN_SET(field
, "FileDescriptorStoreMax",
2233 return bus_append_safe_atou(m
, field
, eq
);
2235 if (STR_IN_SET(field
, "ExecCondition",
2249 return bus_append_exec_command(m
, field
, eq
);
2251 if (STR_IN_SET(field
, "RestartPreventExitStatus",
2252 "RestartForceExitStatus",
2253 "SuccessExitStatus")) {
2254 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
2255 size_t n_status
= 0, n_signal
= 0;
2259 _cleanup_free_
char *word
= NULL
;
2261 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
2267 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
2269 /* We need to call exit_status_from_string() first, because we want
2270 * to parse numbers as exit statuses, not signals. */
2272 r
= exit_status_from_string(word
);
2274 assert(r
>= 0 && r
< 256);
2276 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
2280 status
[n_status
++] = r
;
2282 } else if ((r
= signal_from_string(word
)) >= 0) {
2283 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
2287 signal
[n_signal
++] = r
;
2290 /* original r from exit_status_to_string() */
2291 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
2295 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2297 return bus_log_create_error(r
);
2299 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2301 return bus_log_create_error(r
);
2303 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
2305 return bus_log_create_error(r
);
2307 r
= sd_bus_message_open_container(m
, 'r', "aiai");
2309 return bus_log_create_error(r
);
2311 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
2313 return bus_log_create_error(r
);
2315 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
2317 return bus_log_create_error(r
);
2319 r
= sd_bus_message_close_container(m
);
2321 return bus_log_create_error(r
);
2323 r
= sd_bus_message_close_container(m
);
2325 return bus_log_create_error(r
);
2327 r
= sd_bus_message_close_container(m
);
2329 return bus_log_create_error(r
);
2334 if (streq(field
, "OpenFile"))
2335 return bus_append_open_file(m
, field
, eq
);
2340 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2343 if (STR_IN_SET(field
, "Accept",
2356 "SELinuxContextFromNet"))
2357 return bus_append_parse_boolean(m
, field
, eq
);
2359 if (STR_IN_SET(field
, "Priority",
2362 return bus_append_safe_atoi(m
, field
, eq
);
2364 if (streq(field
, "IPTOS"))
2365 return bus_append_ip_tos_from_string(m
, field
, eq
);
2367 if (STR_IN_SET(field
, "Backlog",
2369 "MaxConnectionsPerSource",
2371 "TriggerLimitBurst"))
2372 return bus_append_safe_atou(m
, field
, eq
);
2374 if (STR_IN_SET(field
, "SocketMode",
2376 return bus_append_parse_mode(m
, field
, eq
);
2378 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
2379 "MessageQueueMessageSize"))
2380 return bus_append_safe_atoi64(m
, field
, eq
);
2382 if (STR_IN_SET(field
, "TimeoutSec",
2384 "KeepAliveIntervalSec",
2386 "TriggerLimitIntervalSec"))
2387 return bus_append_parse_sec_rename(m
, field
, eq
);
2389 if (STR_IN_SET(field
, "ReceiveBuffer",
2392 return bus_append_parse_size(m
, field
, eq
, 1024);
2394 if (STR_IN_SET(field
, "ExecStartPre",
2398 return bus_append_exec_command(m
, field
, eq
);
2400 if (STR_IN_SET(field
, "SmackLabel",
2406 "FileDescriptorName",
2410 return bus_append_string(m
, field
, eq
);
2412 if (streq(field
, "Symlinks"))
2413 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2415 if (streq(field
, "SocketProtocol"))
2416 return bus_append_parse_ip_protocol(m
, field
, eq
);
2418 if (STR_IN_SET(field
, "ListenStream",
2420 "ListenSequentialPacket",
2423 "ListenMessageQueue",
2425 "ListenUSBFunction")) {
2427 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
2429 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
2431 return bus_log_create_error(r
);
2438 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2441 if (STR_IN_SET(field
, "WakeSystem",
2442 "RemainAfterElapse",
2446 "FixedRandomDelay"))
2447 return bus_append_parse_boolean(m
, field
, eq
);
2449 if (STR_IN_SET(field
, "AccuracySec",
2450 "RandomizedDelaySec"))
2451 return bus_append_parse_sec_rename(m
, field
, eq
);
2453 if (STR_IN_SET(field
, "OnActiveSec",
2457 "OnUnitInactiveSec")) {
2459 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
2462 r
= parse_sec(eq
, &t
);
2464 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
2466 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
2469 return bus_log_create_error(r
);
2474 if (streq(field
, "OnCalendar")) {
2476 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
2478 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
2480 return bus_log_create_error(r
);
2488 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2489 ConditionType t
= _CONDITION_TYPE_INVALID
;
2490 bool is_condition
= false;
2493 if (STR_IN_SET(field
, "Description",
2497 "JobTimeoutRebootArgument",
2503 return bus_append_string(m
, field
, eq
);
2505 if (STR_IN_SET(field
, "StopWhenUnneeded",
2506 "RefuseManualStart",
2510 "DefaultDependencies"))
2511 return bus_append_parse_boolean(m
, field
, eq
);
2513 if (STR_IN_SET(field
, "JobTimeoutSec",
2514 "JobRunningTimeoutSec",
2515 "StartLimitIntervalSec"))
2516 return bus_append_parse_sec_rename(m
, field
, eq
);
2518 if (streq(field
, "StartLimitBurst"))
2519 return bus_append_safe_atou(m
, field
, eq
);
2521 if (STR_IN_SET(field
, "SuccessActionExitStatus",
2522 "FailureActionExitStatus")) {
2524 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
2528 r
= safe_atou8(eq
, &u
);
2530 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
2532 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
2535 return bus_log_create_error(r
);
2540 if (unit_dependency_from_string(field
) >= 0 ||
2541 STR_IN_SET(field
, "Documentation",
2542 "RequiresMountsFor",
2544 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2546 t
= condition_type_from_string(field
);
2548 is_condition
= true;
2550 t
= assert_type_from_string(field
);
2553 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
2556 int trigger
, negate
;
2558 trigger
= *p
== '|';
2566 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
2567 field
, trigger
, negate
, p
);
2570 return bus_log_create_error(r
);
2578 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
2579 const char *eq
, *field
;
2585 eq
= strchr(assignment
, '=');
2587 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2588 "Not an assignment: %s", assignment
);
2590 field
= strndupa_safe(assignment
, eq
- assignment
);
2595 r
= bus_append_cgroup_property(m
, field
, eq
);
2599 r
= bus_append_execute_property(m
, field
, eq
);
2603 r
= bus_append_kill_property(m
, field
, eq
);
2607 r
= bus_append_service_property(m
, field
, eq
);
2613 r
= bus_append_cgroup_property(m
, field
, eq
);
2617 r
= bus_append_execute_property(m
, field
, eq
);
2621 r
= bus_append_kill_property(m
, field
, eq
);
2625 r
= bus_append_socket_property(m
, field
, eq
);
2631 r
= bus_append_timer_property(m
, field
, eq
);
2637 r
= bus_append_path_property(m
, field
, eq
);
2643 r
= bus_append_cgroup_property(m
, field
, eq
);
2649 r
= bus_append_cgroup_property(m
, field
, eq
);
2653 r
= bus_append_kill_property(m
, field
, eq
);
2657 r
= bus_append_scope_property(m
, field
, eq
);
2663 r
= bus_append_cgroup_property(m
, field
, eq
);
2667 r
= bus_append_execute_property(m
, field
, eq
);
2671 r
= bus_append_kill_property(m
, field
, eq
);
2675 r
= bus_append_mount_property(m
, field
, eq
);
2681 case UNIT_AUTOMOUNT
:
2682 r
= bus_append_automount_property(m
, field
, eq
);
2694 assert_not_reached();
2697 r
= bus_append_unit_property(m
, field
, eq
);
2701 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2702 "Unknown assignment: %s", assignment
);
2705 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
2710 STRV_FOREACH(i
, l
) {
2711 r
= bus_append_unit_property_assignment(m
, t
, *i
);
2719 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
) {
2720 const char *type
, *path
, *source
;
2721 InstallChange
*changes
= NULL
;
2722 size_t n_changes
= 0;
2725 CLEANUP_ARRAY(changes
, n_changes
, install_changes_free
);
2727 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2729 return bus_log_parse_error(r
);
2731 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2732 InstallChangeType t
;
2734 /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2736 t
= install_change_type_from_string(type
);
2738 log_notice_errno(t
, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2743 r
= install_changes_add(&changes
, &n_changes
, t
, path
, source
);
2748 return bus_log_parse_error(r
);
2750 r
= sd_bus_message_exit_container(m
);
2752 return bus_log_parse_error(r
);
2754 install_changes_dump(0, NULL
, changes
, n_changes
, quiet
);
2759 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2760 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2761 _cleanup_free_
char *path
= NULL
;
2764 path
= unit_dbus_path_from_name(name
);
2768 /* This function warns on its own, because otherwise it'd be awkward to pass
2769 * the dbus error message around. */
2771 r
= sd_bus_get_property_string(
2773 "org.freedesktop.systemd1",
2775 "org.freedesktop.systemd1.Unit",
2780 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));
2785 int unit_info_compare(const UnitInfo
*a
, const UnitInfo
*b
) {
2788 /* First, order by machine */
2789 r
= strcasecmp_ptr(a
->machine
, b
->machine
);
2793 /* Second, order by unit type */
2794 r
= strcasecmp_ptr(strrchr(a
->id
, '.'), strrchr(b
->id
, '.'));
2798 /* Third, order by name */
2799 return strcasecmp(a
->id
, b
->id
);