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"
16 #include "hexdecoct.h"
17 #include "hostname-util.h"
18 #include "in-addr-util.h"
19 #include "ip-protocol-list.h"
20 #include "locale-util.h"
22 #include "missing_fs.h"
23 #include "mountpoint-util.h"
25 #include "numa-util.h"
26 #include "parse-util.h"
27 #include "process-util.h"
28 #include "rlimit-util.h"
29 #include "securebits-util.h"
30 #include "signal-util.h"
31 #include "socket-util.h"
32 #include "sort-util.h"
33 #include "stdio-util.h"
34 #include "string-util.h"
35 #include "syslog-util.h"
36 #include "terminal-util.h"
38 #include "user-util.h"
41 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
47 return sd_bus_message_read(
62 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
63 static int bus_append_##parse_func( \
70 r = parse_func(eq, &val); \
72 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
74 r = sd_bus_message_append(m, "(sv)", field, \
75 bus_type, (cast_type) val); \
77 return bus_log_create_error(r); \
82 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
83 static int bus_append_##parse_func( \
91 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
93 r = sd_bus_message_append(m, "(sv)", field, \
94 bus_type, (int32_t) r); \
96 return bus_log_create_error(r); \
101 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
102 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
103 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
104 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
105 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
106 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
107 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
108 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
109 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
110 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
111 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
112 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
113 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
114 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
115 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
116 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
117 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
118 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
119 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
120 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
121 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
122 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
123 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
125 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
128 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
130 return bus_log_create_error(r
);
135 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
139 r
= sd_bus_message_open_container(m
, 'r', "sv");
141 return bus_log_create_error(r
);
143 r
= sd_bus_message_append_basic(m
, 's', field
);
145 return bus_log_create_error(r
);
147 r
= sd_bus_message_open_container(m
, 'v', "as");
149 return bus_log_create_error(r
);
151 r
= sd_bus_message_open_container(m
, 'a', "s");
153 return bus_log_create_error(r
);
156 _cleanup_free_
char *word
= NULL
;
158 r
= extract_first_word(&p
, &word
, NULL
, flags
);
164 return log_error_errno(r
, "Invalid syntax: %s", eq
);
166 r
= sd_bus_message_append_basic(m
, 's', word
);
168 return bus_log_create_error(r
);
171 r
= sd_bus_message_close_container(m
);
173 return bus_log_create_error(r
);
175 r
= sd_bus_message_close_container(m
);
177 return bus_log_create_error(r
);
179 r
= sd_bus_message_close_container(m
);
181 return bus_log_create_error(r
);
186 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
189 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
191 return bus_log_create_error(r
);
193 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
195 return bus_log_create_error(r
);
197 r
= sd_bus_message_open_container(m
, 'v', "ay");
199 return bus_log_create_error(r
);
201 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
203 return bus_log_create_error(r
);
205 r
= sd_bus_message_close_container(m
);
207 return bus_log_create_error(r
);
209 r
= sd_bus_message_close_container(m
);
211 return bus_log_create_error(r
);
216 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
222 r
= parse_sec(eq
, &t
);
224 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
227 n
= newa(char, l
+ 2);
228 /* Change suffix Sec → USec */
229 strcpy(mempcpy(n
, field
, l
- 3), "USec");
231 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
233 return bus_log_create_error(r
);
238 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
242 r
= parse_size(eq
, base
, &v
);
244 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
246 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
248 return bus_log_create_error(r
);
253 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
254 bool explicit_path
= false, done
= false;
255 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
256 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
257 ExecCommandFlags flags
= 0;
258 bool is_ex_prop
= endswith(field
, "Ex");
265 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
268 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
277 explicit_path
= true;
283 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
286 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
292 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
295 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
301 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
303 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
304 flags
&= ~EXEC_COMMAND_NO_SETUID
;
305 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
308 flags
|= EXEC_COMMAND_NO_SETUID
;
319 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
320 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
322 upgraded_name
= strjoin(field
, "Ex");
328 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
330 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
334 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
336 return log_error_errno(r
, "Failed to parse path: %m");
339 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
341 return log_error_errno(r
, "Failed to parse command line: %m");
343 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
345 return bus_log_create_error(r
);
347 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
349 return bus_log_create_error(r
);
351 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
353 return bus_log_create_error(r
);
355 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
357 return bus_log_create_error(r
);
359 if (!strv_isempty(l
)) {
361 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
363 return bus_log_create_error(r
);
365 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
367 return bus_log_create_error(r
);
369 r
= sd_bus_message_append_strv(m
, l
);
371 return bus_log_create_error(r
);
373 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
));
375 return bus_log_create_error(r
);
377 r
= sd_bus_message_close_container(m
);
379 return bus_log_create_error(r
);
382 r
= sd_bus_message_close_container(m
);
384 return bus_log_create_error(r
);
386 r
= sd_bus_message_close_container(m
);
388 return bus_log_create_error(r
);
390 r
= sd_bus_message_close_container(m
);
392 return bus_log_create_error(r
);
397 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
403 r
= sd_bus_message_open_container(m
, 'r', "iayu");
407 r
= sd_bus_message_append(m
, "i", family
);
411 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
415 r
= sd_bus_message_append(m
, "u", prefixlen
);
419 return sd_bus_message_close_container(m
);
422 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
425 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
426 return bus_append_string(m
, field
, eq
);
428 if (STR_IN_SET(field
, "CPUAccounting",
434 return bus_append_parse_boolean(m
, field
, eq
);
436 if (STR_IN_SET(field
, "CPUWeight",
440 return bus_append_cg_weight_parse(m
, field
, eq
);
442 if (STR_IN_SET(field
, "CPUShares",
444 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
446 if (STR_IN_SET(field
, "AllowedCPUs",
447 "AllowedMemoryNodes")) {
448 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
449 _cleanup_free_
uint8_t *array
= NULL
;
452 r
= parse_cpu_set(eq
, &cpuset
);
454 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
456 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
458 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
460 return bus_append_byte_array(m
, field
, array
, allocated
);
463 if (STR_IN_SET(field
, "BlockIOWeight",
464 "StartupBlockIOWeight"))
465 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
467 if (streq(field
, "DisableControllers"))
468 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
470 if (streq(field
, "Delegate")) {
471 r
= parse_boolean(eq
);
473 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
475 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
477 return bus_log_create_error(r
);
482 if (STR_IN_SET(field
, "MemoryMin",
492 if (isempty(eq
) || streq(eq
, "infinity")) {
493 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
495 return bus_log_create_error(r
);
499 r
= parse_permille(eq
);
503 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
504 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
505 * size can be determined server-side. */
507 n
= strjoina(field
, "Scale");
508 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
510 return bus_log_create_error(r
);
515 if (streq(field
, "TasksMax"))
516 return bus_append_safe_atou64(m
, field
, eq
);
518 return bus_append_parse_size(m
, field
, eq
, 1024);
521 if (streq(field
, "CPUQuota")) {
523 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
525 r
= parse_permille_unbounded(eq
);
527 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
528 "CPU quota too small.");
530 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
532 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
536 return bus_log_create_error(r
);
541 if (streq(field
, "CPUQuotaPeriodSec")) {
542 usec_t u
= USEC_INFINITY
;
544 r
= parse_sec_def_infinity(eq
, &u
);
546 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
548 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
550 return bus_log_create_error(r
);
555 if (streq(field
, "DeviceAllow")) {
557 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
559 const char *path
= eq
, *rwm
= NULL
, *e
;
563 path
= strndupa(eq
, e
- eq
);
567 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
571 return bus_log_create_error(r
);
576 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
578 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
580 const char *path
, *bandwidth
, *e
;
585 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
586 "Failed to parse %s value %s.",
589 path
= strndupa(eq
, e
- eq
);
592 if (streq(bandwidth
, "infinity"))
593 bytes
= CGROUP_LIMIT_MAX
;
595 r
= parse_size(bandwidth
, 1000, &bytes
);
597 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
600 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
604 return bus_log_create_error(r
);
609 if (STR_IN_SET(field
, "IODeviceWeight",
610 "BlockIODeviceWeight")) {
612 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
614 const char *path
, *weight
, *e
;
619 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
620 "Failed to parse %s value %s.",
623 path
= strndupa(eq
, e
- eq
);
626 r
= safe_atou64(weight
, &u
);
628 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
630 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
634 return bus_log_create_error(r
);
639 if (streq(field
, "IODeviceLatencyTargetSec")) {
640 const char *field_usec
= "IODeviceLatencyTargetUSec";
643 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
645 const char *path
, *target
, *e
;
650 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
651 "Failed to parse %s value %s.",
654 path
= strndupa(eq
, e
- eq
);
657 r
= parse_sec(target
, &usec
);
659 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
661 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
665 return bus_log_create_error(r
);
670 if (STR_IN_SET(field
, "IPAddressAllow",
672 unsigned char prefixlen
;
673 union in_addr_union prefix
= {};
677 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
679 return bus_log_create_error(r
);
684 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
686 return bus_log_create_error(r
);
688 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
690 return bus_log_create_error(r
);
692 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
694 return bus_log_create_error(r
);
696 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
698 return bus_log_create_error(r
);
700 if (streq(eq
, "any")) {
701 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
703 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
705 return bus_log_create_error(r
);
707 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
709 return bus_log_create_error(r
);
711 } else if (is_localhost(eq
)) {
712 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
714 prefix
.in
.s_addr
= htobe32(0x7f000000);
715 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
717 return bus_log_create_error(r
);
719 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
720 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
724 } else if (streq(eq
, "link-local")) {
725 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
727 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
728 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
730 return bus_log_create_error(r
);
732 prefix
.in6
= (struct in6_addr
) {
733 .s6_addr32
[0] = htobe32(0xfe800000)
735 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
737 return bus_log_create_error(r
);
739 } else if (streq(eq
, "multicast")) {
740 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
742 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
743 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
745 return bus_log_create_error(r
);
747 prefix
.in6
= (struct in6_addr
) {
748 .s6_addr32
[0] = htobe32(0xff000000)
750 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
752 return bus_log_create_error(r
);
756 _cleanup_free_
char *word
= NULL
;
758 r
= extract_first_word(&eq
, &word
, NULL
, 0);
764 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
766 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
768 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
770 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
772 return bus_log_create_error(r
);
776 r
= sd_bus_message_close_container(m
);
778 return bus_log_create_error(r
);
780 r
= sd_bus_message_close_container(m
);
782 return bus_log_create_error(r
);
784 r
= sd_bus_message_close_container(m
);
786 return bus_log_create_error(r
);
791 if (STR_IN_SET(field
, "IPIngressFilterPath",
792 "IPEgressFilterPath")) {
794 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
796 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
799 return bus_log_create_error(r
);
807 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
808 if (streq(field
, "Where"))
809 return bus_append_string(m
, field
, eq
);
811 if (streq(field
, "DirectoryMode"))
812 return bus_append_parse_mode(m
, field
, eq
);
814 if (streq(field
, "TimeoutIdleSec"))
815 return bus_append_parse_sec_rename(m
, field
, eq
);
820 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
824 if (STR_IN_SET(field
, "User",
837 "RuntimeDirectoryPreserve",
840 "NetworkNamespacePath",
842 return bus_append_string(m
, field
, eq
);
844 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
855 "MemoryDenyWriteExecute",
859 "ProtectKernelTunables",
860 "ProtectKernelModules",
863 "ProtectControlGroups",
865 "CPUSchedulingResetOnFork",
869 return bus_append_parse_boolean(m
, field
, eq
);
871 if (STR_IN_SET(field
, "ReadWriteDirectories",
872 "ReadOnlyDirectories",
873 "InaccessibleDirectories",
881 "ConfigurationDirectory",
882 "SupplementaryGroups",
883 "SystemCallArchitectures"))
884 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
886 if (STR_IN_SET(field
, "SyslogLevel",
888 return bus_append_log_level_from_string(m
, field
, eq
);
890 if (streq(field
, "SyslogFacility"))
891 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
893 if (streq(field
, "SecureBits"))
894 return bus_append_secure_bits_from_string(m
, field
, eq
);
896 if (streq(field
, "CPUSchedulingPolicy"))
897 return bus_append_sched_policy_from_string(m
, field
, eq
);
899 if (STR_IN_SET(field
, "CPUSchedulingPriority",
901 return bus_append_safe_atoi(m
, field
, eq
);
903 if (streq(field
, "CoredumpFilter"))
904 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
906 if (streq(field
, "Nice"))
907 return bus_append_parse_nice(m
, field
, eq
);
909 if (streq(field
, "SystemCallErrorNumber"))
910 return bus_append_parse_errno(m
, field
, eq
);
912 if (streq(field
, "IOSchedulingClass"))
913 return bus_append_ioprio_class_from_string(m
, field
, eq
);
915 if (streq(field
, "IOSchedulingPriority"))
916 return bus_append_ioprio_parse_priority(m
, field
, eq
);
918 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
919 "StateDirectoryMode",
920 "CacheDirectoryMode",
922 "ConfigurationDirectoryMode",
924 return bus_append_parse_mode(m
, field
, eq
);
926 if (streq(field
, "TimerSlackNSec"))
927 return bus_append_parse_nsec(m
, field
, eq
);
929 if (streq(field
, "LogRateLimitIntervalSec"))
930 return bus_append_parse_sec_rename(m
, field
, eq
);
932 if (streq(field
, "LogRateLimitBurst"))
933 return bus_append_safe_atou(m
, field
, eq
);
935 if (streq(field
, "MountFlags"))
936 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
938 if (STR_IN_SET(field
, "Environment",
941 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
943 if (streq(field
, "EnvironmentFile")) {
945 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
947 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
948 eq
[0] == '-' ? eq
+ 1 : eq
,
951 return bus_log_create_error(r
);
956 if (streq(field
, "LogExtraFields")) {
957 r
= sd_bus_message_open_container(m
, 'r', "sv");
959 return bus_log_create_error(r
);
961 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
963 return bus_log_create_error(r
);
965 r
= sd_bus_message_open_container(m
, 'v', "aay");
967 return bus_log_create_error(r
);
969 r
= sd_bus_message_open_container(m
, 'a', "ay");
971 return bus_log_create_error(r
);
973 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
975 return bus_log_create_error(r
);
977 r
= sd_bus_message_close_container(m
);
979 return bus_log_create_error(r
);
981 r
= sd_bus_message_close_container(m
);
983 return bus_log_create_error(r
);
985 r
= sd_bus_message_close_container(m
);
987 return bus_log_create_error(r
);
992 if (STR_IN_SET(field
, "StandardInput",
995 const char *n
, *appended
;
997 if ((n
= startswith(eq
, "fd:"))) {
998 appended
= strjoina(field
, "FileDescriptorName");
999 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1000 } else if ((n
= startswith(eq
, "file:"))) {
1001 appended
= strjoina(field
, "File");
1002 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1003 } else if ((n
= startswith(eq
, "append:"))) {
1004 appended
= strjoina(field
, "FileToAppend");
1005 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1007 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1009 return bus_log_create_error(r
);
1014 if (streq(field
, "StandardInputText")) {
1015 _cleanup_free_
char *unescaped
= NULL
;
1017 r
= cunescape(eq
, 0, &unescaped
);
1019 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
1021 if (!strextend(&unescaped
, "\n", NULL
))
1024 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
1025 * interface anyway */
1027 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
1030 if (streq(field
, "StandardInputData")) {
1031 _cleanup_free_
void *decoded
= NULL
;
1034 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
1036 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1038 return bus_append_byte_array(m
, field
, decoded
, sz
);
1041 if ((suffix
= startswith(field
, "Limit"))) {
1044 rl
= rlimit_from_string(suffix
);
1049 r
= rlimit_parse(rl
, eq
, &l
);
1051 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1053 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
1055 return bus_log_create_error(r
);
1057 sn
= strjoina(field
, "Soft");
1058 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1060 return bus_log_create_error(r
);
1066 if (STR_IN_SET(field
, "AppArmorProfile",
1067 "SmackProcessLabel")) {
1076 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1078 return bus_log_create_error(r
);
1083 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1084 "AmbientCapabilities")) {
1086 bool invert
= false;
1094 r
= capability_set_from_string(p
, &sum
);
1096 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1098 sum
= invert
? ~sum
: sum
;
1100 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1102 return bus_log_create_error(r
);
1107 if (streq(field
, "CPUAffinity")) {
1108 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1109 _cleanup_free_
uint8_t *array
= NULL
;
1112 if (eq
&& streq(eq
, "numa")) {
1113 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1115 return bus_log_create_error(r
);
1119 r
= parse_cpu_set(eq
, &cpuset
);
1121 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1123 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1125 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1127 return bus_append_byte_array(m
, field
, array
, allocated
);
1130 if (streq(field
, "NUMAPolicy")) {
1131 r
= mpol_from_string(eq
);
1133 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1135 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1137 return bus_log_create_error(r
);
1142 if (streq(field
, "NUMAMask")) {
1143 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1144 _cleanup_free_
uint8_t *array
= NULL
;
1147 r
= parse_cpu_set(eq
, &nodes
);
1149 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1151 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1153 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1155 return bus_append_byte_array(m
, field
, array
, allocated
);
1158 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1159 "SystemCallFilter")) {
1168 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1170 return bus_log_create_error(r
);
1172 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1174 return bus_log_create_error(r
);
1176 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1178 return bus_log_create_error(r
);
1180 r
= sd_bus_message_open_container(m
, 'r', "bas");
1182 return bus_log_create_error(r
);
1184 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
1186 return bus_log_create_error(r
);
1188 r
= sd_bus_message_open_container(m
, 'a', "s");
1190 return bus_log_create_error(r
);
1193 _cleanup_free_
char *word
= NULL
;
1195 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1201 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1203 r
= sd_bus_message_append_basic(m
, 's', word
);
1205 return bus_log_create_error(r
);
1208 r
= sd_bus_message_close_container(m
);
1210 return bus_log_create_error(r
);
1212 r
= sd_bus_message_close_container(m
);
1214 return bus_log_create_error(r
);
1216 r
= sd_bus_message_close_container(m
);
1218 return bus_log_create_error(r
);
1220 r
= sd_bus_message_close_container(m
);
1222 return bus_log_create_error(r
);
1227 if (streq(field
, "RestrictNamespaces")) {
1228 bool invert
= false;
1229 unsigned long flags
;
1231 r
= parse_boolean(eq
);
1235 flags
= NAMESPACE_FLAGS_ALL
;
1242 r
= namespace_flags_from_string(eq
, &flags
);
1244 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1248 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1250 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1252 return bus_log_create_error(r
);
1257 if (STR_IN_SET(field
, "BindPaths",
1258 "BindReadOnlyPaths")) {
1261 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1263 return bus_log_create_error(r
);
1265 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1267 return bus_log_create_error(r
);
1269 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1271 return bus_log_create_error(r
);
1273 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1275 return bus_log_create_error(r
);
1278 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1279 char *s
= NULL
, *d
= NULL
;
1280 bool ignore_enoent
= false;
1281 uint64_t flags
= MS_REC
;
1283 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1285 return log_error_errno(r
, "Failed to parse argument: %m");
1291 ignore_enoent
= true;
1295 if (p
&& p
[-1] == ':') {
1296 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1298 return log_error_errno(r
, "Failed to parse argument: %m");
1300 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1301 "Missing argument after ':': %s",
1306 if (p
&& p
[-1] == ':') {
1307 _cleanup_free_
char *options
= NULL
;
1309 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1311 return log_error_errno(r
, "Failed to parse argument: %m");
1313 if (isempty(options
) || streq(options
, "rbind"))
1315 else if (streq(options
, "norbind"))
1318 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1319 "Unknown options: %s",
1325 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1327 return bus_log_create_error(r
);
1330 r
= sd_bus_message_close_container(m
);
1332 return bus_log_create_error(r
);
1334 r
= sd_bus_message_close_container(m
);
1336 return bus_log_create_error(r
);
1338 r
= sd_bus_message_close_container(m
);
1340 return bus_log_create_error(r
);
1345 if (streq(field
, "TemporaryFileSystem")) {
1348 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1350 return bus_log_create_error(r
);
1352 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1354 return bus_log_create_error(r
);
1356 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1358 return bus_log_create_error(r
);
1360 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1362 return bus_log_create_error(r
);
1365 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1368 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1370 return log_error_errno(r
, "Failed to parse argument: %m");
1375 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1377 return log_error_errno(r
, "Failed to parse argument: %m");
1379 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1380 "Failed to parse argument: %s",
1383 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1385 return bus_log_create_error(r
);
1388 r
= sd_bus_message_close_container(m
);
1390 return bus_log_create_error(r
);
1392 r
= sd_bus_message_close_container(m
);
1394 return bus_log_create_error(r
);
1396 r
= sd_bus_message_close_container(m
);
1398 return bus_log_create_error(r
);
1406 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1407 if (streq(field
, "KillMode"))
1408 return bus_append_string(m
, field
, eq
);
1410 if (STR_IN_SET(field
, "SendSIGHUP",
1412 return bus_append_parse_boolean(m
, field
, eq
);
1414 if (STR_IN_SET(field
, "KillSignal",
1415 "RestartKillSignal",
1418 return bus_append_signal_from_string(m
, field
, eq
);
1423 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1425 if (STR_IN_SET(field
, "What",
1429 return bus_append_string(m
, field
, eq
);
1431 if (streq(field
, "TimeoutSec"))
1432 return bus_append_parse_sec_rename(m
, field
, eq
);
1434 if (streq(field
, "DirectoryMode"))
1435 return bus_append_parse_mode(m
, field
, eq
);
1437 if (STR_IN_SET(field
, "SloppyOptions",
1440 return bus_append_parse_boolean(m
, field
, eq
);
1445 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1448 if (streq(field
, "MakeDirectory"))
1449 return bus_append_parse_boolean(m
, field
, eq
);
1451 if (streq(field
, "DirectoryMode"))
1452 return bus_append_parse_mode(m
, field
, eq
);
1454 if (STR_IN_SET(field
, "PathExists",
1458 "DirectoryNotEmpty")) {
1460 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1462 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1464 return bus_log_create_error(r
);
1472 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1473 if (streq(field
, "RuntimeMaxSec"))
1474 return bus_append_parse_sec_rename(m
, field
, eq
);
1476 if (streq(field
, "TimeoutStopSec"))
1477 return bus_append_parse_sec_rename(m
, field
, eq
);
1482 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1485 if (STR_IN_SET(field
, "PIDFile",
1490 "USBFunctionDescriptors",
1491 "USBFunctionStrings",
1493 return bus_append_string(m
, field
, eq
);
1495 if (STR_IN_SET(field
, "PermissionsStartOnly",
1496 "RootDirectoryStartOnly",
1499 return bus_append_parse_boolean(m
, field
, eq
);
1501 if (STR_IN_SET(field
, "RestartSec",
1507 return bus_append_parse_sec_rename(m
, field
, eq
);
1509 if (streq(field
, "TimeoutSec")) {
1510 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1514 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1517 if (streq(field
, "FileDescriptorStoreMax"))
1518 return bus_append_safe_atou(m
, field
, eq
);
1520 if (STR_IN_SET(field
, "ExecCondition",
1534 return bus_append_exec_command(m
, field
, eq
);
1536 if (STR_IN_SET(field
, "RestartPreventExitStatus",
1537 "RestartForceExitStatus",
1538 "SuccessExitStatus")) {
1539 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1540 size_t n_status
= 0, n_signal
= 0;
1544 _cleanup_free_
char *word
= NULL
;
1546 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1552 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1554 /* We need to call exit_status_from_string() first, because we want
1555 * to parse numbers as exit statuses, not signals. */
1557 r
= exit_status_from_string(word
);
1559 assert(r
>= 0 && r
< 256);
1561 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
1565 status
[n_status
++] = r
;
1567 } else if ((r
= signal_from_string(word
)) >= 0) {
1568 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
1572 signal
[n_signal
++] = r
;
1575 /* original r from exit_status_to_string() */
1576 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
1580 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1582 return bus_log_create_error(r
);
1584 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1586 return bus_log_create_error(r
);
1588 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1590 return bus_log_create_error(r
);
1592 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1594 return bus_log_create_error(r
);
1596 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
1598 return bus_log_create_error(r
);
1600 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
1602 return bus_log_create_error(r
);
1604 r
= sd_bus_message_close_container(m
);
1606 return bus_log_create_error(r
);
1608 r
= sd_bus_message_close_container(m
);
1610 return bus_log_create_error(r
);
1612 r
= sd_bus_message_close_container(m
);
1614 return bus_log_create_error(r
);
1622 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1625 if (STR_IN_SET(field
, "Accept",
1636 "SELinuxContextFromNet"))
1637 return bus_append_parse_boolean(m
, field
, eq
);
1639 if (STR_IN_SET(field
, "Priority",
1642 return bus_append_safe_atoi(m
, field
, eq
);
1644 if (streq(field
, "IPTOS"))
1645 return bus_append_ip_tos_from_string(m
, field
, eq
);
1647 if (STR_IN_SET(field
, "Backlog",
1649 "MaxConnectionsPerSource",
1651 "TriggerLimitBurst"))
1652 return bus_append_safe_atou(m
, field
, eq
);
1654 if (STR_IN_SET(field
, "SocketMode",
1656 return bus_append_parse_mode(m
, field
, eq
);
1658 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
1659 "MessageQueueMessageSize"))
1660 return bus_append_safe_atoi64(m
, field
, eq
);
1662 if (STR_IN_SET(field
, "TimeoutSec",
1664 "KeepAliveIntervalSec",
1666 "TriggerLimitIntervalSec"))
1667 return bus_append_parse_sec_rename(m
, field
, eq
);
1669 if (STR_IN_SET(field
, "ReceiveBuffer",
1672 return bus_append_parse_size(m
, field
, eq
, 1024);
1674 if (STR_IN_SET(field
, "ExecStartPre",
1678 return bus_append_exec_command(m
, field
, eq
);
1680 if (STR_IN_SET(field
, "SmackLabel",
1686 "FileDescriptorName",
1689 return bus_append_string(m
, field
, eq
);
1691 if (streq(field
, "Symlinks"))
1692 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1694 if (streq(field
, "SocketProtocol"))
1695 return bus_append_parse_ip_protocol(m
, field
, eq
);
1697 if (STR_IN_SET(field
, "ListenStream",
1699 "ListenSequentialPacket",
1702 "ListenMessageQueue",
1704 "ListenUSBFunction")) {
1706 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1708 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1710 return bus_log_create_error(r
);
1717 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1720 if (STR_IN_SET(field
, "WakeSystem",
1721 "RemainAfterElapse",
1725 return bus_append_parse_boolean(m
, field
, eq
);
1727 if (STR_IN_SET(field
, "AccuracySec",
1728 "RandomizedDelaySec"))
1729 return bus_append_parse_sec_rename(m
, field
, eq
);
1731 if (STR_IN_SET(field
, "OnActiveSec",
1735 "OnUnitInactiveSec")) {
1737 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1740 r
= parse_sec(eq
, &t
);
1742 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1744 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1747 return bus_log_create_error(r
);
1752 if (streq(field
, "OnCalendar")) {
1754 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1756 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1758 return bus_log_create_error(r
);
1766 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1767 ConditionType t
= _CONDITION_TYPE_INVALID
;
1768 bool is_condition
= false;
1771 if (STR_IN_SET(field
, "Description",
1775 "JobTimeoutRebootArgument",
1781 return bus_append_string(m
, field
, eq
);
1783 if (STR_IN_SET(field
, "StopWhenUnneeded",
1784 "RefuseManualStart",
1788 "DefaultDependencies"))
1789 return bus_append_parse_boolean(m
, field
, eq
);
1791 if (STR_IN_SET(field
, "JobTimeoutSec",
1792 "JobRunningTimeoutSec",
1793 "StartLimitIntervalSec"))
1794 return bus_append_parse_sec_rename(m
, field
, eq
);
1796 if (streq(field
, "StartLimitBurst"))
1797 return bus_append_safe_atou(m
, field
, eq
);
1799 if (STR_IN_SET(field
, "SuccessActionExitStatus",
1800 "FailureActionExitStatus")) {
1802 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1806 r
= safe_atou8(eq
, &u
);
1808 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1810 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1813 return bus_log_create_error(r
);
1818 if (unit_dependency_from_string(field
) >= 0 ||
1819 STR_IN_SET(field
, "Documentation",
1820 "RequiresMountsFor"))
1821 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1823 t
= condition_type_from_string(field
);
1825 is_condition
= true;
1827 t
= assert_type_from_string(field
);
1830 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1833 int trigger
, negate
;
1835 trigger
= *p
== '|';
1843 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1844 field
, trigger
, negate
, p
);
1847 return bus_log_create_error(r
);
1855 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1856 const char *eq
, *field
;
1862 eq
= strchr(assignment
, '=');
1864 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1865 "Not an assignment: %s", assignment
);
1867 field
= strndupa(assignment
, eq
- assignment
);
1872 r
= bus_append_cgroup_property(m
, field
, eq
);
1876 r
= bus_append_execute_property(m
, field
, eq
);
1880 r
= bus_append_kill_property(m
, field
, eq
);
1884 r
= bus_append_service_property(m
, field
, eq
);
1890 r
= bus_append_cgroup_property(m
, field
, eq
);
1894 r
= bus_append_execute_property(m
, field
, eq
);
1898 r
= bus_append_kill_property(m
, field
, eq
);
1902 r
= bus_append_socket_property(m
, field
, eq
);
1908 r
= bus_append_timer_property(m
, field
, eq
);
1914 r
= bus_append_path_property(m
, field
, eq
);
1920 r
= bus_append_cgroup_property(m
, field
, eq
);
1926 r
= bus_append_cgroup_property(m
, field
, eq
);
1930 r
= bus_append_kill_property(m
, field
, eq
);
1934 r
= bus_append_scope_property(m
, field
, eq
);
1940 r
= bus_append_cgroup_property(m
, field
, eq
);
1944 r
= bus_append_execute_property(m
, field
, eq
);
1948 r
= bus_append_kill_property(m
, field
, eq
);
1952 r
= bus_append_mount_property(m
, field
, eq
);
1958 case UNIT_AUTOMOUNT
:
1959 r
= bus_append_automount_property(m
, field
, eq
);
1968 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1969 "Not supported unit type");
1972 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1973 "Invalid unit type");
1976 r
= bus_append_unit_property(m
, field
, eq
);
1980 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1981 "Unknown assignment: %s", assignment
);
1984 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1990 STRV_FOREACH(i
, l
) {
1991 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1999 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
2000 const char *type
, *path
, *source
;
2003 /* changes is dereferenced when calling unit_file_dump_changes() later,
2004 * so we have to make sure this is not NULL. */
2008 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2010 return bus_log_parse_error(r
);
2012 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2013 /* We expect only "success" changes to be sent over the bus.
2014 Hence, reject anything negative. */
2015 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
2018 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
2022 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2027 return bus_log_parse_error(r
);
2029 r
= sd_bus_message_exit_container(m
);
2031 return bus_log_parse_error(r
);
2033 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2037 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2038 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2039 _cleanup_free_
char *path
= NULL
;
2042 path
= unit_dbus_path_from_name(name
);
2046 /* This function warns on it's own, because otherwise it'd be awkward to pass
2047 * the dbus error message around. */
2049 r
= sd_bus_get_property_string(
2051 "org.freedesktop.systemd1",
2053 "org.freedesktop.systemd1.Unit",
2058 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));