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 "hexdecoct.h"
13 #include "hostname-util.h"
14 #include "in-addr-util.h"
15 #include "ip-protocol-list.h"
16 #include "locale-util.h"
18 #include "missing_fs.h"
19 #include "mountpoint-util.h"
21 #include "parse-util.h"
22 #include "process-util.h"
23 #include "rlimit-util.h"
24 #include "securebits-util.h"
25 #include "signal-util.h"
26 #include "socket-util.h"
27 #include "sort-util.h"
28 #include "string-util.h"
29 #include "syslog-util.h"
30 #include "terminal-util.h"
32 #include "user-util.h"
35 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
41 return sd_bus_message_read(
56 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
57 static int bus_append_##parse_func( \
64 r = parse_func(eq, &val); \
66 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
68 r = sd_bus_message_append(m, "(sv)", field, \
69 bus_type, (cast_type) val); \
71 return bus_log_create_error(r); \
76 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
77 static int bus_append_##parse_func( \
85 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
87 r = sd_bus_message_append(m, "(sv)", field, \
88 bus_type, (int32_t) r); \
90 return bus_log_create_error(r); \
95 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
96 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
97 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
98 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
99 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
100 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
101 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
102 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
103 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
104 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
105 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
106 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
107 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
108 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
109 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
110 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
111 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
112 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
113 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
114 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
115 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
116 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
118 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
121 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
123 return bus_log_create_error(r
);
128 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
132 r
= sd_bus_message_open_container(m
, 'r', "sv");
134 return bus_log_create_error(r
);
136 r
= sd_bus_message_append_basic(m
, 's', field
);
138 return bus_log_create_error(r
);
140 r
= sd_bus_message_open_container(m
, 'v', "as");
142 return bus_log_create_error(r
);
144 r
= sd_bus_message_open_container(m
, 'a', "s");
146 return bus_log_create_error(r
);
149 _cleanup_free_
char *word
= NULL
;
151 r
= extract_first_word(&p
, &word
, NULL
, flags
);
157 return log_error_errno(r
, "Invalid syntax: %s", eq
);
159 r
= sd_bus_message_append_basic(m
, 's', word
);
161 return bus_log_create_error(r
);
164 r
= sd_bus_message_close_container(m
);
166 return bus_log_create_error(r
);
168 r
= sd_bus_message_close_container(m
);
170 return bus_log_create_error(r
);
172 r
= sd_bus_message_close_container(m
);
174 return bus_log_create_error(r
);
179 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
182 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
184 return bus_log_create_error(r
);
186 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
188 return bus_log_create_error(r
);
190 r
= sd_bus_message_open_container(m
, 'v', "ay");
192 return bus_log_create_error(r
);
194 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
196 return bus_log_create_error(r
);
198 r
= sd_bus_message_close_container(m
);
200 return bus_log_create_error(r
);
202 r
= sd_bus_message_close_container(m
);
204 return bus_log_create_error(r
);
209 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
215 r
= parse_sec(eq
, &t
);
217 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
220 n
= newa(char, l
+ 2);
221 /* Change suffix Sec → USec */
222 strcpy(mempcpy(n
, field
, l
- 3), "USec");
224 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
226 return bus_log_create_error(r
);
231 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
235 r
= parse_size(eq
, base
, &v
);
237 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
239 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
241 return bus_log_create_error(r
);
246 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
247 bool ignore_failure
= false, explicit_path
= false, done
= false;
248 _cleanup_strv_free_
char **l
= NULL
;
249 _cleanup_free_
char *path
= NULL
;
259 ignore_failure
= true;
268 explicit_path
= true;
275 /* The bus API doesn't support +, ! and !! currently, unfortunately. :-( */
276 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
277 "Sorry, but +, ! and !! are currently not supported for transient services.");
286 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
288 return log_error_errno(r
, "Failed to parse path: %m");
291 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
293 return log_error_errno(r
, "Failed to parse command line: %m");
295 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
297 return bus_log_create_error(r
);
299 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
301 return bus_log_create_error(r
);
303 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
305 return bus_log_create_error(r
);
307 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
309 return bus_log_create_error(r
);
311 if (!strv_isempty(l
)) {
313 r
= sd_bus_message_open_container(m
, 'r', "sasb");
315 return bus_log_create_error(r
);
317 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
319 return bus_log_create_error(r
);
321 r
= sd_bus_message_append_strv(m
, l
);
323 return bus_log_create_error(r
);
325 r
= sd_bus_message_append(m
, "b", ignore_failure
);
327 return bus_log_create_error(r
);
329 r
= sd_bus_message_close_container(m
);
331 return bus_log_create_error(r
);
334 r
= sd_bus_message_close_container(m
);
336 return bus_log_create_error(r
);
338 r
= sd_bus_message_close_container(m
);
340 return bus_log_create_error(r
);
342 r
= sd_bus_message_close_container(m
);
344 return bus_log_create_error(r
);
349 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
355 r
= sd_bus_message_open_container(m
, 'r', "iayu");
359 r
= sd_bus_message_append(m
, "i", family
);
363 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
367 r
= sd_bus_message_append(m
, "u", prefixlen
);
371 return sd_bus_message_close_container(m
);
374 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
377 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
379 return bus_append_string(m
, field
, eq
);
381 if (STR_IN_SET(field
,
382 "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
383 "TasksAccounting", "IPAccounting"))
385 return bus_append_parse_boolean(m
, field
, eq
);
387 if (STR_IN_SET(field
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
389 return bus_append_cg_weight_parse(m
, field
, eq
);
391 if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares"))
393 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
395 if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight"))
397 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
399 if (streq(field
, "Delegate")) {
401 r
= parse_boolean(eq
);
403 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_QUOTES
);
405 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
407 return bus_log_create_error(r
);
412 if (STR_IN_SET(field
, "MemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
414 if (isempty(eq
) || streq(eq
, "infinity")) {
415 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
417 return bus_log_create_error(r
);
421 r
= parse_permille(eq
);
425 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
426 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
427 * size can be determined server-side. */
429 n
= strjoina(field
, "Scale");
430 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
432 return bus_log_create_error(r
);
437 if (streq(field
, "TasksMax"))
438 return bus_append_safe_atou64(m
, field
, eq
);
440 return bus_append_parse_size(m
, field
, eq
, 1024);
443 if (streq(field
, "CPUQuota")) {
446 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
448 r
= parse_permille_unbounded(eq
);
450 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
451 "CPU quota too small.");
453 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
455 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
459 return bus_log_create_error(r
);
464 if (streq(field
, "CPUQuotaPeriodSec")) {
465 usec_t u
= USEC_INFINITY
;
467 r
= parse_sec_def_infinity(eq
, &u
);
469 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
471 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
473 return bus_log_create_error(r
);
478 if (streq(field
, "DeviceAllow")) {
481 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
483 const char *path
= eq
, *rwm
= NULL
, *e
;
487 path
= strndupa(eq
, e
- eq
);
491 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
495 return bus_log_create_error(r
);
500 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
503 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
505 const char *path
, *bandwidth
, *e
;
510 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
511 "Failed to parse %s value %s.",
514 path
= strndupa(eq
, e
- eq
);
517 if (streq(bandwidth
, "infinity"))
518 bytes
= CGROUP_LIMIT_MAX
;
520 r
= parse_size(bandwidth
, 1000, &bytes
);
522 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
525 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
529 return bus_log_create_error(r
);
534 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
537 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
539 const char *path
, *weight
, *e
;
544 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
545 "Failed to parse %s value %s.",
548 path
= strndupa(eq
, e
- eq
);
551 r
= safe_atou64(weight
, &u
);
553 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
555 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
559 return bus_log_create_error(r
);
564 if (streq(field
, "IODeviceLatencyTargetSec")) {
565 const char *field_usec
= "IODeviceLatencyTargetUSec";
568 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
570 const char *path
, *target
, *e
;
575 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
576 "Failed to parse %s value %s.",
579 path
= strndupa(eq
, e
- eq
);
582 r
= parse_sec(target
, &usec
);
584 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
586 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
590 return bus_log_create_error(r
);
595 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
596 unsigned char prefixlen
;
597 union in_addr_union prefix
= {};
601 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
603 return bus_log_create_error(r
);
608 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
610 return bus_log_create_error(r
);
612 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
614 return bus_log_create_error(r
);
616 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
618 return bus_log_create_error(r
);
620 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
622 return bus_log_create_error(r
);
624 if (streq(eq
, "any")) {
625 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
627 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
629 return bus_log_create_error(r
);
631 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
633 return bus_log_create_error(r
);
635 } else if (is_localhost(eq
)) {
636 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
638 prefix
.in
.s_addr
= htobe32(0x7f000000);
639 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
641 return bus_log_create_error(r
);
643 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
644 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
648 } else if (streq(eq
, "link-local")) {
649 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
651 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
652 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
654 return bus_log_create_error(r
);
656 prefix
.in6
= (struct in6_addr
) {
657 .s6_addr32
[0] = htobe32(0xfe800000)
659 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
661 return bus_log_create_error(r
);
663 } else if (streq(eq
, "multicast")) {
664 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
666 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
667 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
669 return bus_log_create_error(r
);
671 prefix
.in6
= (struct in6_addr
) {
672 .s6_addr32
[0] = htobe32(0xff000000)
674 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
676 return bus_log_create_error(r
);
680 _cleanup_free_
char *word
= NULL
;
682 r
= extract_first_word(&eq
, &word
, NULL
, 0);
688 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
690 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
692 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
694 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
696 return bus_log_create_error(r
);
700 r
= sd_bus_message_close_container(m
);
702 return bus_log_create_error(r
);
704 r
= sd_bus_message_close_container(m
);
706 return bus_log_create_error(r
);
708 r
= sd_bus_message_close_container(m
);
710 return bus_log_create_error(r
);
718 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
720 if (streq(field
, "Where"))
722 return bus_append_string(m
, field
, eq
);
724 if (streq(field
, "DirectoryMode"))
726 return bus_append_parse_mode(m
, field
, eq
);
728 if (streq(field
, "TimeoutIdleSec"))
730 return bus_append_parse_sec_rename(m
, field
, eq
);
735 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
739 if (STR_IN_SET(field
,
741 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
742 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
743 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
744 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
746 return bus_append_string(m
, field
, eq
);
748 if (STR_IN_SET(field
,
749 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
750 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
751 "PrivateMounts", "NoNewPrivileges", "SyslogLevelPrefix",
752 "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
753 "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups",
754 "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality", "ProtectHostname"))
756 return bus_append_parse_boolean(m
, field
, eq
);
758 if (STR_IN_SET(field
,
759 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
760 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
761 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
762 "SupplementaryGroups", "SystemCallArchitectures"))
764 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
766 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
768 return bus_append_log_level_from_string(m
, field
, eq
);
770 if (streq(field
, "SyslogFacility"))
772 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
774 if (streq(field
, "SecureBits"))
776 return bus_append_secure_bits_from_string(m
, field
, eq
);
778 if (streq(field
, "CPUSchedulingPolicy"))
780 return bus_append_sched_policy_from_string(m
, field
, eq
);
782 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
784 return bus_append_safe_atoi(m
, field
, eq
);
786 if (streq(field
, "Nice"))
788 return bus_append_parse_nice(m
, field
, eq
);
790 if (streq(field
, "SystemCallErrorNumber"))
792 return bus_append_parse_errno(m
, field
, eq
);
794 if (streq(field
, "IOSchedulingClass"))
796 return bus_append_ioprio_class_from_string(m
, field
, eq
);
798 if (streq(field
, "IOSchedulingPriority"))
800 return bus_append_ioprio_parse_priority(m
, field
, eq
);
802 if (STR_IN_SET(field
,
803 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
804 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
806 return bus_append_parse_mode(m
, field
, eq
);
808 if (streq(field
, "TimerSlackNSec"))
810 return bus_append_parse_nsec(m
, field
, eq
);
812 if (streq(field
, "LogRateLimitIntervalSec"))
814 return bus_append_parse_sec_rename(m
, field
, eq
);
816 if (streq(field
, "LogRateLimitBurst"))
818 return bus_append_safe_atou(m
, field
, eq
);
820 if (streq(field
, "MountFlags"))
822 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
824 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
826 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
828 if (streq(field
, "EnvironmentFile")) {
831 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
833 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
834 eq
[0] == '-' ? eq
+ 1 : eq
,
837 return bus_log_create_error(r
);
842 if (streq(field
, "LogExtraFields")) {
844 r
= sd_bus_message_open_container(m
, 'r', "sv");
846 return bus_log_create_error(r
);
848 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
850 return bus_log_create_error(r
);
852 r
= sd_bus_message_open_container(m
, 'v', "aay");
854 return bus_log_create_error(r
);
856 r
= sd_bus_message_open_container(m
, 'a', "ay");
858 return bus_log_create_error(r
);
860 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
862 return bus_log_create_error(r
);
864 r
= sd_bus_message_close_container(m
);
866 return bus_log_create_error(r
);
868 r
= sd_bus_message_close_container(m
);
870 return bus_log_create_error(r
);
872 r
= sd_bus_message_close_container(m
);
874 return bus_log_create_error(r
);
879 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
880 const char *n
, *appended
;
882 if ((n
= startswith(eq
, "fd:"))) {
883 appended
= strjoina(field
, "FileDescriptorName");
884 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
885 } else if ((n
= startswith(eq
, "file:"))) {
886 appended
= strjoina(field
, "File");
887 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
888 } else if ((n
= startswith(eq
, "append:"))) {
889 appended
= strjoina(field
, "FileToAppend");
890 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
892 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
894 return bus_log_create_error(r
);
899 if (streq(field
, "StandardInputText")) {
900 _cleanup_free_
char *unescaped
= NULL
;
902 r
= cunescape(eq
, 0, &unescaped
);
904 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
906 if (!strextend(&unescaped
, "\n", NULL
))
909 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
910 * interface anyway */
912 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
915 if (streq(field
, "StandardInputData")) {
916 _cleanup_free_
void *decoded
= NULL
;
919 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
921 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
923 return bus_append_byte_array(m
, field
, decoded
, sz
);
926 if ((suffix
= startswith(field
, "Limit"))) {
929 rl
= rlimit_from_string(suffix
);
934 r
= rlimit_parse(rl
, eq
, &l
);
936 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
938 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
940 return bus_log_create_error(r
);
942 sn
= strjoina(field
, "Soft");
943 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
945 return bus_log_create_error(r
);
951 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
960 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
962 return bus_log_create_error(r
);
967 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
977 r
= capability_set_from_string(p
, &sum
);
979 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
981 sum
= invert
? ~sum
: sum
;
983 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
985 return bus_log_create_error(r
);
990 if (streq(field
, "CPUAffinity")) {
991 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
993 r
= parse_cpu_set(eq
, &cpuset
);
995 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
997 return bus_append_byte_array(m
, field
, cpuset
, CPU_ALLOC_SIZE(r
));
1000 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
1009 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1011 return bus_log_create_error(r
);
1013 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1015 return bus_log_create_error(r
);
1017 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1019 return bus_log_create_error(r
);
1021 r
= sd_bus_message_open_container(m
, 'r', "bas");
1023 return bus_log_create_error(r
);
1025 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
1027 return bus_log_create_error(r
);
1029 r
= sd_bus_message_open_container(m
, 'a', "s");
1031 return bus_log_create_error(r
);
1034 _cleanup_free_
char *word
= NULL
;
1036 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1042 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1044 r
= sd_bus_message_append_basic(m
, 's', word
);
1046 return bus_log_create_error(r
);
1049 r
= sd_bus_message_close_container(m
);
1051 return bus_log_create_error(r
);
1053 r
= sd_bus_message_close_container(m
);
1055 return bus_log_create_error(r
);
1057 r
= sd_bus_message_close_container(m
);
1059 return bus_log_create_error(r
);
1061 r
= sd_bus_message_close_container(m
);
1063 return bus_log_create_error(r
);
1068 if (streq(field
, "RestrictNamespaces")) {
1069 bool invert
= false;
1070 unsigned long flags
;
1072 r
= parse_boolean(eq
);
1076 flags
= NAMESPACE_FLAGS_ALL
;
1083 r
= namespace_flags_from_string(eq
, &flags
);
1085 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1089 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1091 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1093 return bus_log_create_error(r
);
1098 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1101 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1103 return bus_log_create_error(r
);
1105 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1107 return bus_log_create_error(r
);
1109 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1111 return bus_log_create_error(r
);
1113 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1115 return bus_log_create_error(r
);
1118 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1119 char *s
= NULL
, *d
= NULL
;
1120 bool ignore_enoent
= false;
1121 uint64_t flags
= MS_REC
;
1123 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1125 return log_error_errno(r
, "Failed to parse argument: %m");
1131 ignore_enoent
= true;
1135 if (p
&& p
[-1] == ':') {
1136 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1138 return log_error_errno(r
, "Failed to parse argument: %m");
1140 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1141 "Missing argument after ':': %s",
1146 if (p
&& p
[-1] == ':') {
1147 _cleanup_free_
char *options
= NULL
;
1149 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
1151 return log_error_errno(r
, "Failed to parse argument: %m");
1153 if (isempty(options
) || streq(options
, "rbind"))
1155 else if (streq(options
, "norbind"))
1158 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1159 "Unknown options: %s",
1165 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1167 return bus_log_create_error(r
);
1170 r
= sd_bus_message_close_container(m
);
1172 return bus_log_create_error(r
);
1174 r
= sd_bus_message_close_container(m
);
1176 return bus_log_create_error(r
);
1178 r
= sd_bus_message_close_container(m
);
1180 return bus_log_create_error(r
);
1185 if (streq(field
, "TemporaryFileSystem")) {
1188 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1190 return bus_log_create_error(r
);
1192 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1194 return bus_log_create_error(r
);
1196 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1198 return bus_log_create_error(r
);
1200 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1202 return bus_log_create_error(r
);
1205 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1208 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1210 return log_error_errno(r
, "Failed to parse argument: %m");
1215 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1217 return log_error_errno(r
, "Failed to parse argument: %m");
1219 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1220 "Failed to parse argument: %s",
1223 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1225 return bus_log_create_error(r
);
1228 r
= sd_bus_message_close_container(m
);
1230 return bus_log_create_error(r
);
1232 r
= sd_bus_message_close_container(m
);
1234 return bus_log_create_error(r
);
1236 r
= sd_bus_message_close_container(m
);
1238 return bus_log_create_error(r
);
1246 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1248 if (streq(field
, "KillMode"))
1250 return bus_append_string(m
, field
, eq
);
1252 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1254 return bus_append_parse_boolean(m
, field
, eq
);
1256 if (STR_IN_SET(field
, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1258 return bus_append_signal_from_string(m
, field
, eq
);
1263 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1265 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1267 return bus_append_string(m
, field
, eq
);
1269 if (streq(field
, "TimeoutSec"))
1271 return bus_append_parse_sec_rename(m
, field
, eq
);
1273 if (streq(field
, "DirectoryMode"))
1275 return bus_append_parse_mode(m
, field
, eq
);
1277 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1279 return bus_append_parse_boolean(m
, field
, eq
);
1284 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1287 if (streq(field
, "MakeDirectory"))
1289 return bus_append_parse_boolean(m
, field
, eq
);
1291 if (streq(field
, "DirectoryMode"))
1293 return bus_append_parse_mode(m
, field
, eq
);
1295 if (STR_IN_SET(field
,
1296 "PathExists", "PathExistsGlob", "PathChanged",
1297 "PathModified", "DirectoryNotEmpty")) {
1300 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1302 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1304 return bus_log_create_error(r
);
1312 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1315 if (STR_IN_SET(field
,
1316 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1317 "USBFunctionDescriptors", "USBFunctionStrings"))
1319 return bus_append_string(m
, field
, eq
);
1321 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1323 return bus_append_parse_boolean(m
, field
, eq
);
1325 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1327 return bus_append_parse_sec_rename(m
, field
, eq
);
1329 if (streq(field
, "TimeoutSec")) {
1331 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1335 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1338 if (streq(field
, "FileDescriptorStoreMax"))
1340 return bus_append_safe_atou(m
, field
, eq
);
1342 if (STR_IN_SET(field
,
1343 "ExecStartPre", "ExecStart", "ExecStartPost",
1344 "ExecReload", "ExecStop", "ExecStopPost"))
1346 return bus_append_exec_command(m
, field
, eq
);
1348 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1349 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1350 size_t sz_status
= 0, sz_signal
= 0;
1354 _cleanup_free_
char *word
= NULL
;
1357 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1363 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1365 r
= safe_atoi(word
, &val
);
1367 val
= signal_from_string(word
);
1369 return log_error_errno(r
, "Invalid status or signal %s in %s: %m", word
, field
);
1371 signal
= reallocarray(signal
, sz_signal
+ 1, sizeof(int));
1375 signal
[sz_signal
++] = val
;
1377 status
= reallocarray(status
, sz_status
+ 1, sizeof(int));
1381 status
[sz_status
++] = val
;
1385 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1387 return bus_log_create_error(r
);
1389 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1391 return bus_log_create_error(r
);
1393 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1395 return bus_log_create_error(r
);
1397 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1399 return bus_log_create_error(r
);
1401 r
= sd_bus_message_append_array(m
, 'i', status
, sz_status
);
1403 return bus_log_create_error(r
);
1405 r
= sd_bus_message_append_array(m
, 'i', signal
, sz_signal
);
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
);
1417 r
= sd_bus_message_close_container(m
);
1419 return bus_log_create_error(r
);
1427 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1430 if (STR_IN_SET(field
,
1431 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1432 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1434 return bus_append_parse_boolean(m
, field
, eq
);
1436 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1438 return bus_append_safe_atoi(m
, field
, eq
);
1440 if (streq(field
, "IPTOS"))
1442 return bus_append_ip_tos_from_string(m
, field
, eq
);
1444 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1446 return bus_append_safe_atou(m
, field
, eq
);
1448 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1450 return bus_append_parse_mode(m
, field
, eq
);
1452 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1454 return bus_append_safe_atoi64(m
, field
, eq
);
1456 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1458 return bus_append_parse_sec_rename(m
, field
, eq
);
1460 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1462 return bus_append_parse_size(m
, field
, eq
, 1024);
1464 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1466 return bus_append_exec_command(m
, field
, eq
);
1468 if (STR_IN_SET(field
,
1469 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1470 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1471 "SocketUser", "SocketGroup"))
1473 return bus_append_string(m
, field
, eq
);
1475 if (streq(field
, "Symlinks"))
1477 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1479 if (streq(field
, "SocketProtocol"))
1481 return bus_append_parse_ip_protocol(m
, field
, eq
);
1483 if (STR_IN_SET(field
,
1484 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1485 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1488 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1490 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1492 return bus_log_create_error(r
);
1499 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1502 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent"))
1504 return bus_append_parse_boolean(m
, field
, eq
);
1506 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1508 return bus_append_parse_sec_rename(m
, field
, eq
);
1510 if (STR_IN_SET(field
,
1511 "OnActiveSec", "OnBootSec", "OnStartupSec",
1512 "OnUnitActiveSec","OnUnitInactiveSec")) {
1515 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1518 r
= parse_sec(eq
, &t
);
1520 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1522 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1525 return bus_log_create_error(r
);
1530 if (streq(field
, "OnCalendar")) {
1533 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1535 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1537 return bus_log_create_error(r
);
1545 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1546 ConditionType t
= _CONDITION_TYPE_INVALID
;
1547 bool is_condition
= false;
1550 if (STR_IN_SET(field
,
1551 "Description", "SourcePath", "OnFailureJobMode",
1552 "JobTimeoutAction", "JobTimeoutRebootArgument",
1553 "StartLimitAction", "FailureAction", "SuccessAction",
1554 "RebootArgument", "CollectMode"))
1556 return bus_append_string(m
, field
, eq
);
1558 if (STR_IN_SET(field
,
1559 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1560 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1562 return bus_append_parse_boolean(m
, field
, eq
);
1564 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1566 return bus_append_parse_sec_rename(m
, field
, eq
);
1568 if (streq(field
, "StartLimitBurst"))
1570 return bus_append_safe_atou(m
, field
, eq
);
1572 if (STR_IN_SET(field
, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1575 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1579 r
= safe_atou8(eq
, &u
);
1581 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1583 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1586 return bus_log_create_error(r
);
1591 if (unit_dependency_from_string(field
) >= 0 ||
1592 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1594 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1596 t
= condition_type_from_string(field
);
1598 is_condition
= true;
1600 t
= assert_type_from_string(field
);
1603 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1606 int trigger
, negate
;
1608 trigger
= *p
== '|';
1616 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1617 field
, trigger
, negate
, p
);
1620 return bus_log_create_error(r
);
1628 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1629 const char *eq
, *field
;
1635 eq
= strchr(assignment
, '=');
1637 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1638 "Not an assignment: %s", assignment
);
1640 field
= strndupa(assignment
, eq
- assignment
);
1645 r
= bus_append_cgroup_property(m
, field
, eq
);
1649 r
= bus_append_execute_property(m
, field
, eq
);
1653 r
= bus_append_kill_property(m
, field
, eq
);
1657 r
= bus_append_service_property(m
, field
, eq
);
1663 r
= bus_append_cgroup_property(m
, field
, eq
);
1667 r
= bus_append_execute_property(m
, field
, eq
);
1671 r
= bus_append_kill_property(m
, field
, eq
);
1675 r
= bus_append_socket_property(m
, field
, eq
);
1681 r
= bus_append_timer_property(m
, field
, eq
);
1687 r
= bus_append_path_property(m
, field
, eq
);
1693 r
= bus_append_cgroup_property(m
, field
, eq
);
1700 if (streq(field
, "TimeoutStopSec"))
1701 return bus_append_parse_sec_rename(m
, field
, eq
);
1703 r
= bus_append_cgroup_property(m
, field
, eq
);
1707 r
= bus_append_kill_property(m
, field
, eq
);
1713 r
= bus_append_cgroup_property(m
, field
, eq
);
1717 r
= bus_append_execute_property(m
, field
, eq
);
1721 r
= bus_append_kill_property(m
, field
, eq
);
1725 r
= bus_append_mount_property(m
, field
, eq
);
1731 case UNIT_AUTOMOUNT
:
1732 r
= bus_append_automount_property(m
, field
, eq
);
1741 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1742 "Not supported unit type");
1745 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1746 "Invalid unit type");
1749 r
= bus_append_unit_property(m
, field
, eq
);
1753 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1754 "Unknown assignment: %s", assignment
);
1757 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1763 STRV_FOREACH(i
, l
) {
1764 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1772 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
1773 const char *type
, *path
, *source
;
1776 /* changes is dereferenced when calling unit_file_dump_changes() later,
1777 * so we have to make sure this is not NULL. */
1781 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1783 return bus_log_parse_error(r
);
1785 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1786 /* We expect only "success" changes to be sent over the bus.
1787 Hence, reject anything negative. */
1788 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1791 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1795 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1800 return bus_log_parse_error(r
);
1802 r
= sd_bus_message_exit_container(m
);
1804 return bus_log_parse_error(r
);
1806 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
1810 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
1811 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1812 _cleanup_free_
char *path
= NULL
;
1815 path
= unit_dbus_path_from_name(name
);
1819 /* This function warns on it's own, because otherwise it'd be awkward to pass
1820 * the dbus error message around. */
1822 r
= sd_bus_get_property_string(
1824 "org.freedesktop.systemd1",
1826 "org.freedesktop.systemd1.Unit",
1831 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));