1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
5 #include "bus-unit-util.h"
8 #include "cgroup-util.h"
10 #include "cpu-set-util.h"
12 #include "exec-util.h"
13 #include "hexdecoct.h"
14 #include "hostname-util.h"
15 #include "in-addr-util.h"
16 #include "ip-protocol-list.h"
17 #include "locale-util.h"
19 #include "missing_fs.h"
20 #include "mountpoint-util.h"
22 #include "parse-util.h"
23 #include "process-util.h"
24 #include "rlimit-util.h"
25 #include "securebits-util.h"
26 #include "signal-util.h"
27 #include "socket-util.h"
28 #include "sort-util.h"
29 #include "string-util.h"
30 #include "syslog-util.h"
31 #include "terminal-util.h"
33 #include "user-util.h"
36 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
42 return sd_bus_message_read(
57 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
58 static int bus_append_##parse_func( \
65 r = parse_func(eq, &val); \
67 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
69 r = sd_bus_message_append(m, "(sv)", field, \
70 bus_type, (cast_type) val); \
72 return bus_log_create_error(r); \
77 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
78 static int bus_append_##parse_func( \
86 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
88 r = sd_bus_message_append(m, "(sv)", field, \
89 bus_type, (int32_t) r); \
91 return bus_log_create_error(r); \
96 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
97 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
98 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
99 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
100 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
101 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
102 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
103 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
104 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
105 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
106 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
107 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
108 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
109 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
110 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
111 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
112 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
113 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
114 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
115 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
116 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
117 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
119 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
122 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
124 return bus_log_create_error(r
);
129 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
133 r
= sd_bus_message_open_container(m
, 'r', "sv");
135 return bus_log_create_error(r
);
137 r
= sd_bus_message_append_basic(m
, 's', field
);
139 return bus_log_create_error(r
);
141 r
= sd_bus_message_open_container(m
, 'v', "as");
143 return bus_log_create_error(r
);
145 r
= sd_bus_message_open_container(m
, 'a', "s");
147 return bus_log_create_error(r
);
150 _cleanup_free_
char *word
= NULL
;
152 r
= extract_first_word(&p
, &word
, NULL
, flags
);
158 return log_error_errno(r
, "Invalid syntax: %s", eq
);
160 r
= sd_bus_message_append_basic(m
, 's', word
);
162 return bus_log_create_error(r
);
165 r
= sd_bus_message_close_container(m
);
167 return bus_log_create_error(r
);
169 r
= sd_bus_message_close_container(m
);
171 return bus_log_create_error(r
);
173 r
= sd_bus_message_close_container(m
);
175 return bus_log_create_error(r
);
180 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
183 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
185 return bus_log_create_error(r
);
187 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
189 return bus_log_create_error(r
);
191 r
= sd_bus_message_open_container(m
, 'v', "ay");
193 return bus_log_create_error(r
);
195 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
197 return bus_log_create_error(r
);
199 r
= sd_bus_message_close_container(m
);
201 return bus_log_create_error(r
);
203 r
= sd_bus_message_close_container(m
);
205 return bus_log_create_error(r
);
210 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
216 r
= parse_sec(eq
, &t
);
218 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
221 n
= newa(char, l
+ 2);
222 /* Change suffix Sec → USec */
223 strcpy(mempcpy(n
, field
, l
- 3), "USec");
225 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
227 return bus_log_create_error(r
);
232 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
236 r
= parse_size(eq
, base
, &v
);
238 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
240 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
242 return bus_log_create_error(r
);
247 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
248 bool explicit_path
= false, done
= false;
249 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
250 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
251 ExecCommandFlags flags
= 0;
252 bool is_ex_prop
= endswith(field
, "Ex");
259 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
262 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
271 explicit_path
= true;
277 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
280 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
286 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
289 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
295 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
297 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
298 flags
&= ~EXEC_COMMAND_NO_SETUID
;
299 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
302 flags
|= EXEC_COMMAND_NO_SETUID
;
313 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
314 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
316 upgraded_name
= strappend(field
, "Ex");
322 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
324 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
328 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
330 return log_error_errno(r
, "Failed to parse path: %m");
333 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
335 return log_error_errno(r
, "Failed to parse command line: %m");
337 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
339 return bus_log_create_error(r
);
341 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
343 return bus_log_create_error(r
);
345 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
347 return bus_log_create_error(r
);
349 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
351 return bus_log_create_error(r
);
353 if (!strv_isempty(l
)) {
355 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
357 return bus_log_create_error(r
);
359 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
361 return bus_log_create_error(r
);
363 r
= sd_bus_message_append_strv(m
, l
);
365 return bus_log_create_error(r
);
367 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
));
369 return bus_log_create_error(r
);
371 r
= sd_bus_message_close_container(m
);
373 return bus_log_create_error(r
);
376 r
= sd_bus_message_close_container(m
);
378 return bus_log_create_error(r
);
380 r
= sd_bus_message_close_container(m
);
382 return bus_log_create_error(r
);
384 r
= sd_bus_message_close_container(m
);
386 return bus_log_create_error(r
);
391 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
397 r
= sd_bus_message_open_container(m
, 'r', "iayu");
401 r
= sd_bus_message_append(m
, "i", family
);
405 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
409 r
= sd_bus_message_append(m
, "u", prefixlen
);
413 return sd_bus_message_close_container(m
);
416 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
419 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
421 return bus_append_string(m
, field
, eq
);
423 if (STR_IN_SET(field
,
424 "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
425 "TasksAccounting", "IPAccounting"))
427 return bus_append_parse_boolean(m
, field
, eq
);
429 if (STR_IN_SET(field
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
431 return bus_append_cg_weight_parse(m
, field
, eq
);
433 if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares"))
435 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
437 if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight"))
439 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
441 if (streq(field
, "DisableControllers"))
443 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_QUOTES
);
445 if (streq(field
, "Delegate")) {
447 r
= parse_boolean(eq
);
449 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_QUOTES
);
451 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
453 return bus_log_create_error(r
);
458 if (STR_IN_SET(field
, "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
460 if (isempty(eq
) || streq(eq
, "infinity")) {
461 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
463 return bus_log_create_error(r
);
467 r
= parse_permille(eq
);
471 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
472 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
473 * size can be determined server-side. */
475 n
= strjoina(field
, "Scale");
476 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
478 return bus_log_create_error(r
);
483 if (streq(field
, "TasksMax"))
484 return bus_append_safe_atou64(m
, field
, eq
);
486 return bus_append_parse_size(m
, field
, eq
, 1024);
489 if (streq(field
, "CPUQuota")) {
492 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
494 r
= parse_permille_unbounded(eq
);
496 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
497 "CPU quota too small.");
499 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
501 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
505 return bus_log_create_error(r
);
510 if (streq(field
, "CPUQuotaPeriodSec")) {
511 usec_t u
= USEC_INFINITY
;
513 r
= parse_sec_def_infinity(eq
, &u
);
515 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
517 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
519 return bus_log_create_error(r
);
524 if (streq(field
, "DeviceAllow")) {
527 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
529 const char *path
= eq
, *rwm
= NULL
, *e
;
533 path
= strndupa(eq
, e
- eq
);
537 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
541 return bus_log_create_error(r
);
546 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
549 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
551 const char *path
, *bandwidth
, *e
;
556 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
557 "Failed to parse %s value %s.",
560 path
= strndupa(eq
, e
- eq
);
563 if (streq(bandwidth
, "infinity"))
564 bytes
= CGROUP_LIMIT_MAX
;
566 r
= parse_size(bandwidth
, 1000, &bytes
);
568 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
571 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
575 return bus_log_create_error(r
);
580 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
583 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
585 const char *path
, *weight
, *e
;
590 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
591 "Failed to parse %s value %s.",
594 path
= strndupa(eq
, e
- eq
);
597 r
= safe_atou64(weight
, &u
);
599 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
601 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
605 return bus_log_create_error(r
);
610 if (streq(field
, "IODeviceLatencyTargetSec")) {
611 const char *field_usec
= "IODeviceLatencyTargetUSec";
614 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
616 const char *path
, *target
, *e
;
621 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
622 "Failed to parse %s value %s.",
625 path
= strndupa(eq
, e
- eq
);
628 r
= parse_sec(target
, &usec
);
630 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
632 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
636 return bus_log_create_error(r
);
641 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
642 unsigned char prefixlen
;
643 union in_addr_union prefix
= {};
647 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
649 return bus_log_create_error(r
);
654 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
656 return bus_log_create_error(r
);
658 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
660 return bus_log_create_error(r
);
662 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
664 return bus_log_create_error(r
);
666 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
668 return bus_log_create_error(r
);
670 if (streq(eq
, "any")) {
671 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
673 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
675 return bus_log_create_error(r
);
677 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
679 return bus_log_create_error(r
);
681 } else if (is_localhost(eq
)) {
682 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
684 prefix
.in
.s_addr
= htobe32(0x7f000000);
685 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
687 return bus_log_create_error(r
);
689 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
690 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
694 } else if (streq(eq
, "link-local")) {
695 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
697 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
698 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
700 return bus_log_create_error(r
);
702 prefix
.in6
= (struct in6_addr
) {
703 .s6_addr32
[0] = htobe32(0xfe800000)
705 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
707 return bus_log_create_error(r
);
709 } else if (streq(eq
, "multicast")) {
710 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
712 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
713 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
715 return bus_log_create_error(r
);
717 prefix
.in6
= (struct in6_addr
) {
718 .s6_addr32
[0] = htobe32(0xff000000)
720 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
722 return bus_log_create_error(r
);
726 _cleanup_free_
char *word
= NULL
;
728 r
= extract_first_word(&eq
, &word
, NULL
, 0);
734 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
736 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
738 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
740 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
742 return bus_log_create_error(r
);
746 r
= sd_bus_message_close_container(m
);
748 return bus_log_create_error(r
);
750 r
= sd_bus_message_close_container(m
);
752 return bus_log_create_error(r
);
754 r
= sd_bus_message_close_container(m
);
756 return bus_log_create_error(r
);
764 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
766 if (streq(field
, "Where"))
768 return bus_append_string(m
, field
, eq
);
770 if (streq(field
, "DirectoryMode"))
772 return bus_append_parse_mode(m
, field
, eq
);
774 if (streq(field
, "TimeoutIdleSec"))
776 return bus_append_parse_sec_rename(m
, field
, eq
);
781 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
785 if (STR_IN_SET(field
,
787 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
788 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
789 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
790 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
792 return bus_append_string(m
, field
, eq
);
794 if (STR_IN_SET(field
,
795 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
796 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
797 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
798 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
799 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
800 "ProtectHostname", "RestrictSUIDSGID"))
802 return bus_append_parse_boolean(m
, field
, eq
);
804 if (STR_IN_SET(field
,
805 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
806 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
807 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
808 "SupplementaryGroups", "SystemCallArchitectures"))
810 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
812 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
814 return bus_append_log_level_from_string(m
, field
, eq
);
816 if (streq(field
, "SyslogFacility"))
818 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
820 if (streq(field
, "SecureBits"))
822 return bus_append_secure_bits_from_string(m
, field
, eq
);
824 if (streq(field
, "CPUSchedulingPolicy"))
826 return bus_append_sched_policy_from_string(m
, field
, eq
);
828 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
830 return bus_append_safe_atoi(m
, field
, eq
);
832 if (streq(field
, "Nice"))
834 return bus_append_parse_nice(m
, field
, eq
);
836 if (streq(field
, "SystemCallErrorNumber"))
838 return bus_append_parse_errno(m
, field
, eq
);
840 if (streq(field
, "IOSchedulingClass"))
842 return bus_append_ioprio_class_from_string(m
, field
, eq
);
844 if (streq(field
, "IOSchedulingPriority"))
846 return bus_append_ioprio_parse_priority(m
, field
, eq
);
848 if (STR_IN_SET(field
,
849 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
850 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
852 return bus_append_parse_mode(m
, field
, eq
);
854 if (streq(field
, "TimerSlackNSec"))
856 return bus_append_parse_nsec(m
, field
, eq
);
858 if (streq(field
, "LogRateLimitIntervalSec"))
860 return bus_append_parse_sec_rename(m
, field
, eq
);
862 if (streq(field
, "LogRateLimitBurst"))
864 return bus_append_safe_atou(m
, field
, eq
);
866 if (streq(field
, "MountFlags"))
868 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
870 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
872 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
874 if (streq(field
, "EnvironmentFile")) {
877 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
879 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
880 eq
[0] == '-' ? eq
+ 1 : eq
,
883 return bus_log_create_error(r
);
888 if (streq(field
, "LogExtraFields")) {
890 r
= sd_bus_message_open_container(m
, 'r', "sv");
892 return bus_log_create_error(r
);
894 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
896 return bus_log_create_error(r
);
898 r
= sd_bus_message_open_container(m
, 'v', "aay");
900 return bus_log_create_error(r
);
902 r
= sd_bus_message_open_container(m
, 'a', "ay");
904 return bus_log_create_error(r
);
906 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
908 return bus_log_create_error(r
);
910 r
= sd_bus_message_close_container(m
);
912 return bus_log_create_error(r
);
914 r
= sd_bus_message_close_container(m
);
916 return bus_log_create_error(r
);
918 r
= sd_bus_message_close_container(m
);
920 return bus_log_create_error(r
);
925 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
926 const char *n
, *appended
;
928 if ((n
= startswith(eq
, "fd:"))) {
929 appended
= strjoina(field
, "FileDescriptorName");
930 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
931 } else if ((n
= startswith(eq
, "file:"))) {
932 appended
= strjoina(field
, "File");
933 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
934 } else if ((n
= startswith(eq
, "append:"))) {
935 appended
= strjoina(field
, "FileToAppend");
936 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
938 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
940 return bus_log_create_error(r
);
945 if (streq(field
, "StandardInputText")) {
946 _cleanup_free_
char *unescaped
= NULL
;
948 r
= cunescape(eq
, 0, &unescaped
);
950 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
952 if (!strextend(&unescaped
, "\n", NULL
))
955 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
956 * interface anyway */
958 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
961 if (streq(field
, "StandardInputData")) {
962 _cleanup_free_
void *decoded
= NULL
;
965 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
967 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
969 return bus_append_byte_array(m
, field
, decoded
, sz
);
972 if ((suffix
= startswith(field
, "Limit"))) {
975 rl
= rlimit_from_string(suffix
);
980 r
= rlimit_parse(rl
, eq
, &l
);
982 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
984 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
986 return bus_log_create_error(r
);
988 sn
= strjoina(field
, "Soft");
989 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
991 return bus_log_create_error(r
);
997 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
1006 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1008 return bus_log_create_error(r
);
1013 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
1015 bool invert
= false;
1023 r
= capability_set_from_string(p
, &sum
);
1025 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1027 sum
= invert
? ~sum
: sum
;
1029 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1031 return bus_log_create_error(r
);
1036 if (streq(field
, "CPUAffinity")) {
1037 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1038 _cleanup_free_
uint8_t *array
= NULL
;
1041 r
= parse_cpu_set(eq
, &cpuset
);
1043 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1045 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1047 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1049 return bus_append_byte_array(m
, field
, array
, allocated
);
1052 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
1061 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1063 return bus_log_create_error(r
);
1065 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1067 return bus_log_create_error(r
);
1069 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1071 return bus_log_create_error(r
);
1073 r
= sd_bus_message_open_container(m
, 'r', "bas");
1075 return bus_log_create_error(r
);
1077 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
1079 return bus_log_create_error(r
);
1081 r
= sd_bus_message_open_container(m
, 'a', "s");
1083 return bus_log_create_error(r
);
1086 _cleanup_free_
char *word
= NULL
;
1088 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1094 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1096 r
= sd_bus_message_append_basic(m
, 's', word
);
1098 return bus_log_create_error(r
);
1101 r
= sd_bus_message_close_container(m
);
1103 return bus_log_create_error(r
);
1105 r
= sd_bus_message_close_container(m
);
1107 return bus_log_create_error(r
);
1109 r
= sd_bus_message_close_container(m
);
1111 return bus_log_create_error(r
);
1113 r
= sd_bus_message_close_container(m
);
1115 return bus_log_create_error(r
);
1120 if (streq(field
, "RestrictNamespaces")) {
1121 bool invert
= false;
1122 unsigned long flags
;
1124 r
= parse_boolean(eq
);
1128 flags
= NAMESPACE_FLAGS_ALL
;
1135 r
= namespace_flags_from_string(eq
, &flags
);
1137 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1141 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1143 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1145 return bus_log_create_error(r
);
1150 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1153 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1155 return bus_log_create_error(r
);
1157 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1159 return bus_log_create_error(r
);
1161 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1163 return bus_log_create_error(r
);
1165 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1167 return bus_log_create_error(r
);
1170 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1171 char *s
= NULL
, *d
= NULL
;
1172 bool ignore_enoent
= false;
1173 uint64_t flags
= MS_REC
;
1175 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1177 return log_error_errno(r
, "Failed to parse argument: %m");
1183 ignore_enoent
= true;
1187 if (p
&& p
[-1] == ':') {
1188 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1190 return log_error_errno(r
, "Failed to parse argument: %m");
1192 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1193 "Missing argument after ':': %s",
1198 if (p
&& p
[-1] == ':') {
1199 _cleanup_free_
char *options
= NULL
;
1201 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
1203 return log_error_errno(r
, "Failed to parse argument: %m");
1205 if (isempty(options
) || streq(options
, "rbind"))
1207 else if (streq(options
, "norbind"))
1210 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1211 "Unknown options: %s",
1217 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1219 return bus_log_create_error(r
);
1222 r
= sd_bus_message_close_container(m
);
1224 return bus_log_create_error(r
);
1226 r
= sd_bus_message_close_container(m
);
1228 return bus_log_create_error(r
);
1230 r
= sd_bus_message_close_container(m
);
1232 return bus_log_create_error(r
);
1237 if (streq(field
, "TemporaryFileSystem")) {
1240 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1242 return bus_log_create_error(r
);
1244 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1246 return bus_log_create_error(r
);
1248 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1250 return bus_log_create_error(r
);
1252 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1254 return bus_log_create_error(r
);
1257 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1260 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1262 return log_error_errno(r
, "Failed to parse argument: %m");
1267 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1269 return log_error_errno(r
, "Failed to parse argument: %m");
1271 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1272 "Failed to parse argument: %s",
1275 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1277 return bus_log_create_error(r
);
1280 r
= sd_bus_message_close_container(m
);
1282 return bus_log_create_error(r
);
1284 r
= sd_bus_message_close_container(m
);
1286 return bus_log_create_error(r
);
1288 r
= sd_bus_message_close_container(m
);
1290 return bus_log_create_error(r
);
1298 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1300 if (streq(field
, "KillMode"))
1302 return bus_append_string(m
, field
, eq
);
1304 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1306 return bus_append_parse_boolean(m
, field
, eq
);
1308 if (STR_IN_SET(field
, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1310 return bus_append_signal_from_string(m
, field
, eq
);
1315 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1317 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1319 return bus_append_string(m
, field
, eq
);
1321 if (streq(field
, "TimeoutSec"))
1323 return bus_append_parse_sec_rename(m
, field
, eq
);
1325 if (streq(field
, "DirectoryMode"))
1327 return bus_append_parse_mode(m
, field
, eq
);
1329 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1331 return bus_append_parse_boolean(m
, field
, eq
);
1336 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1339 if (streq(field
, "MakeDirectory"))
1341 return bus_append_parse_boolean(m
, field
, eq
);
1343 if (streq(field
, "DirectoryMode"))
1345 return bus_append_parse_mode(m
, field
, eq
);
1347 if (STR_IN_SET(field
,
1348 "PathExists", "PathExistsGlob", "PathChanged",
1349 "PathModified", "DirectoryNotEmpty")) {
1352 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1354 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1356 return bus_log_create_error(r
);
1364 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1367 if (STR_IN_SET(field
,
1368 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1369 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
1371 return bus_append_string(m
, field
, eq
);
1373 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1375 return bus_append_parse_boolean(m
, field
, eq
);
1377 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1379 return bus_append_parse_sec_rename(m
, field
, eq
);
1381 if (streq(field
, "TimeoutSec")) {
1383 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1387 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1390 if (streq(field
, "FileDescriptorStoreMax"))
1392 return bus_append_safe_atou(m
, field
, eq
);
1394 if (STR_IN_SET(field
,
1395 "ExecStartPre", "ExecStart", "ExecStartPost",
1396 "ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
1397 "ExecReload", "ExecStop", "ExecStopPost"))
1398 return bus_append_exec_command(m
, field
, eq
);
1400 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1401 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1402 size_t sz_status
= 0, sz_signal
= 0;
1406 _cleanup_free_
char *word
= NULL
;
1409 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1415 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1417 r
= safe_atoi(word
, &val
);
1419 val
= signal_from_string(word
);
1421 return log_error_errno(r
, "Invalid status or signal %s in %s: %m", word
, field
);
1423 signal
= reallocarray(signal
, sz_signal
+ 1, sizeof(int));
1427 signal
[sz_signal
++] = val
;
1429 status
= reallocarray(status
, sz_status
+ 1, sizeof(int));
1433 status
[sz_status
++] = val
;
1437 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1439 return bus_log_create_error(r
);
1441 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1443 return bus_log_create_error(r
);
1445 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1447 return bus_log_create_error(r
);
1449 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1451 return bus_log_create_error(r
);
1453 r
= sd_bus_message_append_array(m
, 'i', status
, sz_status
);
1455 return bus_log_create_error(r
);
1457 r
= sd_bus_message_append_array(m
, 'i', signal
, sz_signal
);
1459 return bus_log_create_error(r
);
1461 r
= sd_bus_message_close_container(m
);
1463 return bus_log_create_error(r
);
1465 r
= sd_bus_message_close_container(m
);
1467 return bus_log_create_error(r
);
1469 r
= sd_bus_message_close_container(m
);
1471 return bus_log_create_error(r
);
1479 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1482 if (STR_IN_SET(field
,
1483 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1484 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1486 return bus_append_parse_boolean(m
, field
, eq
);
1488 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1490 return bus_append_safe_atoi(m
, field
, eq
);
1492 if (streq(field
, "IPTOS"))
1494 return bus_append_ip_tos_from_string(m
, field
, eq
);
1496 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1498 return bus_append_safe_atou(m
, field
, eq
);
1500 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1502 return bus_append_parse_mode(m
, field
, eq
);
1504 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1506 return bus_append_safe_atoi64(m
, field
, eq
);
1508 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1510 return bus_append_parse_sec_rename(m
, field
, eq
);
1512 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1514 return bus_append_parse_size(m
, field
, eq
, 1024);
1516 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1518 return bus_append_exec_command(m
, field
, eq
);
1520 if (STR_IN_SET(field
,
1521 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1522 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1523 "SocketUser", "SocketGroup"))
1525 return bus_append_string(m
, field
, eq
);
1527 if (streq(field
, "Symlinks"))
1529 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1531 if (streq(field
, "SocketProtocol"))
1533 return bus_append_parse_ip_protocol(m
, field
, eq
);
1535 if (STR_IN_SET(field
,
1536 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1537 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1540 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1542 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1544 return bus_log_create_error(r
);
1551 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1554 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent",
1555 "OnTimezoneChange", "OnClockChange"))
1557 return bus_append_parse_boolean(m
, field
, eq
);
1559 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1561 return bus_append_parse_sec_rename(m
, field
, eq
);
1563 if (STR_IN_SET(field
,
1564 "OnActiveSec", "OnBootSec", "OnStartupSec",
1565 "OnUnitActiveSec","OnUnitInactiveSec")) {
1568 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1571 r
= parse_sec(eq
, &t
);
1573 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1575 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1578 return bus_log_create_error(r
);
1583 if (streq(field
, "OnCalendar")) {
1586 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1588 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1590 return bus_log_create_error(r
);
1598 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1599 ConditionType t
= _CONDITION_TYPE_INVALID
;
1600 bool is_condition
= false;
1603 if (STR_IN_SET(field
,
1604 "Description", "SourcePath", "OnFailureJobMode",
1605 "JobTimeoutAction", "JobTimeoutRebootArgument",
1606 "StartLimitAction", "FailureAction", "SuccessAction",
1607 "RebootArgument", "CollectMode"))
1609 return bus_append_string(m
, field
, eq
);
1611 if (STR_IN_SET(field
,
1612 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1613 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1615 return bus_append_parse_boolean(m
, field
, eq
);
1617 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1619 return bus_append_parse_sec_rename(m
, field
, eq
);
1621 if (streq(field
, "StartLimitBurst"))
1623 return bus_append_safe_atou(m
, field
, eq
);
1625 if (STR_IN_SET(field
, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1628 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1632 r
= safe_atou8(eq
, &u
);
1634 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1636 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1639 return bus_log_create_error(r
);
1644 if (unit_dependency_from_string(field
) >= 0 ||
1645 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1647 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1649 t
= condition_type_from_string(field
);
1651 is_condition
= true;
1653 t
= assert_type_from_string(field
);
1656 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1659 int trigger
, negate
;
1661 trigger
= *p
== '|';
1669 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1670 field
, trigger
, negate
, p
);
1673 return bus_log_create_error(r
);
1681 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1682 const char *eq
, *field
;
1688 eq
= strchr(assignment
, '=');
1690 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1691 "Not an assignment: %s", assignment
);
1693 field
= strndupa(assignment
, eq
- assignment
);
1698 r
= bus_append_cgroup_property(m
, field
, eq
);
1702 r
= bus_append_execute_property(m
, field
, eq
);
1706 r
= bus_append_kill_property(m
, field
, eq
);
1710 r
= bus_append_service_property(m
, field
, eq
);
1716 r
= bus_append_cgroup_property(m
, field
, eq
);
1720 r
= bus_append_execute_property(m
, field
, eq
);
1724 r
= bus_append_kill_property(m
, field
, eq
);
1728 r
= bus_append_socket_property(m
, field
, eq
);
1734 r
= bus_append_timer_property(m
, field
, eq
);
1740 r
= bus_append_path_property(m
, field
, eq
);
1746 r
= bus_append_cgroup_property(m
, field
, eq
);
1753 if (streq(field
, "TimeoutStopSec"))
1754 return bus_append_parse_sec_rename(m
, field
, eq
);
1756 r
= bus_append_cgroup_property(m
, field
, eq
);
1760 r
= bus_append_kill_property(m
, field
, eq
);
1766 r
= bus_append_cgroup_property(m
, field
, eq
);
1770 r
= bus_append_execute_property(m
, field
, eq
);
1774 r
= bus_append_kill_property(m
, field
, eq
);
1778 r
= bus_append_mount_property(m
, field
, eq
);
1784 case UNIT_AUTOMOUNT
:
1785 r
= bus_append_automount_property(m
, field
, eq
);
1794 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1795 "Not supported unit type");
1798 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1799 "Invalid unit type");
1802 r
= bus_append_unit_property(m
, field
, eq
);
1806 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1807 "Unknown assignment: %s", assignment
);
1810 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1816 STRV_FOREACH(i
, l
) {
1817 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1825 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
1826 const char *type
, *path
, *source
;
1829 /* changes is dereferenced when calling unit_file_dump_changes() later,
1830 * so we have to make sure this is not NULL. */
1834 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1836 return bus_log_parse_error(r
);
1838 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1839 /* We expect only "success" changes to be sent over the bus.
1840 Hence, reject anything negative. */
1841 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1844 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1848 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1853 return bus_log_parse_error(r
);
1855 r
= sd_bus_message_exit_container(m
);
1857 return bus_log_parse_error(r
);
1859 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
1863 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
1864 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1865 _cleanup_free_
char *path
= NULL
;
1868 path
= unit_dbus_path_from_name(name
);
1872 /* This function warns on it's own, because otherwise it'd be awkward to pass
1873 * the dbus error message around. */
1875 r
= sd_bus_get_property_string(
1877 "org.freedesktop.systemd1",
1879 "org.freedesktop.systemd1.Unit",
1884 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));