1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "alloc-util.h"
6 #include "bus-locator.h"
7 #include "bus-unit-util.h"
10 #include "cgroup-setup.h"
11 #include "cgroup-util.h"
12 #include "condition.h"
13 #include "coredump-util.h"
14 #include "cpu-set-util.h"
15 #include "dissect-image.h"
17 #include "exec-util.h"
18 #include "exit-status.h"
20 #include "hexdecoct.h"
21 #include "hostname-util.h"
22 #include "in-addr-util.h"
23 #include "ioprio-util.h"
24 #include "ip-protocol-list.h"
25 #include "libmount-util.h"
26 #include "locale-util.h"
29 #include "missing_fs.h"
30 #include "mountpoint-util.h"
32 #include "numa-util.h"
33 #include "open-file.h"
34 #include "parse-helpers.h"
35 #include "parse-util.h"
36 #include "path-util.h"
37 #include "percent-util.h"
38 #include "process-util.h"
39 #include "rlimit-util.h"
41 #include "seccomp-util.h"
43 #include "securebits-util.h"
44 #include "signal-util.h"
45 #include "socket-util.h"
46 #include "sort-util.h"
47 #include "stdio-util.h"
48 #include "string-util.h"
49 #include "syslog-util.h"
50 #include "terminal-util.h"
52 #include "user-util.h"
55 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
61 return sd_bus_message_read(
76 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
77 static int bus_append_##parse_func( \
84 r = parse_func(eq, &val); \
86 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
88 r = sd_bus_message_append(m, "(sv)", field, \
89 bus_type, (cast_type) val); \
91 return bus_log_create_error(r); \
96 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
97 static int bus_append_##parse_func( \
103 r = parse_func(eq); \
105 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
107 r = sd_bus_message_append(m, "(sv)", field, \
108 bus_type, (int32_t) r); \
110 return bus_log_create_error(r); \
115 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
116 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
117 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
118 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
119 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
121 static inline int seccomp_parse_errno_or_action(const char *eq
) { return -EINVAL
; }
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_blkio_weight_parse
);
133 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
134 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
135 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse
);
136 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flag_from_string
);
137 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
138 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
139 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
140 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
141 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
143 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
146 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
148 return bus_log_create_error(r
);
153 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, 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
);
174 _cleanup_free_
char *word
= NULL
;
176 r
= extract_first_word(&p
, &word
, NULL
, flags
);
182 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;
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
|EXEC_COMMAND_AMBIENT_MAGIC
))
313 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
319 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
321 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
322 flags
&= ~EXEC_COMMAND_NO_SETUID
;
323 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
326 flags
|= EXEC_COMMAND_NO_SETUID
;
337 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
338 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
340 upgraded_name
= strjoin(field
, "Ex");
346 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
348 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
352 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
354 return log_error_errno(r
, "Failed to parse path: %m");
357 r
= strv_split_full(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
359 return log_error_errno(r
, "Failed to parse command line: %m");
361 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
363 return bus_log_create_error(r
);
365 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
367 return bus_log_create_error(r
);
369 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
371 return bus_log_create_error(r
);
373 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
375 return bus_log_create_error(r
);
377 if (!strv_isempty(l
)) {
379 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
381 return bus_log_create_error(r
);
383 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
385 return bus_log_create_error(r
);
387 r
= sd_bus_message_append_strv(m
, l
);
389 return bus_log_create_error(r
);
391 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
));
393 return bus_log_create_error(r
);
395 r
= sd_bus_message_close_container(m
);
397 return bus_log_create_error(r
);
400 r
= sd_bus_message_close_container(m
);
402 return bus_log_create_error(r
);
404 r
= sd_bus_message_close_container(m
);
406 return bus_log_create_error(r
);
408 r
= sd_bus_message_close_container(m
);
410 return bus_log_create_error(r
);
415 static int bus_append_open_file(sd_bus_message
*m
, const char *field
, const char *eq
) {
416 _cleanup_(open_file_freep
) OpenFile
*of
= NULL
;
421 r
= open_file_parse(eq
, &of
);
423 return log_error_errno(r
, "Failed to parse OpenFile= setting: %m");
425 r
= sd_bus_message_append(m
, "(sv)", field
, "a(sst)", (size_t) 1, of
->path
, of
->fdname
, of
->flags
);
427 return bus_log_create_error(r
);
432 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
438 r
= sd_bus_message_open_container(m
, 'r', "iayu");
442 r
= sd_bus_message_append(m
, "i", family
);
446 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
450 r
= sd_bus_message_append(m
, "u", prefixlen
);
454 return sd_bus_message_close_container(m
);
457 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
460 if (STR_IN_SET(field
, "DevicePolicy",
463 "ManagedOOMMemoryPressure",
464 "ManagedOOMPreference",
465 "MemoryPressureWatch",
467 return bus_append_string(m
, field
, eq
);
469 if (STR_IN_SET(field
, "ManagedOOMMemoryPressureLimit")) {
470 r
= parse_permyriad(eq
);
472 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
474 /* Pass around scaled to 2^32-1 == 100% */
475 r
= sd_bus_message_append(m
, "(sv)", field
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
477 return bus_log_create_error(r
);
482 if (STR_IN_SET(field
, "CPUAccounting",
488 return bus_append_parse_boolean(m
, field
, eq
);
490 if (STR_IN_SET(field
, "CPUWeight",
492 return bus_append_cg_cpu_weight_parse(m
, field
, eq
);
494 if (STR_IN_SET(field
, "IOWeight",
496 return bus_append_cg_weight_parse(m
, field
, eq
);
498 if (STR_IN_SET(field
, "CPUShares",
500 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
502 if (STR_IN_SET(field
, "AllowedCPUs",
503 "StartupAllowedCPUs",
504 "AllowedMemoryNodes",
505 "StartupAllowedMemoryNodes")) {
506 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
507 _cleanup_free_
uint8_t *array
= NULL
;
510 r
= parse_cpu_set(eq
, &cpuset
);
512 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
514 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
516 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
518 return bus_append_byte_array(m
, field
, array
, allocated
);
521 if (STR_IN_SET(field
, "BlockIOWeight",
522 "StartupBlockIOWeight"))
523 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
525 if (streq(field
, "DisableControllers"))
526 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
528 if (streq(field
, "Delegate")) {
529 r
= parse_boolean(eq
);
531 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
533 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
535 return bus_log_create_error(r
);
540 if (STR_IN_SET(field
, "MemoryMin",
551 if (streq(eq
, "infinity")) {
552 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
554 return bus_log_create_error(r
);
556 } else if (isempty(eq
)) {
557 uint64_t empty_value
= STR_IN_SET(field
,
565 r
= sd_bus_message_append(m
, "(sv)", field
, "t", empty_value
);
567 return bus_log_create_error(r
);
571 r
= parse_permyriad(eq
);
575 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
576 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
577 * size can be determined server-side. */
579 n
= strjoina(field
, "Scale");
580 r
= sd_bus_message_append(m
, "(sv)", n
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
582 return bus_log_create_error(r
);
587 if (streq(field
, "TasksMax"))
588 return bus_append_safe_atou64(m
, field
, eq
);
590 return bus_append_parse_size(m
, field
, eq
, 1024);
593 if (streq(field
, "CPUQuota")) {
595 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
597 r
= parse_permyriad_unbounded(eq
);
599 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
600 "CPU quota too small.");
602 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
604 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 10000U));
608 return bus_log_create_error(r
);
613 if (streq(field
, "CPUQuotaPeriodSec")) {
614 usec_t u
= USEC_INFINITY
;
616 r
= parse_sec_def_infinity(eq
, &u
);
618 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
620 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
622 return bus_log_create_error(r
);
627 if (streq(field
, "DeviceAllow")) {
629 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
631 const char *path
= eq
, *rwm
= NULL
, *e
;
635 path
= strndupa_safe(eq
, e
- eq
);
639 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
643 return bus_log_create_error(r
);
648 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
650 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
652 const char *path
, *bandwidth
, *e
;
657 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
658 "Failed to parse %s value %s.",
661 path
= strndupa_safe(eq
, e
- eq
);
664 if (streq(bandwidth
, "infinity"))
665 bytes
= CGROUP_LIMIT_MAX
;
667 r
= parse_size(bandwidth
, 1000, &bytes
);
669 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
672 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
676 return bus_log_create_error(r
);
681 if (STR_IN_SET(field
, "IODeviceWeight",
682 "BlockIODeviceWeight")) {
684 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
686 const char *path
, *weight
, *e
;
691 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
692 "Failed to parse %s value %s.",
695 path
= strndupa_safe(eq
, e
- eq
);
698 r
= safe_atou64(weight
, &u
);
700 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
702 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
706 return bus_log_create_error(r
);
711 if (streq(field
, "IODeviceLatencyTargetSec")) {
712 const char *field_usec
= "IODeviceLatencyTargetUSec";
715 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
717 const char *path
, *target
, *e
;
722 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
723 "Failed to parse %s value %s.",
726 path
= strndupa_safe(eq
, e
- eq
);
729 r
= parse_sec(target
, &usec
);
731 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
733 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
737 return bus_log_create_error(r
);
742 if (STR_IN_SET(field
, "IPAddressAllow",
744 unsigned char prefixlen
;
745 union in_addr_union prefix
= {};
749 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
751 return bus_log_create_error(r
);
756 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
758 return bus_log_create_error(r
);
760 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
762 return bus_log_create_error(r
);
764 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
766 return bus_log_create_error(r
);
768 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
770 return bus_log_create_error(r
);
772 if (streq(eq
, "any")) {
773 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
775 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
777 return bus_log_create_error(r
);
779 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
781 return bus_log_create_error(r
);
783 } else if (is_localhost(eq
)) {
784 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
786 prefix
.in
.s_addr
= htobe32(0x7f000000);
787 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
789 return bus_log_create_error(r
);
791 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
792 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
796 } else if (streq(eq
, "link-local")) {
797 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
799 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
800 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
802 return bus_log_create_error(r
);
804 prefix
.in6
= (struct in6_addr
) {
805 .s6_addr32
[0] = htobe32(0xfe800000)
807 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
809 return bus_log_create_error(r
);
811 } else if (streq(eq
, "multicast")) {
812 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
814 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
815 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
817 return bus_log_create_error(r
);
819 prefix
.in6
= (struct in6_addr
) {
820 .s6_addr32
[0] = htobe32(0xff000000)
822 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
824 return bus_log_create_error(r
);
828 _cleanup_free_
char *word
= NULL
;
830 r
= extract_first_word(&eq
, &word
, NULL
, 0);
836 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
838 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
840 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
842 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
844 return bus_log_create_error(r
);
848 r
= sd_bus_message_close_container(m
);
850 return bus_log_create_error(r
);
852 r
= sd_bus_message_close_container(m
);
854 return bus_log_create_error(r
);
856 r
= sd_bus_message_close_container(m
);
858 return bus_log_create_error(r
);
863 if (STR_IN_SET(field
, "IPIngressFilterPath",
864 "IPEgressFilterPath")) {
866 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
868 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
871 return bus_log_create_error(r
);
876 if (streq(field
, "BPFProgram")) {
878 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
880 _cleanup_free_
char *word
= NULL
;
882 r
= extract_first_word(&eq
, &word
, ":", 0);
886 return log_error_errno(r
, "Failed to parse %s: %m", field
);
888 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, word
, eq
);
891 return bus_log_create_error(r
);
896 if (STR_IN_SET(field
, "SocketBindAllow",
899 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iiqq)", 0);
901 int32_t family
, ip_protocol
;
902 uint16_t nr_ports
, port_min
;
904 r
= parse_socket_bind_item(eq
, &family
, &ip_protocol
, &nr_ports
, &port_min
);
908 return log_error_errno(r
, "Failed to parse %s", field
);
910 r
= sd_bus_message_append(
911 m
, "(sv)", field
, "a(iiqq)", 1, family
, ip_protocol
, nr_ports
, port_min
);
914 return bus_log_create_error(r
);
919 if (streq(field
, "MemoryPressureThresholdSec"))
920 return bus_append_parse_sec_rename(m
, field
, eq
);
925 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
926 if (STR_IN_SET(field
, "Where",
928 return bus_append_string(m
, field
, eq
);
930 if (streq(field
, "DirectoryMode"))
931 return bus_append_parse_mode(m
, field
, eq
);
933 if (streq(field
, "TimeoutIdleSec"))
934 return bus_append_parse_sec_rename(m
, field
, eq
);
939 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
943 if (STR_IN_SET(field
, "User",
957 "RuntimeDirectoryPreserve",
962 "NetworkNamespacePath",
967 "ExtensionImagePolicy"))
968 return bus_append_string(m
, field
, eq
);
970 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
982 "MemoryDenyWriteExecute",
986 "ProtectKernelTunables",
987 "ProtectKernelModules",
990 "ProtectControlGroups",
992 "CPUSchedulingResetOnFork",
998 return bus_append_parse_boolean(m
, field
, eq
);
1000 if (STR_IN_SET(field
, "ReadWriteDirectories",
1001 "ReadOnlyDirectories",
1002 "InaccessibleDirectories",
1005 "InaccessiblePaths",
1009 "ExtensionDirectories",
1010 "ConfigurationDirectory",
1011 "SupplementaryGroups",
1012 "SystemCallArchitectures"))
1013 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1015 if (STR_IN_SET(field
, "SyslogLevel",
1017 return bus_append_log_level_from_string(m
, field
, eq
);
1019 if (streq(field
, "SyslogFacility"))
1020 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
1022 if (streq(field
, "SecureBits"))
1023 return bus_append_secure_bits_from_string(m
, field
, eq
);
1025 if (streq(field
, "CPUSchedulingPolicy"))
1026 return bus_append_sched_policy_from_string(m
, field
, eq
);
1028 if (STR_IN_SET(field
, "CPUSchedulingPriority",
1030 return bus_append_safe_atoi(m
, field
, eq
);
1032 if (streq(field
, "CoredumpFilter"))
1033 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
1035 if (streq(field
, "Nice"))
1036 return bus_append_parse_nice(m
, field
, eq
);
1038 if (streq(field
, "SystemCallErrorNumber"))
1039 return bus_append_seccomp_parse_errno_or_action(m
, field
, eq
);
1041 if (streq(field
, "IOSchedulingClass"))
1042 return bus_append_ioprio_class_from_string(m
, field
, eq
);
1044 if (streq(field
, "IOSchedulingPriority"))
1045 return bus_append_ioprio_parse_priority(m
, field
, eq
);
1047 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
1048 "StateDirectoryMode",
1049 "CacheDirectoryMode",
1050 "LogsDirectoryMode",
1051 "ConfigurationDirectoryMode",
1053 return bus_append_parse_mode(m
, field
, eq
);
1055 if (streq(field
, "TimerSlackNSec"))
1056 return bus_append_parse_nsec(m
, field
, eq
);
1058 if (streq(field
, "LogRateLimitIntervalSec"))
1059 return bus_append_parse_sec_rename(m
, field
, eq
);
1061 if (STR_IN_SET(field
, "LogRateLimitBurst",
1064 return bus_append_safe_atou(m
, field
, eq
);
1066 if (streq(field
, "MountFlags"))
1067 return bus_append_mount_propagation_flag_from_string(m
, field
, eq
);
1069 if (STR_IN_SET(field
, "Environment",
1072 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
1074 if (streq(field
, "EnvironmentFile")) {
1076 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1078 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1079 eq
[0] == '-' ? eq
+ 1 : eq
,
1082 return bus_log_create_error(r
);
1087 if (STR_IN_SET(field
, "SetCredential", "SetCredentialEncrypted")) {
1088 r
= sd_bus_message_open_container(m
, 'r', "sv");
1090 return bus_log_create_error(r
);
1092 r
= sd_bus_message_append_basic(m
, 's', field
);
1094 return bus_log_create_error(r
);
1096 r
= sd_bus_message_open_container(m
, 'v', "a(say)");
1098 return bus_log_create_error(r
);
1101 r
= sd_bus_message_append(m
, "a(say)", 0);
1103 _cleanup_free_
char *word
= NULL
;
1106 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1110 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1112 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1114 r
= sd_bus_message_open_container(m
, 'a', "(say)");
1116 return bus_log_create_error(r
);
1118 r
= sd_bus_message_open_container(m
, 'r', "say");
1120 return bus_log_create_error(r
);
1122 r
= sd_bus_message_append(m
, "s", word
);
1124 return bus_log_create_error(r
);
1126 if (streq(field
, "SetCredentialEncrypted")) {
1127 _cleanup_free_
void *decoded
= NULL
;
1128 size_t decoded_size
;
1130 r
= unbase64mem(p
, SIZE_MAX
, &decoded
, &decoded_size
);
1132 return log_error_errno(r
, "Failed to base64 decode encrypted credential: %m");
1134 r
= sd_bus_message_append_array(m
, 'y', decoded
, decoded_size
);
1136 _cleanup_free_
char *unescaped
= NULL
;
1139 l
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &unescaped
);
1141 return log_error_errno(l
, "Failed to unescape %s= value: %s", field
, p
);
1143 r
= sd_bus_message_append_array(m
, 'y', unescaped
, l
);
1146 return bus_log_create_error(r
);
1148 r
= sd_bus_message_close_container(m
);
1150 return bus_log_create_error(r
);
1152 r
= sd_bus_message_close_container(m
);
1155 return bus_log_create_error(r
);
1157 r
= sd_bus_message_close_container(m
);
1159 return bus_log_create_error(r
);
1161 r
= sd_bus_message_close_container(m
);
1163 return bus_log_create_error(r
);
1168 if (STR_IN_SET(field
, "LoadCredential", "LoadCredentialEncrypted")) {
1169 r
= sd_bus_message_open_container(m
, 'r', "sv");
1171 return bus_log_create_error(r
);
1173 r
= sd_bus_message_append_basic(m
, 's', field
);
1175 return bus_log_create_error(r
);
1177 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1179 return bus_log_create_error(r
);
1182 r
= sd_bus_message_append(m
, "a(ss)", 0);
1184 _cleanup_free_
char *word
= NULL
;
1187 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1191 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1193 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1195 if (isempty(p
)) /* If only one field is specified, then this means "inherit from above" */
1198 r
= sd_bus_message_append(m
, "a(ss)", 1, word
, p
);
1201 return bus_log_create_error(r
);
1203 r
= sd_bus_message_close_container(m
);
1205 return bus_log_create_error(r
);
1207 r
= sd_bus_message_close_container(m
);
1209 return bus_log_create_error(r
);
1214 if (streq(field
, "ImportCredential")) {
1216 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
1218 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
1220 return bus_log_create_error(r
);
1225 if (streq(field
, "LogExtraFields")) {
1226 r
= sd_bus_message_open_container(m
, 'r', "sv");
1228 return bus_log_create_error(r
);
1230 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
1232 return bus_log_create_error(r
);
1234 r
= sd_bus_message_open_container(m
, 'v', "aay");
1236 return bus_log_create_error(r
);
1238 r
= sd_bus_message_open_container(m
, 'a', "ay");
1240 return bus_log_create_error(r
);
1242 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
1244 return bus_log_create_error(r
);
1246 r
= sd_bus_message_close_container(m
);
1248 return bus_log_create_error(r
);
1250 r
= sd_bus_message_close_container(m
);
1252 return bus_log_create_error(r
);
1254 r
= sd_bus_message_close_container(m
);
1256 return bus_log_create_error(r
);
1261 if (streq(field
, "LogFilterPatterns")) {
1262 r
= sd_bus_message_append(m
, "(sv)", "LogFilterPatterns", "a(bs)", 1,
1264 eq
[0] != '~' ? eq
: eq
+ 1);
1266 return bus_log_create_error(r
);
1271 if (STR_IN_SET(field
, "StandardInput",
1274 const char *n
, *appended
;
1276 if ((n
= startswith(eq
, "fd:"))) {
1277 appended
= strjoina(field
, "FileDescriptorName");
1278 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1279 } else if ((n
= startswith(eq
, "file:"))) {
1280 appended
= strjoina(field
, "File");
1281 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1282 } else if ((n
= startswith(eq
, "append:"))) {
1283 appended
= strjoina(field
, "FileToAppend");
1284 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1285 } else if ((n
= startswith(eq
, "truncate:"))) {
1286 appended
= strjoina(field
, "FileToTruncate");
1287 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1289 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1291 return bus_log_create_error(r
);
1296 if (streq(field
, "StandardInputText")) {
1297 _cleanup_free_
char *unescaped
= NULL
;
1300 l
= cunescape(eq
, 0, &unescaped
);
1302 return log_error_errno(l
, "Failed to unescape text '%s': %m", eq
);
1304 if (!strextend(&unescaped
, "\n"))
1307 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1308 * programmatic interface anyway */
1310 return bus_append_byte_array(m
, field
, unescaped
, l
+ 1);
1313 if (streq(field
, "StandardInputData")) {
1314 _cleanup_free_
void *decoded
= NULL
;
1317 r
= unbase64mem(eq
, SIZE_MAX
, &decoded
, &sz
);
1319 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1321 return bus_append_byte_array(m
, field
, decoded
, sz
);
1324 if ((suffix
= startswith(field
, "Limit"))) {
1327 rl
= rlimit_from_string(suffix
);
1332 r
= rlimit_parse(rl
, eq
, &l
);
1334 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1336 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
1338 return bus_log_create_error(r
);
1340 sn
= strjoina(field
, "Soft");
1341 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1343 return bus_log_create_error(r
);
1349 if (STR_IN_SET(field
, "AppArmorProfile",
1350 "SmackProcessLabel")) {
1359 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1361 return bus_log_create_error(r
);
1366 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1367 "AmbientCapabilities")) {
1369 bool invert
= false;
1377 r
= capability_set_from_string(p
, &sum
);
1379 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1381 sum
= invert
? ~sum
: sum
;
1383 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1385 return bus_log_create_error(r
);
1390 if (streq(field
, "CPUAffinity")) {
1391 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1392 _cleanup_free_
uint8_t *array
= NULL
;
1395 if (eq
&& streq(eq
, "numa")) {
1396 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1398 return bus_log_create_error(r
);
1402 r
= parse_cpu_set(eq
, &cpuset
);
1404 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1406 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1408 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1410 return bus_append_byte_array(m
, field
, array
, allocated
);
1413 if (streq(field
, "NUMAPolicy")) {
1414 r
= mpol_from_string(eq
);
1416 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1418 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1420 return bus_log_create_error(r
);
1425 if (streq(field
, "NUMAMask")) {
1426 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1427 _cleanup_free_
uint8_t *array
= NULL
;
1430 if (eq
&& streq(eq
, "all")) {
1431 r
= numa_mask_add_all(&nodes
);
1433 return log_error_errno(r
, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1435 r
= parse_cpu_set(eq
, &nodes
);
1437 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1440 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1442 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1444 return bus_append_byte_array(m
, field
, array
, allocated
);
1447 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1448 "RestrictFileSystems",
1451 "RestrictNetworkInterfaces")) {
1460 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1462 return bus_log_create_error(r
);
1464 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1466 return bus_log_create_error(r
);
1468 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1470 return bus_log_create_error(r
);
1472 r
= sd_bus_message_open_container(m
, 'r', "bas");
1474 return bus_log_create_error(r
);
1476 r
= sd_bus_message_append_basic(m
, 'b', &allow_list
);
1478 return bus_log_create_error(r
);
1480 r
= sd_bus_message_open_container(m
, 'a', "s");
1482 return bus_log_create_error(r
);
1485 _cleanup_free_
char *word
= NULL
;
1487 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1493 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1495 r
= sd_bus_message_append_basic(m
, 's', word
);
1497 return bus_log_create_error(r
);
1500 r
= sd_bus_message_close_container(m
);
1502 return bus_log_create_error(r
);
1504 r
= sd_bus_message_close_container(m
);
1506 return bus_log_create_error(r
);
1508 r
= sd_bus_message_close_container(m
);
1510 return bus_log_create_error(r
);
1512 r
= sd_bus_message_close_container(m
);
1514 return bus_log_create_error(r
);
1519 if (streq(field
, "RestrictNamespaces")) {
1520 bool invert
= false;
1521 unsigned long flags
;
1523 r
= parse_boolean(eq
);
1527 flags
= NAMESPACE_FLAGS_ALL
;
1534 r
= namespace_flags_from_string(eq
, &flags
);
1536 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1540 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1542 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1544 return bus_log_create_error(r
);
1549 if (STR_IN_SET(field
, "BindPaths",
1550 "BindReadOnlyPaths")) {
1553 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1555 return bus_log_create_error(r
);
1557 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1559 return bus_log_create_error(r
);
1561 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1563 return bus_log_create_error(r
);
1565 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1567 return bus_log_create_error(r
);
1570 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1571 char *s
= NULL
, *d
= NULL
;
1572 bool ignore_enoent
= false;
1573 uint64_t flags
= MS_REC
;
1575 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1577 return log_error_errno(r
, "Failed to parse argument: %m");
1583 ignore_enoent
= true;
1587 if (p
&& p
[-1] == ':') {
1588 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1590 return log_error_errno(r
, "Failed to parse argument: %m");
1592 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1593 "Missing argument after ':': %s",
1598 if (p
&& p
[-1] == ':') {
1599 _cleanup_free_
char *options
= NULL
;
1601 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1603 return log_error_errno(r
, "Failed to parse argument: %m");
1605 if (isempty(options
) || streq(options
, "rbind"))
1607 else if (streq(options
, "norbind"))
1610 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1611 "Unknown options: %s",
1617 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1619 return bus_log_create_error(r
);
1622 r
= sd_bus_message_close_container(m
);
1624 return bus_log_create_error(r
);
1626 r
= sd_bus_message_close_container(m
);
1628 return bus_log_create_error(r
);
1630 r
= sd_bus_message_close_container(m
);
1632 return bus_log_create_error(r
);
1637 if (streq(field
, "TemporaryFileSystem")) {
1640 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1642 return bus_log_create_error(r
);
1644 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1646 return bus_log_create_error(r
);
1648 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1650 return bus_log_create_error(r
);
1652 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1654 return bus_log_create_error(r
);
1657 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1660 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1662 return log_error_errno(r
, "Failed to parse argument: %m");
1667 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1669 return log_error_errno(r
, "Failed to parse argument: %m");
1671 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1672 "Failed to parse argument: %s",
1675 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1677 return bus_log_create_error(r
);
1680 r
= sd_bus_message_close_container(m
);
1682 return bus_log_create_error(r
);
1684 r
= sd_bus_message_close_container(m
);
1686 return bus_log_create_error(r
);
1688 r
= sd_bus_message_close_container(m
);
1690 return bus_log_create_error(r
);
1695 if (streq(field
, "RootHash")) {
1696 _cleanup_free_
void *roothash_decoded
= NULL
;
1697 size_t roothash_decoded_size
= 0;
1699 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1700 if (path_is_absolute(eq
))
1701 return bus_append_string(m
, "RootHashPath", eq
);
1703 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1704 r
= unhexmem(eq
, strlen(eq
), &roothash_decoded
, &roothash_decoded_size
);
1706 return log_error_errno(r
, "Failed to decode RootHash= '%s': %m", eq
);
1707 if (roothash_decoded_size
< sizeof(sd_id128_t
))
1708 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "RootHash= '%s' is too short: %m", eq
);
1710 return bus_append_byte_array(m
, field
, roothash_decoded
, roothash_decoded_size
);
1713 if (streq(field
, "RootHashSignature")) {
1714 _cleanup_free_
void *roothash_sig_decoded
= NULL
;
1716 size_t roothash_sig_decoded_size
= 0;
1718 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1719 if (path_is_absolute(eq
))
1720 return bus_append_string(m
, "RootHashSignaturePath", eq
);
1722 if (!(value
= startswith(eq
, "base64:")))
1723 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq
);
1725 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1726 r
= unbase64mem(value
, strlen(value
), &roothash_sig_decoded
, &roothash_sig_decoded_size
);
1728 return log_error_errno(r
, "Failed to decode RootHashSignature= '%s': %m", eq
);
1730 return bus_append_byte_array(m
, field
, roothash_sig_decoded
, roothash_sig_decoded_size
);
1733 if (streq(field
, "RootImageOptions")) {
1734 _cleanup_strv_free_
char **l
= NULL
;
1737 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1739 return bus_log_create_error(r
);
1741 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1743 return bus_log_create_error(r
);
1745 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1747 return bus_log_create_error(r
);
1749 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1751 return bus_log_create_error(r
);
1753 r
= strv_split_colon_pairs(&l
, p
);
1755 return log_error_errno(r
, "Failed to parse argument: %m");
1757 STRV_FOREACH_PAIR(first
, second
, l
) {
1758 r
= sd_bus_message_append(m
, "(ss)",
1759 !isempty(*second
) ? *first
: "root",
1760 !isempty(*second
) ? *second
: *first
);
1762 return bus_log_create_error(r
);
1765 r
= sd_bus_message_close_container(m
);
1767 return bus_log_create_error(r
);
1769 r
= sd_bus_message_close_container(m
);
1771 return bus_log_create_error(r
);
1773 r
= sd_bus_message_close_container(m
);
1775 return bus_log_create_error(r
);
1780 if (streq(field
, "MountImages")) {
1783 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1785 return bus_log_create_error(r
);
1787 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1789 return bus_log_create_error(r
);
1791 r
= sd_bus_message_open_container(m
, 'v', "a(ssba(ss))");
1793 return bus_log_create_error(r
);
1795 r
= sd_bus_message_open_container(m
, 'a', "(ssba(ss))");
1797 return bus_log_create_error(r
);
1800 _cleanup_free_
char *first
= NULL
, *second
= NULL
, *tuple
= NULL
;
1801 const char *q
= NULL
, *source
= NULL
;
1802 bool permissive
= false;
1804 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1806 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1811 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &first
, &second
, NULL
);
1813 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1818 if (source
[0] == '-') {
1823 if (isempty(second
))
1824 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1825 "Missing argument after ':': %s",
1828 r
= sd_bus_message_open_container(m
, 'r', "ssba(ss)");
1830 return bus_log_create_error(r
);
1832 r
= sd_bus_message_append(m
, "ssb", source
, second
, permissive
);
1834 return bus_log_create_error(r
);
1836 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1838 return bus_log_create_error(r
);
1841 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1843 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
1845 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1848 /* Single set of options, applying to the root partition/single filesystem */
1850 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1852 return bus_log_create_error(r
);
1857 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
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
);
1871 r
= sd_bus_message_close_container(m
);
1873 return bus_log_create_error(r
);
1875 r
= sd_bus_message_close_container(m
);
1877 return bus_log_create_error(r
);
1879 r
= sd_bus_message_close_container(m
);
1881 return bus_log_create_error(r
);
1886 if (streq(field
, "ExtensionImages")) {
1889 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1891 return bus_log_create_error(r
);
1893 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1895 return bus_log_create_error(r
);
1897 r
= sd_bus_message_open_container(m
, 'v', "a(sba(ss))");
1899 return bus_log_create_error(r
);
1901 r
= sd_bus_message_open_container(m
, 'a', "(sba(ss))");
1903 return bus_log_create_error(r
);
1906 _cleanup_free_
char *source
= NULL
, *tuple
= NULL
;
1907 const char *q
= NULL
, *s
= NULL
;
1908 bool permissive
= false;
1910 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1912 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1917 r
= extract_first_word(&q
, &source
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
);
1919 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1929 r
= sd_bus_message_open_container(m
, 'r', "sba(ss)");
1931 return bus_log_create_error(r
);
1933 r
= sd_bus_message_append(m
, "sb", s
, permissive
);
1935 return bus_log_create_error(r
);
1937 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1939 return bus_log_create_error(r
);
1942 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1944 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
1946 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1949 /* Single set of options, applying to the root partition/single filesystem */
1951 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1953 return bus_log_create_error(r
);
1958 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
1960 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
);
1972 r
= sd_bus_message_close_container(m
);
1974 return bus_log_create_error(r
);
1976 r
= sd_bus_message_close_container(m
);
1978 return bus_log_create_error(r
);
1980 r
= sd_bus_message_close_container(m
);
1982 return bus_log_create_error(r
);
1987 if (STR_IN_SET(field
, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
1988 _cleanup_strv_free_
char **symlinks
= NULL
, **sources
= NULL
;
1991 /* Adding new directories is supported from both *DirectorySymlink methods and the
1992 * older ones, so first parse the input, and if we are given a new-style src:dst
1993 * tuple use the new method, else use the old one. */
1996 _cleanup_free_
char *tuple
= NULL
, *source
= NULL
, *destination
= NULL
;
1998 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
);
2000 return log_error_errno(r
, "Failed to parse argument: %m");
2004 const char *t
= tuple
;
2005 r
= extract_many_words(&t
, ":", EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
, &source
, &destination
, NULL
);
2007 return log_error_errno(r
?: SYNTHETIC_ERRNO(EINVAL
), "Failed to parse argument: %m");
2009 path_simplify(source
);
2011 if (isempty(destination
)) {
2012 r
= strv_consume(&sources
, TAKE_PTR(source
));
2014 return bus_log_create_error(r
);
2016 path_simplify(destination
);
2018 r
= strv_consume_pair(&symlinks
, TAKE_PTR(source
), TAKE_PTR(destination
));
2024 if (!strv_isempty(sources
)) {
2025 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2027 return bus_log_create_error(r
);
2029 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2031 return bus_log_create_error(r
);
2033 r
= sd_bus_message_open_container(m
, 'v', "as");
2035 return bus_log_create_error(r
);
2037 r
= sd_bus_message_append_strv(m
, sources
);
2039 return bus_log_create_error(r
);
2041 r
= sd_bus_message_close_container(m
);
2043 return bus_log_create_error(r
);
2045 r
= sd_bus_message_close_container(m
);
2047 return bus_log_create_error(r
);
2050 /* For State and Runtime directories we support an optional destination parameter, which
2051 * will be used to create a symlink to the source. But it is new so we cannot change the
2052 * old DBUS signatures, so append a new message type. */
2053 if (!strv_isempty(symlinks
)) {
2054 const char *symlink_field
;
2056 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2058 return bus_log_create_error(r
);
2060 if (streq(field
, "StateDirectory"))
2061 symlink_field
= "StateDirectorySymlink";
2062 else if (streq(field
, "RuntimeDirectory"))
2063 symlink_field
= "RuntimeDirectorySymlink";
2064 else if (streq(field
, "CacheDirectory"))
2065 symlink_field
= "CacheDirectorySymlink";
2066 else if (streq(field
, "LogsDirectory"))
2067 symlink_field
= "LogsDirectorySymlink";
2069 assert_not_reached();
2071 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, symlink_field
);
2073 return bus_log_create_error(r
);
2075 r
= sd_bus_message_open_container(m
, 'v', "a(sst)");
2077 return bus_log_create_error(r
);
2079 r
= sd_bus_message_open_container(m
, 'a', "(sst)");
2081 return bus_log_create_error(r
);
2083 STRV_FOREACH_PAIR(source
, destination
, symlinks
) {
2084 r
= sd_bus_message_append(m
, "(sst)", *source
, *destination
, 0);
2086 return bus_log_create_error(r
);
2089 r
= sd_bus_message_close_container(m
);
2091 return bus_log_create_error(r
);
2093 r
= sd_bus_message_close_container(m
);
2095 return bus_log_create_error(r
);
2097 r
= sd_bus_message_close_container(m
);
2099 return bus_log_create_error(r
);
2108 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2109 if (streq(field
, "KillMode"))
2110 return bus_append_string(m
, field
, eq
);
2112 if (STR_IN_SET(field
, "SendSIGHUP",
2114 return bus_append_parse_boolean(m
, field
, eq
);
2116 if (STR_IN_SET(field
, "KillSignal",
2117 "RestartKillSignal",
2121 return bus_append_signal_from_string(m
, field
, eq
);
2126 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2128 if (STR_IN_SET(field
, "What",
2132 return bus_append_string(m
, field
, eq
);
2134 if (streq(field
, "TimeoutSec"))
2135 return bus_append_parse_sec_rename(m
, field
, eq
);
2137 if (streq(field
, "DirectoryMode"))
2138 return bus_append_parse_mode(m
, field
, eq
);
2140 if (STR_IN_SET(field
, "SloppyOptions",
2144 return bus_append_parse_boolean(m
, field
, eq
);
2149 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2152 if (streq(field
, "MakeDirectory"))
2153 return bus_append_parse_boolean(m
, field
, eq
);
2155 if (streq(field
, "DirectoryMode"))
2156 return bus_append_parse_mode(m
, field
, eq
);
2158 if (STR_IN_SET(field
, "PathExists",
2162 "DirectoryNotEmpty")) {
2164 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
2166 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
2168 return bus_log_create_error(r
);
2173 if (streq(field
, "TriggerLimitBurst"))
2174 return bus_append_safe_atou(m
, field
, eq
);
2176 if (streq(field
, "TriggerLimitIntervalSec"))
2177 return bus_append_parse_sec_rename(m
, field
, eq
);
2182 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2183 if (streq(field
, "RuntimeMaxSec"))
2184 return bus_append_parse_sec_rename(m
, field
, eq
);
2186 if (streq(field
, "RuntimeRandomizedExtraSec"))
2187 return bus_append_parse_sec_rename(m
, field
, eq
);
2189 if (streq(field
, "TimeoutStopSec"))
2190 return bus_append_parse_sec_rename(m
, field
, eq
);
2192 /* Scope units don't have execution context but we still want to allow setting these two,
2193 * so let's handle them separately. */
2194 if (STR_IN_SET(field
, "User", "Group"))
2195 return bus_append_string(m
, field
, eq
);
2197 if (streq(field
, "OOMPolicy"))
2198 return bus_append_string(m
, field
, eq
);
2203 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2206 if (STR_IN_SET(field
, "PIDFile",
2213 "USBFunctionDescriptors",
2214 "USBFunctionStrings",
2216 "TimeoutStartFailureMode",
2217 "TimeoutStopFailureMode",
2218 "FileDescriptorStorePreserve"))
2219 return bus_append_string(m
, field
, eq
);
2221 if (STR_IN_SET(field
, "PermissionsStartOnly",
2222 "RootDirectoryStartOnly",
2225 return bus_append_parse_boolean(m
, field
, eq
);
2227 if (STR_IN_SET(field
, "RestartSec",
2228 "RestartMaxDelaySec",
2233 "RuntimeRandomizedExtraSec",
2235 return bus_append_parse_sec_rename(m
, field
, eq
);
2237 if (streq(field
, "TimeoutSec")) {
2238 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
2242 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
2245 if (STR_IN_SET(field
, "FileDescriptorStoreMax",
2247 return bus_append_safe_atou(m
, field
, eq
);
2249 if (STR_IN_SET(field
, "ExecCondition",
2263 return bus_append_exec_command(m
, field
, eq
);
2265 if (STR_IN_SET(field
, "RestartPreventExitStatus",
2266 "RestartForceExitStatus",
2267 "SuccessExitStatus")) {
2268 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
2269 size_t n_status
= 0, n_signal
= 0;
2273 _cleanup_free_
char *word
= NULL
;
2275 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
2281 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
2283 /* We need to call exit_status_from_string() first, because we want
2284 * to parse numbers as exit statuses, not signals. */
2286 r
= exit_status_from_string(word
);
2288 assert(r
>= 0 && r
< 256);
2290 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
2294 status
[n_status
++] = r
;
2296 } else if ((r
= signal_from_string(word
)) >= 0) {
2297 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
2301 signal
[n_signal
++] = r
;
2304 /* original r from exit_status_to_string() */
2305 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
2309 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2311 return bus_log_create_error(r
);
2313 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2315 return bus_log_create_error(r
);
2317 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
2319 return bus_log_create_error(r
);
2321 r
= sd_bus_message_open_container(m
, 'r', "aiai");
2323 return bus_log_create_error(r
);
2325 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
2327 return bus_log_create_error(r
);
2329 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
2331 return bus_log_create_error(r
);
2333 r
= sd_bus_message_close_container(m
);
2335 return bus_log_create_error(r
);
2337 r
= sd_bus_message_close_container(m
);
2339 return bus_log_create_error(r
);
2341 r
= sd_bus_message_close_container(m
);
2343 return bus_log_create_error(r
);
2348 if (streq(field
, "OpenFile"))
2349 return bus_append_open_file(m
, field
, eq
);
2354 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2357 if (STR_IN_SET(field
, "Accept",
2370 "SELinuxContextFromNet"))
2371 return bus_append_parse_boolean(m
, field
, eq
);
2373 if (STR_IN_SET(field
, "Priority",
2376 return bus_append_safe_atoi(m
, field
, eq
);
2378 if (streq(field
, "IPTOS"))
2379 return bus_append_ip_tos_from_string(m
, field
, eq
);
2381 if (STR_IN_SET(field
, "Backlog",
2383 "MaxConnectionsPerSource",
2385 "TriggerLimitBurst"))
2386 return bus_append_safe_atou(m
, field
, eq
);
2388 if (STR_IN_SET(field
, "SocketMode",
2390 return bus_append_parse_mode(m
, field
, eq
);
2392 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
2393 "MessageQueueMessageSize"))
2394 return bus_append_safe_atoi64(m
, field
, eq
);
2396 if (STR_IN_SET(field
, "TimeoutSec",
2398 "KeepAliveIntervalSec",
2400 "TriggerLimitIntervalSec"))
2401 return bus_append_parse_sec_rename(m
, field
, eq
);
2403 if (STR_IN_SET(field
, "ReceiveBuffer",
2406 return bus_append_parse_size(m
, field
, eq
, 1024);
2408 if (STR_IN_SET(field
, "ExecStartPre",
2412 return bus_append_exec_command(m
, field
, eq
);
2414 if (STR_IN_SET(field
, "SmackLabel",
2420 "FileDescriptorName",
2424 return bus_append_string(m
, field
, eq
);
2426 if (streq(field
, "Symlinks"))
2427 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2429 if (streq(field
, "SocketProtocol"))
2430 return bus_append_parse_ip_protocol(m
, field
, eq
);
2432 if (STR_IN_SET(field
, "ListenStream",
2434 "ListenSequentialPacket",
2437 "ListenMessageQueue",
2439 "ListenUSBFunction")) {
2441 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
2443 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
2445 return bus_log_create_error(r
);
2452 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2455 if (STR_IN_SET(field
, "WakeSystem",
2456 "RemainAfterElapse",
2460 "FixedRandomDelay"))
2461 return bus_append_parse_boolean(m
, field
, eq
);
2463 if (STR_IN_SET(field
, "AccuracySec",
2464 "RandomizedDelaySec"))
2465 return bus_append_parse_sec_rename(m
, field
, eq
);
2467 if (STR_IN_SET(field
, "OnActiveSec",
2471 "OnUnitInactiveSec")) {
2473 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
2476 r
= parse_sec(eq
, &t
);
2478 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
2480 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
2483 return bus_log_create_error(r
);
2488 if (streq(field
, "OnCalendar")) {
2490 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
2492 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
2494 return bus_log_create_error(r
);
2502 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2503 ConditionType t
= _CONDITION_TYPE_INVALID
;
2504 bool is_condition
= false;
2507 if (STR_IN_SET(field
, "Description",
2511 "JobTimeoutRebootArgument",
2517 return bus_append_string(m
, field
, eq
);
2519 if (STR_IN_SET(field
, "StopWhenUnneeded",
2520 "RefuseManualStart",
2524 "DefaultDependencies"))
2525 return bus_append_parse_boolean(m
, field
, eq
);
2527 if (STR_IN_SET(field
, "JobTimeoutSec",
2528 "JobRunningTimeoutSec",
2529 "StartLimitIntervalSec"))
2530 return bus_append_parse_sec_rename(m
, field
, eq
);
2532 if (streq(field
, "StartLimitBurst"))
2533 return bus_append_safe_atou(m
, field
, eq
);
2535 if (STR_IN_SET(field
, "SuccessActionExitStatus",
2536 "FailureActionExitStatus")) {
2538 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
2542 r
= safe_atou8(eq
, &u
);
2544 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
2546 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
2549 return bus_log_create_error(r
);
2554 if (unit_dependency_from_string(field
) >= 0 ||
2555 STR_IN_SET(field
, "Documentation",
2556 "RequiresMountsFor",
2558 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2560 t
= condition_type_from_string(field
);
2562 is_condition
= true;
2564 t
= assert_type_from_string(field
);
2567 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
2570 int trigger
, negate
;
2572 trigger
= *p
== '|';
2580 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
2581 field
, trigger
, negate
, p
);
2584 return bus_log_create_error(r
);
2592 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
2593 const char *eq
, *field
;
2599 eq
= strchr(assignment
, '=');
2601 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2602 "Not an assignment: %s", assignment
);
2604 field
= strndupa_safe(assignment
, eq
- assignment
);
2609 r
= bus_append_cgroup_property(m
, field
, eq
);
2613 r
= bus_append_execute_property(m
, field
, eq
);
2617 r
= bus_append_kill_property(m
, field
, eq
);
2621 r
= bus_append_service_property(m
, field
, eq
);
2627 r
= bus_append_cgroup_property(m
, field
, eq
);
2631 r
= bus_append_execute_property(m
, field
, eq
);
2635 r
= bus_append_kill_property(m
, field
, eq
);
2639 r
= bus_append_socket_property(m
, field
, eq
);
2645 r
= bus_append_timer_property(m
, field
, eq
);
2651 r
= bus_append_path_property(m
, field
, eq
);
2657 r
= bus_append_cgroup_property(m
, field
, eq
);
2663 r
= bus_append_cgroup_property(m
, field
, eq
);
2667 r
= bus_append_kill_property(m
, field
, eq
);
2671 r
= bus_append_scope_property(m
, field
, eq
);
2677 r
= bus_append_cgroup_property(m
, field
, eq
);
2681 r
= bus_append_execute_property(m
, field
, eq
);
2685 r
= bus_append_kill_property(m
, field
, eq
);
2689 r
= bus_append_mount_property(m
, field
, eq
);
2695 case UNIT_AUTOMOUNT
:
2696 r
= bus_append_automount_property(m
, field
, eq
);
2708 assert_not_reached();
2711 r
= bus_append_unit_property(m
, field
, eq
);
2715 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2716 "Unknown assignment: %s", assignment
);
2719 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
2724 STRV_FOREACH(i
, l
) {
2725 r
= bus_append_unit_property_assignment(m
, t
, *i
);
2733 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
) {
2734 const char *type
, *path
, *source
;
2735 InstallChange
*changes
= NULL
;
2736 size_t n_changes
= 0;
2739 CLEANUP_ARRAY(changes
, n_changes
, install_changes_free
);
2741 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2743 return bus_log_parse_error(r
);
2745 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2746 InstallChangeType t
;
2748 /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2750 t
= install_change_type_from_string(type
);
2752 log_notice_errno(t
, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2757 r
= install_changes_add(&changes
, &n_changes
, t
, path
, source
);
2762 return bus_log_parse_error(r
);
2764 r
= sd_bus_message_exit_container(m
);
2766 return bus_log_parse_error(r
);
2768 install_changes_dump(0, NULL
, changes
, n_changes
, quiet
);
2773 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2774 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2775 _cleanup_free_
char *path
= NULL
;
2778 path
= unit_dbus_path_from_name(name
);
2782 /* This function warns on its own, because otherwise it'd be awkward to pass
2783 * the dbus error message around. */
2785 r
= sd_bus_get_property_string(
2787 "org.freedesktop.systemd1",
2789 "org.freedesktop.systemd1.Unit",
2794 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));
2799 int unit_info_compare(const UnitInfo
*a
, const UnitInfo
*b
) {
2802 /* First, order by machine */
2803 r
= strcasecmp_ptr(a
->machine
, b
->machine
);
2807 /* Second, order by unit type */
2808 r
= strcasecmp_ptr(strrchr(a
->id
, '.'), strrchr(b
->id
, '.'));
2812 /* Third, order by name */
2813 return strcasecmp(a
->id
, b
->id
);
2816 int bus_service_manager_reload(sd_bus
*bus
) {
2817 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2818 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2823 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "Reload");
2825 return bus_log_create_error(r
);
2827 /* Reloading the daemon may take long, hence set a longer timeout here */
2828 r
= sd_bus_call(bus
, m
, DAEMON_RELOAD_TIMEOUT_SEC
, &error
, NULL
);
2830 return log_error_errno(r
, "Failed to reload service manager: %s", bus_error_message(&error
, r
));