1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
5 #include "bus-unit-util.h"
8 #include "cgroup-setup.h"
9 #include "cgroup-util.h"
10 #include "condition.h"
11 #include "coredump-util.h"
12 #include "cpu-set-util.h"
14 #include "exec-util.h"
15 #include "exit-status.h"
17 #include "hexdecoct.h"
18 #include "hostname-util.h"
19 #include "in-addr-util.h"
20 #include "ip-protocol-list.h"
21 #include "libmount-util.h"
22 #include "locale-util.h"
24 #include "missing_fs.h"
25 #include "mountpoint-util.h"
27 #include "numa-util.h"
28 #include "parse-util.h"
29 #include "path-util.h"
30 #include "process-util.h"
31 #include "rlimit-util.h"
32 #include "securebits-util.h"
33 #include "signal-util.h"
34 #include "socket-util.h"
35 #include "sort-util.h"
36 #include "stdio-util.h"
37 #include "string-util.h"
38 #include "syslog-util.h"
39 #include "terminal-util.h"
41 #include "user-util.h"
44 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
50 return sd_bus_message_read(
65 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
66 static int bus_append_##parse_func( \
73 r = parse_func(eq, &val); \
75 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
77 r = sd_bus_message_append(m, "(sv)", field, \
78 bus_type, (cast_type) val); \
80 return bus_log_create_error(r); \
85 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
86 static int bus_append_##parse_func( \
94 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
96 r = sd_bus_message_append(m, "(sv)", field, \
97 bus_type, (int32_t) r); \
99 return bus_log_create_error(r); \
104 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
105 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
106 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
107 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
108 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
109 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
110 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
111 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
112 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
113 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
114 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
115 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
116 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
117 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
118 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
119 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
120 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
121 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
122 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
123 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
124 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
125 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
126 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
128 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
131 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
133 return bus_log_create_error(r
);
138 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
142 r
= sd_bus_message_open_container(m
, 'r', "sv");
144 return bus_log_create_error(r
);
146 r
= sd_bus_message_append_basic(m
, 's', field
);
148 return bus_log_create_error(r
);
150 r
= sd_bus_message_open_container(m
, 'v', "as");
152 return bus_log_create_error(r
);
154 r
= sd_bus_message_open_container(m
, 'a', "s");
156 return bus_log_create_error(r
);
159 _cleanup_free_
char *word
= NULL
;
161 r
= extract_first_word(&p
, &word
, NULL
, flags
);
167 return log_error_errno(r
, "Invalid syntax: %s", eq
);
169 r
= sd_bus_message_append_basic(m
, 's', word
);
171 return bus_log_create_error(r
);
174 r
= sd_bus_message_close_container(m
);
176 return bus_log_create_error(r
);
178 r
= sd_bus_message_close_container(m
);
180 return bus_log_create_error(r
);
182 r
= sd_bus_message_close_container(m
);
184 return bus_log_create_error(r
);
189 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
192 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
194 return bus_log_create_error(r
);
196 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
198 return bus_log_create_error(r
);
200 r
= sd_bus_message_open_container(m
, 'v', "ay");
202 return bus_log_create_error(r
);
204 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
206 return bus_log_create_error(r
);
208 r
= sd_bus_message_close_container(m
);
210 return bus_log_create_error(r
);
212 r
= sd_bus_message_close_container(m
);
214 return bus_log_create_error(r
);
219 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
225 r
= parse_sec(eq
, &t
);
227 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
230 n
= newa(char, l
+ 2);
231 /* Change suffix Sec → USec */
232 strcpy(mempcpy(n
, field
, l
- 3), "USec");
234 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
236 return bus_log_create_error(r
);
241 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
245 r
= parse_size(eq
, base
, &v
);
247 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
249 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
251 return bus_log_create_error(r
);
256 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
257 bool explicit_path
= false, done
= false;
258 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
259 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
260 ExecCommandFlags flags
= 0;
261 bool is_ex_prop
= endswith(field
, "Ex");
268 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
271 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
280 explicit_path
= true;
286 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
289 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
295 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
298 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
304 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
306 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
307 flags
&= ~EXEC_COMMAND_NO_SETUID
;
308 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
311 flags
|= EXEC_COMMAND_NO_SETUID
;
322 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
323 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
325 upgraded_name
= strjoin(field
, "Ex");
331 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
333 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
337 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
339 return log_error_errno(r
, "Failed to parse path: %m");
342 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
344 return log_error_errno(r
, "Failed to parse command line: %m");
346 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
348 return bus_log_create_error(r
);
350 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
352 return bus_log_create_error(r
);
354 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
356 return bus_log_create_error(r
);
358 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
360 return bus_log_create_error(r
);
362 if (!strv_isempty(l
)) {
364 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
366 return bus_log_create_error(r
);
368 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
370 return bus_log_create_error(r
);
372 r
= sd_bus_message_append_strv(m
, l
);
374 return bus_log_create_error(r
);
376 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
));
378 return bus_log_create_error(r
);
380 r
= sd_bus_message_close_container(m
);
382 return bus_log_create_error(r
);
385 r
= sd_bus_message_close_container(m
);
387 return bus_log_create_error(r
);
389 r
= sd_bus_message_close_container(m
);
391 return bus_log_create_error(r
);
393 r
= sd_bus_message_close_container(m
);
395 return bus_log_create_error(r
);
400 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
406 r
= sd_bus_message_open_container(m
, 'r', "iayu");
410 r
= sd_bus_message_append(m
, "i", family
);
414 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
418 r
= sd_bus_message_append(m
, "u", prefixlen
);
422 return sd_bus_message_close_container(m
);
425 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
428 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
429 return bus_append_string(m
, field
, eq
);
431 if (STR_IN_SET(field
, "CPUAccounting",
437 return bus_append_parse_boolean(m
, field
, eq
);
439 if (STR_IN_SET(field
, "CPUWeight",
443 return bus_append_cg_weight_parse(m
, field
, eq
);
445 if (STR_IN_SET(field
, "CPUShares",
447 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
449 if (STR_IN_SET(field
, "AllowedCPUs",
450 "AllowedMemoryNodes")) {
451 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
452 _cleanup_free_
uint8_t *array
= NULL
;
455 r
= parse_cpu_set(eq
, &cpuset
);
457 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
459 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
461 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
463 return bus_append_byte_array(m
, field
, array
, allocated
);
466 if (STR_IN_SET(field
, "BlockIOWeight",
467 "StartupBlockIOWeight"))
468 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
470 if (streq(field
, "DisableControllers"))
471 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
473 if (streq(field
, "Delegate")) {
474 r
= parse_boolean(eq
);
476 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
478 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
480 return bus_log_create_error(r
);
485 if (STR_IN_SET(field
, "MemoryMin",
495 if (streq(eq
, "infinity")) {
496 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
498 return bus_log_create_error(r
);
500 } else if (isempty(eq
)) {
501 uint64_t empty_value
= STR_IN_SET(field
,
509 r
= sd_bus_message_append(m
, "(sv)", field
, "t", empty_value
);
511 return bus_log_create_error(r
);
515 r
= parse_permille(eq
);
519 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
520 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
521 * size can be determined server-side. */
523 n
= strjoina(field
, "Scale");
524 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
526 return bus_log_create_error(r
);
531 if (streq(field
, "TasksMax"))
532 return bus_append_safe_atou64(m
, field
, eq
);
534 return bus_append_parse_size(m
, field
, eq
, 1024);
537 if (streq(field
, "CPUQuota")) {
539 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
541 r
= parse_permille_unbounded(eq
);
543 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
544 "CPU quota too small.");
546 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
548 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
552 return bus_log_create_error(r
);
557 if (streq(field
, "CPUQuotaPeriodSec")) {
558 usec_t u
= USEC_INFINITY
;
560 r
= parse_sec_def_infinity(eq
, &u
);
562 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
564 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
566 return bus_log_create_error(r
);
571 if (streq(field
, "DeviceAllow")) {
573 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
575 const char *path
= eq
, *rwm
= NULL
, *e
;
579 path
= strndupa(eq
, e
- eq
);
583 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
587 return bus_log_create_error(r
);
592 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
594 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
596 const char *path
, *bandwidth
, *e
;
601 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
602 "Failed to parse %s value %s.",
605 path
= strndupa(eq
, e
- eq
);
608 if (streq(bandwidth
, "infinity"))
609 bytes
= CGROUP_LIMIT_MAX
;
611 r
= parse_size(bandwidth
, 1000, &bytes
);
613 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
616 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
620 return bus_log_create_error(r
);
625 if (STR_IN_SET(field
, "IODeviceWeight",
626 "BlockIODeviceWeight")) {
628 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
630 const char *path
, *weight
, *e
;
635 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
636 "Failed to parse %s value %s.",
639 path
= strndupa(eq
, e
- eq
);
642 r
= safe_atou64(weight
, &u
);
644 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
646 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
650 return bus_log_create_error(r
);
655 if (streq(field
, "IODeviceLatencyTargetSec")) {
656 const char *field_usec
= "IODeviceLatencyTargetUSec";
659 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
661 const char *path
, *target
, *e
;
666 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
667 "Failed to parse %s value %s.",
670 path
= strndupa(eq
, e
- eq
);
673 r
= parse_sec(target
, &usec
);
675 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
677 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
681 return bus_log_create_error(r
);
686 if (STR_IN_SET(field
, "IPAddressAllow",
688 unsigned char prefixlen
;
689 union in_addr_union prefix
= {};
693 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
695 return bus_log_create_error(r
);
700 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
702 return bus_log_create_error(r
);
704 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
706 return bus_log_create_error(r
);
708 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
710 return bus_log_create_error(r
);
712 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
714 return bus_log_create_error(r
);
716 if (streq(eq
, "any")) {
717 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
719 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
721 return bus_log_create_error(r
);
723 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
725 return bus_log_create_error(r
);
727 } else if (is_localhost(eq
)) {
728 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
730 prefix
.in
.s_addr
= htobe32(0x7f000000);
731 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
733 return bus_log_create_error(r
);
735 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
736 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
740 } else if (streq(eq
, "link-local")) {
741 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
743 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
744 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
746 return bus_log_create_error(r
);
748 prefix
.in6
= (struct in6_addr
) {
749 .s6_addr32
[0] = htobe32(0xfe800000)
751 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
753 return bus_log_create_error(r
);
755 } else if (streq(eq
, "multicast")) {
756 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
758 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
759 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
761 return bus_log_create_error(r
);
763 prefix
.in6
= (struct in6_addr
) {
764 .s6_addr32
[0] = htobe32(0xff000000)
766 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
768 return bus_log_create_error(r
);
772 _cleanup_free_
char *word
= NULL
;
774 r
= extract_first_word(&eq
, &word
, NULL
, 0);
780 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
782 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
784 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
786 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
788 return bus_log_create_error(r
);
792 r
= sd_bus_message_close_container(m
);
794 return bus_log_create_error(r
);
796 r
= sd_bus_message_close_container(m
);
798 return bus_log_create_error(r
);
800 r
= sd_bus_message_close_container(m
);
802 return bus_log_create_error(r
);
807 if (STR_IN_SET(field
, "IPIngressFilterPath",
808 "IPEgressFilterPath")) {
810 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
812 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
815 return bus_log_create_error(r
);
823 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
824 if (streq(field
, "Where"))
825 return bus_append_string(m
, field
, eq
);
827 if (streq(field
, "DirectoryMode"))
828 return bus_append_parse_mode(m
, field
, eq
);
830 if (streq(field
, "TimeoutIdleSec"))
831 return bus_append_parse_sec_rename(m
, field
, eq
);
836 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
840 if (STR_IN_SET(field
, "User",
854 "RuntimeDirectoryPreserve",
857 "NetworkNamespacePath",
859 return bus_append_string(m
, field
, eq
);
861 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
872 "MemoryDenyWriteExecute",
876 "ProtectKernelTunables",
877 "ProtectKernelModules",
880 "ProtectControlGroups",
882 "CPUSchedulingResetOnFork",
886 return bus_append_parse_boolean(m
, field
, eq
);
888 if (STR_IN_SET(field
, "ReadWriteDirectories",
889 "ReadOnlyDirectories",
890 "InaccessibleDirectories",
898 "ConfigurationDirectory",
899 "SupplementaryGroups",
900 "SystemCallArchitectures"))
901 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
903 if (STR_IN_SET(field
, "SyslogLevel",
905 return bus_append_log_level_from_string(m
, field
, eq
);
907 if (streq(field
, "SyslogFacility"))
908 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
910 if (streq(field
, "SecureBits"))
911 return bus_append_secure_bits_from_string(m
, field
, eq
);
913 if (streq(field
, "CPUSchedulingPolicy"))
914 return bus_append_sched_policy_from_string(m
, field
, eq
);
916 if (STR_IN_SET(field
, "CPUSchedulingPriority",
918 return bus_append_safe_atoi(m
, field
, eq
);
920 if (streq(field
, "CoredumpFilter"))
921 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
923 if (streq(field
, "Nice"))
924 return bus_append_parse_nice(m
, field
, eq
);
926 if (streq(field
, "SystemCallErrorNumber"))
927 return bus_append_parse_errno(m
, field
, eq
);
929 if (streq(field
, "IOSchedulingClass"))
930 return bus_append_ioprio_class_from_string(m
, field
, eq
);
932 if (streq(field
, "IOSchedulingPriority"))
933 return bus_append_ioprio_parse_priority(m
, field
, eq
);
935 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
936 "StateDirectoryMode",
937 "CacheDirectoryMode",
939 "ConfigurationDirectoryMode",
941 return bus_append_parse_mode(m
, field
, eq
);
943 if (streq(field
, "TimerSlackNSec"))
944 return bus_append_parse_nsec(m
, field
, eq
);
946 if (streq(field
, "LogRateLimitIntervalSec"))
947 return bus_append_parse_sec_rename(m
, field
, eq
);
949 if (streq(field
, "LogRateLimitBurst"))
950 return bus_append_safe_atou(m
, field
, eq
);
952 if (streq(field
, "MountFlags"))
953 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
955 if (STR_IN_SET(field
, "Environment",
958 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
960 if (streq(field
, "EnvironmentFile")) {
962 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
964 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
965 eq
[0] == '-' ? eq
+ 1 : eq
,
968 return bus_log_create_error(r
);
973 if (streq(field
, "LogExtraFields")) {
974 r
= sd_bus_message_open_container(m
, 'r', "sv");
976 return bus_log_create_error(r
);
978 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
980 return bus_log_create_error(r
);
982 r
= sd_bus_message_open_container(m
, 'v', "aay");
984 return bus_log_create_error(r
);
986 r
= sd_bus_message_open_container(m
, 'a', "ay");
988 return bus_log_create_error(r
);
990 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
992 return bus_log_create_error(r
);
994 r
= sd_bus_message_close_container(m
);
996 return bus_log_create_error(r
);
998 r
= sd_bus_message_close_container(m
);
1000 return bus_log_create_error(r
);
1002 r
= sd_bus_message_close_container(m
);
1004 return bus_log_create_error(r
);
1009 if (STR_IN_SET(field
, "StandardInput",
1012 const char *n
, *appended
;
1014 if ((n
= startswith(eq
, "fd:"))) {
1015 appended
= strjoina(field
, "FileDescriptorName");
1016 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1017 } else if ((n
= startswith(eq
, "file:"))) {
1018 appended
= strjoina(field
, "File");
1019 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1020 } else if ((n
= startswith(eq
, "append:"))) {
1021 appended
= strjoina(field
, "FileToAppend");
1022 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1024 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1026 return bus_log_create_error(r
);
1031 if (streq(field
, "StandardInputText")) {
1032 _cleanup_free_
char *unescaped
= NULL
;
1034 r
= cunescape(eq
, 0, &unescaped
);
1036 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
1038 if (!strextend(&unescaped
, "\n", NULL
))
1041 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
1042 * interface anyway */
1044 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
1047 if (streq(field
, "StandardInputData")) {
1048 _cleanup_free_
void *decoded
= NULL
;
1051 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
1053 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1055 return bus_append_byte_array(m
, field
, decoded
, sz
);
1058 if ((suffix
= startswith(field
, "Limit"))) {
1061 rl
= rlimit_from_string(suffix
);
1066 r
= rlimit_parse(rl
, eq
, &l
);
1068 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1070 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
1072 return bus_log_create_error(r
);
1074 sn
= strjoina(field
, "Soft");
1075 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1077 return bus_log_create_error(r
);
1083 if (STR_IN_SET(field
, "AppArmorProfile",
1084 "SmackProcessLabel")) {
1093 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1095 return bus_log_create_error(r
);
1100 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1101 "AmbientCapabilities")) {
1103 bool invert
= false;
1111 r
= capability_set_from_string(p
, &sum
);
1113 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1115 sum
= invert
? ~sum
: sum
;
1117 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1119 return bus_log_create_error(r
);
1124 if (streq(field
, "CPUAffinity")) {
1125 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1126 _cleanup_free_
uint8_t *array
= NULL
;
1129 if (eq
&& streq(eq
, "numa")) {
1130 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1132 return bus_log_create_error(r
);
1136 r
= parse_cpu_set(eq
, &cpuset
);
1138 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1140 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1142 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1144 return bus_append_byte_array(m
, field
, array
, allocated
);
1147 if (streq(field
, "NUMAPolicy")) {
1148 r
= mpol_from_string(eq
);
1150 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1152 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1154 return bus_log_create_error(r
);
1159 if (streq(field
, "NUMAMask")) {
1160 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1161 _cleanup_free_
uint8_t *array
= NULL
;
1164 r
= parse_cpu_set(eq
, &nodes
);
1166 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1168 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1170 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1172 return bus_append_byte_array(m
, field
, array
, allocated
);
1175 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1176 "SystemCallFilter")) {
1185 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1187 return bus_log_create_error(r
);
1189 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1191 return bus_log_create_error(r
);
1193 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1195 return bus_log_create_error(r
);
1197 r
= sd_bus_message_open_container(m
, 'r', "bas");
1199 return bus_log_create_error(r
);
1201 r
= sd_bus_message_append_basic(m
, 'b', &allow_list
);
1203 return bus_log_create_error(r
);
1205 r
= sd_bus_message_open_container(m
, 'a', "s");
1207 return bus_log_create_error(r
);
1210 _cleanup_free_
char *word
= NULL
;
1212 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1218 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1220 r
= sd_bus_message_append_basic(m
, 's', word
);
1222 return bus_log_create_error(r
);
1225 r
= sd_bus_message_close_container(m
);
1227 return bus_log_create_error(r
);
1229 r
= sd_bus_message_close_container(m
);
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
);
1244 if (streq(field
, "RestrictNamespaces")) {
1245 bool invert
= false;
1246 unsigned long flags
;
1248 r
= parse_boolean(eq
);
1252 flags
= NAMESPACE_FLAGS_ALL
;
1259 r
= namespace_flags_from_string(eq
, &flags
);
1261 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1265 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1267 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1269 return bus_log_create_error(r
);
1274 if (STR_IN_SET(field
, "BindPaths",
1275 "BindReadOnlyPaths")) {
1278 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1280 return bus_log_create_error(r
);
1282 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1284 return bus_log_create_error(r
);
1286 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1288 return bus_log_create_error(r
);
1290 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1292 return bus_log_create_error(r
);
1295 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1296 char *s
= NULL
, *d
= NULL
;
1297 bool ignore_enoent
= false;
1298 uint64_t flags
= MS_REC
;
1300 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1302 return log_error_errno(r
, "Failed to parse argument: %m");
1308 ignore_enoent
= true;
1312 if (p
&& p
[-1] == ':') {
1313 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1315 return log_error_errno(r
, "Failed to parse argument: %m");
1317 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1318 "Missing argument after ':': %s",
1323 if (p
&& p
[-1] == ':') {
1324 _cleanup_free_
char *options
= NULL
;
1326 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1328 return log_error_errno(r
, "Failed to parse argument: %m");
1330 if (isempty(options
) || streq(options
, "rbind"))
1332 else if (streq(options
, "norbind"))
1335 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1336 "Unknown options: %s",
1342 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1344 return bus_log_create_error(r
);
1347 r
= sd_bus_message_close_container(m
);
1349 return bus_log_create_error(r
);
1351 r
= sd_bus_message_close_container(m
);
1353 return bus_log_create_error(r
);
1355 r
= sd_bus_message_close_container(m
);
1357 return bus_log_create_error(r
);
1362 if (streq(field
, "TemporaryFileSystem")) {
1365 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1367 return bus_log_create_error(r
);
1369 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1371 return bus_log_create_error(r
);
1373 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1375 return bus_log_create_error(r
);
1377 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1379 return bus_log_create_error(r
);
1382 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1385 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1387 return log_error_errno(r
, "Failed to parse argument: %m");
1392 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1394 return log_error_errno(r
, "Failed to parse argument: %m");
1396 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1397 "Failed to parse argument: %s",
1400 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1402 return bus_log_create_error(r
);
1405 r
= sd_bus_message_close_container(m
);
1407 return bus_log_create_error(r
);
1409 r
= sd_bus_message_close_container(m
);
1411 return bus_log_create_error(r
);
1413 r
= sd_bus_message_close_container(m
);
1415 return bus_log_create_error(r
);
1420 if (streq(field
, "RootHash")) {
1421 _cleanup_free_
void *roothash_decoded
= NULL
;
1422 size_t roothash_decoded_size
= 0;
1424 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1425 if (path_is_absolute(eq
))
1426 return bus_append_string(m
, "RootHashPath", eq
);
1428 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1429 r
= unhexmem(eq
, strlen(eq
), &roothash_decoded
, &roothash_decoded_size
);
1431 return log_error_errno(r
, "Failed to decode RootHash= '%s': %m", eq
);
1432 if (roothash_decoded_size
< sizeof(sd_id128_t
))
1433 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "RootHash= '%s' is too short: %m", eq
);
1435 return bus_append_byte_array(m
, field
, roothash_decoded
, roothash_decoded_size
);
1438 if (streq(field
, "RootHashSignature")) {
1439 _cleanup_free_
void *roothash_sig_decoded
= NULL
;
1441 size_t roothash_sig_decoded_size
= 0;
1443 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1444 if (path_is_absolute(eq
))
1445 return bus_append_string(m
, "RootHashSignaturePath", eq
);
1447 if (!(value
= startswith(eq
, "base64:")))
1448 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq
);
1450 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1451 r
= unbase64mem(value
, strlen(value
), &roothash_sig_decoded
, &roothash_sig_decoded_size
);
1453 return log_error_errno(r
, "Failed to decode RootHashSignature= '%s': %m", eq
);
1455 return bus_append_byte_array(m
, field
, roothash_sig_decoded
, roothash_sig_decoded_size
);
1458 if (streq(field
, "RootImageOptions")) {
1459 _cleanup_strv_free_
char **l
= NULL
;
1460 char **first
= NULL
, **second
= NULL
;
1463 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1465 return bus_log_create_error(r
);
1467 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1469 return bus_log_create_error(r
);
1471 r
= sd_bus_message_open_container(m
, 'v', "a(us)");
1473 return bus_log_create_error(r
);
1475 r
= sd_bus_message_open_container(m
, 'a', "(us)");
1477 return bus_log_create_error(r
);
1479 r
= strv_split_colon_pairs(&l
, p
);
1481 return log_error_errno(r
, "Failed to parse argument: %m");
1483 STRV_FOREACH_PAIR(first
, second
, l
) {
1484 const char *mount_options
;
1485 unsigned partition_number
= 0;
1487 /* Format is either '0:foo' or 'foo' (0 is implied) */
1488 if (!isempty(*second
)) {
1489 mount_options
= *second
;
1490 r
= safe_atou(*first
, &partition_number
);
1492 log_error_errno(r
, "Failed to parse partition number from %s: %m", *first
);
1496 mount_options
= *first
;
1498 r
= sd_bus_message_append(m
, "(us)", partition_number
, mount_options
);
1500 return bus_log_create_error(r
);
1503 r
= sd_bus_message_close_container(m
);
1505 return bus_log_create_error(r
);
1507 r
= sd_bus_message_close_container(m
);
1509 return bus_log_create_error(r
);
1511 r
= sd_bus_message_close_container(m
);
1513 return bus_log_create_error(r
);
1518 if (streq(field
, "MountImages")) {
1519 _cleanup_strv_free_
char **l
= NULL
;
1520 char **source
= NULL
, **destination
= NULL
;
1523 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1525 return bus_log_create_error(r
);
1527 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1529 return bus_log_create_error(r
);
1531 r
= sd_bus_message_open_container(m
, 'v', "a(ssb)");
1533 return bus_log_create_error(r
);
1535 r
= sd_bus_message_open_container(m
, 'a', "(ssb)");
1537 return bus_log_create_error(r
);
1539 r
= strv_split_colon_pairs(&l
, p
);
1541 return log_error_errno(r
, "Failed to parse argument: %m");
1543 STRV_FOREACH_PAIR(source
, destination
, l
) {
1545 bool permissive
= false;
1552 if (isempty(*destination
))
1553 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1554 "Missing argument after ':': %s",
1557 r
= sd_bus_message_append(m
, "(ssb)", s
, *destination
, permissive
);
1559 return bus_log_create_error(r
);
1562 r
= sd_bus_message_close_container(m
);
1564 return bus_log_create_error(r
);
1566 r
= sd_bus_message_close_container(m
);
1568 return bus_log_create_error(r
);
1570 r
= sd_bus_message_close_container(m
);
1572 return bus_log_create_error(r
);
1580 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1581 if (streq(field
, "KillMode"))
1582 return bus_append_string(m
, field
, eq
);
1584 if (STR_IN_SET(field
, "SendSIGHUP",
1586 return bus_append_parse_boolean(m
, field
, eq
);
1588 if (STR_IN_SET(field
, "KillSignal",
1589 "RestartKillSignal",
1592 return bus_append_signal_from_string(m
, field
, eq
);
1597 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1599 if (STR_IN_SET(field
, "What",
1603 return bus_append_string(m
, field
, eq
);
1605 if (streq(field
, "TimeoutSec"))
1606 return bus_append_parse_sec_rename(m
, field
, eq
);
1608 if (streq(field
, "DirectoryMode"))
1609 return bus_append_parse_mode(m
, field
, eq
);
1611 if (STR_IN_SET(field
, "SloppyOptions",
1615 return bus_append_parse_boolean(m
, field
, eq
);
1620 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1623 if (streq(field
, "MakeDirectory"))
1624 return bus_append_parse_boolean(m
, field
, eq
);
1626 if (streq(field
, "DirectoryMode"))
1627 return bus_append_parse_mode(m
, field
, eq
);
1629 if (STR_IN_SET(field
, "PathExists",
1633 "DirectoryNotEmpty")) {
1635 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1637 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1639 return bus_log_create_error(r
);
1647 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1648 if (streq(field
, "RuntimeMaxSec"))
1649 return bus_append_parse_sec_rename(m
, field
, eq
);
1651 if (streq(field
, "TimeoutStopSec"))
1652 return bus_append_parse_sec_rename(m
, field
, eq
);
1657 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1660 if (STR_IN_SET(field
, "PIDFile",
1665 "USBFunctionDescriptors",
1666 "USBFunctionStrings",
1668 "TimeoutStartFailureMode",
1669 "TimeoutStopFailureMode"))
1670 return bus_append_string(m
, field
, eq
);
1672 if (STR_IN_SET(field
, "PermissionsStartOnly",
1673 "RootDirectoryStartOnly",
1676 return bus_append_parse_boolean(m
, field
, eq
);
1678 if (STR_IN_SET(field
, "RestartSec",
1684 return bus_append_parse_sec_rename(m
, field
, eq
);
1686 if (streq(field
, "TimeoutSec")) {
1687 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1691 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1694 if (streq(field
, "FileDescriptorStoreMax"))
1695 return bus_append_safe_atou(m
, field
, eq
);
1697 if (STR_IN_SET(field
, "ExecCondition",
1711 return bus_append_exec_command(m
, field
, eq
);
1713 if (STR_IN_SET(field
, "RestartPreventExitStatus",
1714 "RestartForceExitStatus",
1715 "SuccessExitStatus")) {
1716 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1717 size_t n_status
= 0, n_signal
= 0;
1721 _cleanup_free_
char *word
= NULL
;
1723 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1729 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1731 /* We need to call exit_status_from_string() first, because we want
1732 * to parse numbers as exit statuses, not signals. */
1734 r
= exit_status_from_string(word
);
1736 assert(r
>= 0 && r
< 256);
1738 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
1742 status
[n_status
++] = r
;
1744 } else if ((r
= signal_from_string(word
)) >= 0) {
1745 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
1749 signal
[n_signal
++] = r
;
1752 /* original r from exit_status_to_string() */
1753 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
1757 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1759 return bus_log_create_error(r
);
1761 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1763 return bus_log_create_error(r
);
1765 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1767 return bus_log_create_error(r
);
1769 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1771 return bus_log_create_error(r
);
1773 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
1775 return bus_log_create_error(r
);
1777 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
1779 return bus_log_create_error(r
);
1781 r
= sd_bus_message_close_container(m
);
1783 return bus_log_create_error(r
);
1785 r
= sd_bus_message_close_container(m
);
1787 return bus_log_create_error(r
);
1789 r
= sd_bus_message_close_container(m
);
1791 return bus_log_create_error(r
);
1799 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1802 if (STR_IN_SET(field
, "Accept",
1814 "SELinuxContextFromNet"))
1815 return bus_append_parse_boolean(m
, field
, eq
);
1817 if (STR_IN_SET(field
, "Priority",
1820 return bus_append_safe_atoi(m
, field
, eq
);
1822 if (streq(field
, "IPTOS"))
1823 return bus_append_ip_tos_from_string(m
, field
, eq
);
1825 if (STR_IN_SET(field
, "Backlog",
1827 "MaxConnectionsPerSource",
1829 "TriggerLimitBurst"))
1830 return bus_append_safe_atou(m
, field
, eq
);
1832 if (STR_IN_SET(field
, "SocketMode",
1834 return bus_append_parse_mode(m
, field
, eq
);
1836 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
1837 "MessageQueueMessageSize"))
1838 return bus_append_safe_atoi64(m
, field
, eq
);
1840 if (STR_IN_SET(field
, "TimeoutSec",
1842 "KeepAliveIntervalSec",
1844 "TriggerLimitIntervalSec"))
1845 return bus_append_parse_sec_rename(m
, field
, eq
);
1847 if (STR_IN_SET(field
, "ReceiveBuffer",
1850 return bus_append_parse_size(m
, field
, eq
, 1024);
1852 if (STR_IN_SET(field
, "ExecStartPre",
1856 return bus_append_exec_command(m
, field
, eq
);
1858 if (STR_IN_SET(field
, "SmackLabel",
1864 "FileDescriptorName",
1867 return bus_append_string(m
, field
, eq
);
1869 if (streq(field
, "Symlinks"))
1870 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1872 if (streq(field
, "SocketProtocol"))
1873 return bus_append_parse_ip_protocol(m
, field
, eq
);
1875 if (STR_IN_SET(field
, "ListenStream",
1877 "ListenSequentialPacket",
1880 "ListenMessageQueue",
1882 "ListenUSBFunction")) {
1884 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1886 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1888 return bus_log_create_error(r
);
1895 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1898 if (STR_IN_SET(field
, "WakeSystem",
1899 "RemainAfterElapse",
1903 return bus_append_parse_boolean(m
, field
, eq
);
1905 if (STR_IN_SET(field
, "AccuracySec",
1906 "RandomizedDelaySec"))
1907 return bus_append_parse_sec_rename(m
, field
, eq
);
1909 if (STR_IN_SET(field
, "OnActiveSec",
1913 "OnUnitInactiveSec")) {
1915 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1918 r
= parse_sec(eq
, &t
);
1920 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1922 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1925 return bus_log_create_error(r
);
1930 if (streq(field
, "OnCalendar")) {
1932 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1934 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1936 return bus_log_create_error(r
);
1944 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1945 ConditionType t
= _CONDITION_TYPE_INVALID
;
1946 bool is_condition
= false;
1949 if (STR_IN_SET(field
, "Description",
1953 "JobTimeoutRebootArgument",
1959 return bus_append_string(m
, field
, eq
);
1961 if (STR_IN_SET(field
, "StopWhenUnneeded",
1962 "RefuseManualStart",
1966 "DefaultDependencies"))
1967 return bus_append_parse_boolean(m
, field
, eq
);
1969 if (STR_IN_SET(field
, "JobTimeoutSec",
1970 "JobRunningTimeoutSec",
1971 "StartLimitIntervalSec"))
1972 return bus_append_parse_sec_rename(m
, field
, eq
);
1974 if (streq(field
, "StartLimitBurst"))
1975 return bus_append_safe_atou(m
, field
, eq
);
1977 if (STR_IN_SET(field
, "SuccessActionExitStatus",
1978 "FailureActionExitStatus")) {
1980 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1984 r
= safe_atou8(eq
, &u
);
1986 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1988 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1991 return bus_log_create_error(r
);
1996 if (unit_dependency_from_string(field
) >= 0 ||
1997 STR_IN_SET(field
, "Documentation",
1998 "RequiresMountsFor"))
1999 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2001 t
= condition_type_from_string(field
);
2003 is_condition
= true;
2005 t
= assert_type_from_string(field
);
2008 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
2011 int trigger
, negate
;
2013 trigger
= *p
== '|';
2021 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
2022 field
, trigger
, negate
, p
);
2025 return bus_log_create_error(r
);
2033 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
2034 const char *eq
, *field
;
2040 eq
= strchr(assignment
, '=');
2042 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2043 "Not an assignment: %s", assignment
);
2045 field
= strndupa(assignment
, eq
- assignment
);
2050 r
= bus_append_cgroup_property(m
, field
, eq
);
2054 r
= bus_append_execute_property(m
, field
, eq
);
2058 r
= bus_append_kill_property(m
, field
, eq
);
2062 r
= bus_append_service_property(m
, field
, eq
);
2068 r
= bus_append_cgroup_property(m
, field
, eq
);
2072 r
= bus_append_execute_property(m
, field
, eq
);
2076 r
= bus_append_kill_property(m
, field
, eq
);
2080 r
= bus_append_socket_property(m
, field
, eq
);
2086 r
= bus_append_timer_property(m
, field
, eq
);
2092 r
= bus_append_path_property(m
, field
, eq
);
2098 r
= bus_append_cgroup_property(m
, field
, eq
);
2104 r
= bus_append_cgroup_property(m
, field
, eq
);
2108 r
= bus_append_kill_property(m
, field
, eq
);
2112 r
= bus_append_scope_property(m
, field
, eq
);
2118 r
= bus_append_cgroup_property(m
, field
, eq
);
2122 r
= bus_append_execute_property(m
, field
, eq
);
2126 r
= bus_append_kill_property(m
, field
, eq
);
2130 r
= bus_append_mount_property(m
, field
, eq
);
2136 case UNIT_AUTOMOUNT
:
2137 r
= bus_append_automount_property(m
, field
, eq
);
2146 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2147 "Not supported unit type");
2150 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2151 "Invalid unit type");
2154 r
= bus_append_unit_property(m
, field
, eq
);
2158 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2159 "Unknown assignment: %s", assignment
);
2162 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
2168 STRV_FOREACH(i
, l
) {
2169 r
= bus_append_unit_property_assignment(m
, t
, *i
);
2177 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
2178 const char *type
, *path
, *source
;
2181 /* changes is dereferenced when calling unit_file_dump_changes() later,
2182 * so we have to make sure this is not NULL. */
2186 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2188 return bus_log_parse_error(r
);
2190 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2191 /* We expect only "success" changes to be sent over the bus.
2192 Hence, reject anything negative. */
2193 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
2196 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
2200 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2205 return bus_log_parse_error(r
);
2207 r
= sd_bus_message_exit_container(m
);
2209 return bus_log_parse_error(r
);
2211 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2215 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2216 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2217 _cleanup_free_
char *path
= NULL
;
2220 path
= unit_dbus_path_from_name(name
);
2224 /* This function warns on it's own, because otherwise it'd be awkward to pass
2225 * the dbus error message around. */
2227 r
= sd_bus_get_property_string(
2229 "org.freedesktop.systemd1",
2231 "org.freedesktop.systemd1.Unit",
2236 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));