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
, "DisableControllers"))
401 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_QUOTES
);
403 if (streq(field
, "Delegate")) {
405 r
= parse_boolean(eq
);
407 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_QUOTES
);
409 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
411 return bus_log_create_error(r
);
416 if (STR_IN_SET(field
, "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
418 if (isempty(eq
) || streq(eq
, "infinity")) {
419 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
421 return bus_log_create_error(r
);
425 r
= parse_permille(eq
);
429 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
430 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
431 * size can be determined server-side. */
433 n
= strjoina(field
, "Scale");
434 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
436 return bus_log_create_error(r
);
441 if (streq(field
, "TasksMax"))
442 return bus_append_safe_atou64(m
, field
, eq
);
444 return bus_append_parse_size(m
, field
, eq
, 1024);
447 if (streq(field
, "CPUQuota")) {
450 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
452 r
= parse_permille_unbounded(eq
);
454 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
455 "CPU quota too small.");
457 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
459 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
463 return bus_log_create_error(r
);
468 if (streq(field
, "CPUQuotaPeriodSec")) {
469 usec_t u
= USEC_INFINITY
;
471 r
= parse_sec_def_infinity(eq
, &u
);
473 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
475 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
477 return bus_log_create_error(r
);
482 if (streq(field
, "DeviceAllow")) {
485 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
487 const char *path
= eq
, *rwm
= NULL
, *e
;
491 path
= strndupa(eq
, e
- eq
);
495 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
499 return bus_log_create_error(r
);
504 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
507 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
509 const char *path
, *bandwidth
, *e
;
514 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
515 "Failed to parse %s value %s.",
518 path
= strndupa(eq
, e
- eq
);
521 if (streq(bandwidth
, "infinity"))
522 bytes
= CGROUP_LIMIT_MAX
;
524 r
= parse_size(bandwidth
, 1000, &bytes
);
526 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
529 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
533 return bus_log_create_error(r
);
538 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
541 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
543 const char *path
, *weight
, *e
;
548 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
549 "Failed to parse %s value %s.",
552 path
= strndupa(eq
, e
- eq
);
555 r
= safe_atou64(weight
, &u
);
557 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
559 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
563 return bus_log_create_error(r
);
568 if (streq(field
, "IODeviceLatencyTargetSec")) {
569 const char *field_usec
= "IODeviceLatencyTargetUSec";
572 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
574 const char *path
, *target
, *e
;
579 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
580 "Failed to parse %s value %s.",
583 path
= strndupa(eq
, e
- eq
);
586 r
= parse_sec(target
, &usec
);
588 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
590 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
594 return bus_log_create_error(r
);
599 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
600 unsigned char prefixlen
;
601 union in_addr_union prefix
= {};
605 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
607 return bus_log_create_error(r
);
612 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
614 return bus_log_create_error(r
);
616 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
618 return bus_log_create_error(r
);
620 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
622 return bus_log_create_error(r
);
624 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
626 return bus_log_create_error(r
);
628 if (streq(eq
, "any")) {
629 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
631 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
633 return bus_log_create_error(r
);
635 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
637 return bus_log_create_error(r
);
639 } else if (is_localhost(eq
)) {
640 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
642 prefix
.in
.s_addr
= htobe32(0x7f000000);
643 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
645 return bus_log_create_error(r
);
647 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
648 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
652 } else if (streq(eq
, "link-local")) {
653 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
655 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
656 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
658 return bus_log_create_error(r
);
660 prefix
.in6
= (struct in6_addr
) {
661 .s6_addr32
[0] = htobe32(0xfe800000)
663 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
665 return bus_log_create_error(r
);
667 } else if (streq(eq
, "multicast")) {
668 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
670 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
671 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
673 return bus_log_create_error(r
);
675 prefix
.in6
= (struct in6_addr
) {
676 .s6_addr32
[0] = htobe32(0xff000000)
678 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
680 return bus_log_create_error(r
);
684 _cleanup_free_
char *word
= NULL
;
686 r
= extract_first_word(&eq
, &word
, NULL
, 0);
692 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
694 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
696 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
698 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
700 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
);
712 r
= sd_bus_message_close_container(m
);
714 return bus_log_create_error(r
);
722 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
724 if (streq(field
, "Where"))
726 return bus_append_string(m
, field
, eq
);
728 if (streq(field
, "DirectoryMode"))
730 return bus_append_parse_mode(m
, field
, eq
);
732 if (streq(field
, "TimeoutIdleSec"))
734 return bus_append_parse_sec_rename(m
, field
, eq
);
739 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
743 if (STR_IN_SET(field
,
745 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
746 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
747 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
748 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
750 return bus_append_string(m
, field
, eq
);
752 if (STR_IN_SET(field
,
753 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
754 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
755 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
756 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
757 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
758 "ProtectHostname", "RestrictSUIDSGID"))
760 return bus_append_parse_boolean(m
, field
, eq
);
762 if (STR_IN_SET(field
,
763 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
764 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
765 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
766 "SupplementaryGroups", "SystemCallArchitectures"))
768 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
770 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
772 return bus_append_log_level_from_string(m
, field
, eq
);
774 if (streq(field
, "SyslogFacility"))
776 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
778 if (streq(field
, "SecureBits"))
780 return bus_append_secure_bits_from_string(m
, field
, eq
);
782 if (streq(field
, "CPUSchedulingPolicy"))
784 return bus_append_sched_policy_from_string(m
, field
, eq
);
786 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
788 return bus_append_safe_atoi(m
, field
, eq
);
790 if (streq(field
, "Nice"))
792 return bus_append_parse_nice(m
, field
, eq
);
794 if (streq(field
, "SystemCallErrorNumber"))
796 return bus_append_parse_errno(m
, field
, eq
);
798 if (streq(field
, "IOSchedulingClass"))
800 return bus_append_ioprio_class_from_string(m
, field
, eq
);
802 if (streq(field
, "IOSchedulingPriority"))
804 return bus_append_ioprio_parse_priority(m
, field
, eq
);
806 if (STR_IN_SET(field
,
807 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
808 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
810 return bus_append_parse_mode(m
, field
, eq
);
812 if (streq(field
, "TimerSlackNSec"))
814 return bus_append_parse_nsec(m
, field
, eq
);
816 if (streq(field
, "LogRateLimitIntervalSec"))
818 return bus_append_parse_sec_rename(m
, field
, eq
);
820 if (streq(field
, "LogRateLimitBurst"))
822 return bus_append_safe_atou(m
, field
, eq
);
824 if (streq(field
, "MountFlags"))
826 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
828 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
830 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
832 if (streq(field
, "EnvironmentFile")) {
835 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
837 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
838 eq
[0] == '-' ? eq
+ 1 : eq
,
841 return bus_log_create_error(r
);
846 if (streq(field
, "LogExtraFields")) {
848 r
= sd_bus_message_open_container(m
, 'r', "sv");
850 return bus_log_create_error(r
);
852 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
854 return bus_log_create_error(r
);
856 r
= sd_bus_message_open_container(m
, 'v', "aay");
858 return bus_log_create_error(r
);
860 r
= sd_bus_message_open_container(m
, 'a', "ay");
862 return bus_log_create_error(r
);
864 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
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
);
876 r
= sd_bus_message_close_container(m
);
878 return bus_log_create_error(r
);
883 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
884 const char *n
, *appended
;
886 if ((n
= startswith(eq
, "fd:"))) {
887 appended
= strjoina(field
, "FileDescriptorName");
888 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
889 } else if ((n
= startswith(eq
, "file:"))) {
890 appended
= strjoina(field
, "File");
891 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
892 } else if ((n
= startswith(eq
, "append:"))) {
893 appended
= strjoina(field
, "FileToAppend");
894 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
896 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
898 return bus_log_create_error(r
);
903 if (streq(field
, "StandardInputText")) {
904 _cleanup_free_
char *unescaped
= NULL
;
906 r
= cunescape(eq
, 0, &unescaped
);
908 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
910 if (!strextend(&unescaped
, "\n", NULL
))
913 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
914 * interface anyway */
916 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
919 if (streq(field
, "StandardInputData")) {
920 _cleanup_free_
void *decoded
= NULL
;
923 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
925 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
927 return bus_append_byte_array(m
, field
, decoded
, sz
);
930 if ((suffix
= startswith(field
, "Limit"))) {
933 rl
= rlimit_from_string(suffix
);
938 r
= rlimit_parse(rl
, eq
, &l
);
940 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
942 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
944 return bus_log_create_error(r
);
946 sn
= strjoina(field
, "Soft");
947 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
949 return bus_log_create_error(r
);
955 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
964 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
966 return bus_log_create_error(r
);
971 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
981 r
= capability_set_from_string(p
, &sum
);
983 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
985 sum
= invert
? ~sum
: sum
;
987 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
989 return bus_log_create_error(r
);
994 if (streq(field
, "CPUAffinity")) {
995 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
997 r
= parse_cpu_set(eq
, &cpuset
);
999 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1001 return bus_append_byte_array(m
, field
, cpuset
, CPU_ALLOC_SIZE(r
));
1004 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
1013 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1015 return bus_log_create_error(r
);
1017 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1019 return bus_log_create_error(r
);
1021 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1023 return bus_log_create_error(r
);
1025 r
= sd_bus_message_open_container(m
, 'r', "bas");
1027 return bus_log_create_error(r
);
1029 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
1031 return bus_log_create_error(r
);
1033 r
= sd_bus_message_open_container(m
, 'a', "s");
1035 return bus_log_create_error(r
);
1038 _cleanup_free_
char *word
= NULL
;
1040 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1046 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1048 r
= sd_bus_message_append_basic(m
, 's', word
);
1050 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
);
1065 r
= sd_bus_message_close_container(m
);
1067 return bus_log_create_error(r
);
1072 if (streq(field
, "RestrictNamespaces")) {
1073 bool invert
= false;
1074 unsigned long flags
;
1076 r
= parse_boolean(eq
);
1080 flags
= NAMESPACE_FLAGS_ALL
;
1087 r
= namespace_flags_from_string(eq
, &flags
);
1089 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1093 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1095 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1097 return bus_log_create_error(r
);
1102 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1105 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1107 return bus_log_create_error(r
);
1109 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1111 return bus_log_create_error(r
);
1113 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1115 return bus_log_create_error(r
);
1117 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1119 return bus_log_create_error(r
);
1122 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1123 char *s
= NULL
, *d
= NULL
;
1124 bool ignore_enoent
= false;
1125 uint64_t flags
= MS_REC
;
1127 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1129 return log_error_errno(r
, "Failed to parse argument: %m");
1135 ignore_enoent
= true;
1139 if (p
&& p
[-1] == ':') {
1140 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1142 return log_error_errno(r
, "Failed to parse argument: %m");
1144 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1145 "Missing argument after ':': %s",
1150 if (p
&& p
[-1] == ':') {
1151 _cleanup_free_
char *options
= NULL
;
1153 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
1155 return log_error_errno(r
, "Failed to parse argument: %m");
1157 if (isempty(options
) || streq(options
, "rbind"))
1159 else if (streq(options
, "norbind"))
1162 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1163 "Unknown options: %s",
1169 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1171 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
);
1182 r
= sd_bus_message_close_container(m
);
1184 return bus_log_create_error(r
);
1189 if (streq(field
, "TemporaryFileSystem")) {
1192 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1194 return bus_log_create_error(r
);
1196 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1198 return bus_log_create_error(r
);
1200 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1202 return bus_log_create_error(r
);
1204 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1206 return bus_log_create_error(r
);
1209 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1212 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1214 return log_error_errno(r
, "Failed to parse argument: %m");
1219 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1221 return log_error_errno(r
, "Failed to parse argument: %m");
1223 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1224 "Failed to parse argument: %s",
1227 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1229 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
);
1240 r
= sd_bus_message_close_container(m
);
1242 return bus_log_create_error(r
);
1250 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1252 if (streq(field
, "KillMode"))
1254 return bus_append_string(m
, field
, eq
);
1256 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1258 return bus_append_parse_boolean(m
, field
, eq
);
1260 if (STR_IN_SET(field
, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1262 return bus_append_signal_from_string(m
, field
, eq
);
1267 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1269 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1271 return bus_append_string(m
, field
, eq
);
1273 if (streq(field
, "TimeoutSec"))
1275 return bus_append_parse_sec_rename(m
, field
, eq
);
1277 if (streq(field
, "DirectoryMode"))
1279 return bus_append_parse_mode(m
, field
, eq
);
1281 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1283 return bus_append_parse_boolean(m
, field
, eq
);
1288 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1291 if (streq(field
, "MakeDirectory"))
1293 return bus_append_parse_boolean(m
, field
, eq
);
1295 if (streq(field
, "DirectoryMode"))
1297 return bus_append_parse_mode(m
, field
, eq
);
1299 if (STR_IN_SET(field
,
1300 "PathExists", "PathExistsGlob", "PathChanged",
1301 "PathModified", "DirectoryNotEmpty")) {
1304 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1306 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1308 return bus_log_create_error(r
);
1316 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1319 if (STR_IN_SET(field
,
1320 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1321 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
1323 return bus_append_string(m
, field
, eq
);
1325 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1327 return bus_append_parse_boolean(m
, field
, eq
);
1329 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1331 return bus_append_parse_sec_rename(m
, field
, eq
);
1333 if (streq(field
, "TimeoutSec")) {
1335 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1339 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1342 if (streq(field
, "FileDescriptorStoreMax"))
1344 return bus_append_safe_atou(m
, field
, eq
);
1346 if (STR_IN_SET(field
,
1347 "ExecStartPre", "ExecStart", "ExecStartPost",
1348 "ExecReload", "ExecStop", "ExecStopPost"))
1350 return bus_append_exec_command(m
, field
, eq
);
1352 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1353 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1354 size_t sz_status
= 0, sz_signal
= 0;
1358 _cleanup_free_
char *word
= NULL
;
1361 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1367 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1369 r
= safe_atoi(word
, &val
);
1371 val
= signal_from_string(word
);
1373 return log_error_errno(r
, "Invalid status or signal %s in %s: %m", word
, field
);
1375 signal
= reallocarray(signal
, sz_signal
+ 1, sizeof(int));
1379 signal
[sz_signal
++] = val
;
1381 status
= reallocarray(status
, sz_status
+ 1, sizeof(int));
1385 status
[sz_status
++] = val
;
1389 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1391 return bus_log_create_error(r
);
1393 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1395 return bus_log_create_error(r
);
1397 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1399 return bus_log_create_error(r
);
1401 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1403 return bus_log_create_error(r
);
1405 r
= sd_bus_message_append_array(m
, 'i', status
, sz_status
);
1407 return bus_log_create_error(r
);
1409 r
= sd_bus_message_append_array(m
, 'i', signal
, sz_signal
);
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
);
1421 r
= sd_bus_message_close_container(m
);
1423 return bus_log_create_error(r
);
1431 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1434 if (STR_IN_SET(field
,
1435 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1436 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1438 return bus_append_parse_boolean(m
, field
, eq
);
1440 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1442 return bus_append_safe_atoi(m
, field
, eq
);
1444 if (streq(field
, "IPTOS"))
1446 return bus_append_ip_tos_from_string(m
, field
, eq
);
1448 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1450 return bus_append_safe_atou(m
, field
, eq
);
1452 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1454 return bus_append_parse_mode(m
, field
, eq
);
1456 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1458 return bus_append_safe_atoi64(m
, field
, eq
);
1460 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1462 return bus_append_parse_sec_rename(m
, field
, eq
);
1464 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1466 return bus_append_parse_size(m
, field
, eq
, 1024);
1468 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1470 return bus_append_exec_command(m
, field
, eq
);
1472 if (STR_IN_SET(field
,
1473 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1474 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1475 "SocketUser", "SocketGroup"))
1477 return bus_append_string(m
, field
, eq
);
1479 if (streq(field
, "Symlinks"))
1481 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1483 if (streq(field
, "SocketProtocol"))
1485 return bus_append_parse_ip_protocol(m
, field
, eq
);
1487 if (STR_IN_SET(field
,
1488 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1489 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1492 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1494 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1496 return bus_log_create_error(r
);
1503 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1506 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent",
1507 "OnTimezoneChange", "OnClockChange"))
1509 return bus_append_parse_boolean(m
, field
, eq
);
1511 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1513 return bus_append_parse_sec_rename(m
, field
, eq
);
1515 if (STR_IN_SET(field
,
1516 "OnActiveSec", "OnBootSec", "OnStartupSec",
1517 "OnUnitActiveSec","OnUnitInactiveSec")) {
1520 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1523 r
= parse_sec(eq
, &t
);
1525 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1527 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1530 return bus_log_create_error(r
);
1535 if (streq(field
, "OnCalendar")) {
1538 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1540 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1542 return bus_log_create_error(r
);
1550 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1551 ConditionType t
= _CONDITION_TYPE_INVALID
;
1552 bool is_condition
= false;
1555 if (STR_IN_SET(field
,
1556 "Description", "SourcePath", "OnFailureJobMode",
1557 "JobTimeoutAction", "JobTimeoutRebootArgument",
1558 "StartLimitAction", "FailureAction", "SuccessAction",
1559 "RebootArgument", "CollectMode"))
1561 return bus_append_string(m
, field
, eq
);
1563 if (STR_IN_SET(field
,
1564 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1565 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1567 return bus_append_parse_boolean(m
, field
, eq
);
1569 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1571 return bus_append_parse_sec_rename(m
, field
, eq
);
1573 if (streq(field
, "StartLimitBurst"))
1575 return bus_append_safe_atou(m
, field
, eq
);
1577 if (STR_IN_SET(field
, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1580 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1584 r
= safe_atou8(eq
, &u
);
1586 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1588 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1591 return bus_log_create_error(r
);
1596 if (unit_dependency_from_string(field
) >= 0 ||
1597 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1599 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1601 t
= condition_type_from_string(field
);
1603 is_condition
= true;
1605 t
= assert_type_from_string(field
);
1608 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1611 int trigger
, negate
;
1613 trigger
= *p
== '|';
1621 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1622 field
, trigger
, negate
, p
);
1625 return bus_log_create_error(r
);
1633 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1634 const char *eq
, *field
;
1640 eq
= strchr(assignment
, '=');
1642 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1643 "Not an assignment: %s", assignment
);
1645 field
= strndupa(assignment
, eq
- assignment
);
1650 r
= bus_append_cgroup_property(m
, field
, eq
);
1654 r
= bus_append_execute_property(m
, field
, eq
);
1658 r
= bus_append_kill_property(m
, field
, eq
);
1662 r
= bus_append_service_property(m
, field
, eq
);
1668 r
= bus_append_cgroup_property(m
, field
, eq
);
1672 r
= bus_append_execute_property(m
, field
, eq
);
1676 r
= bus_append_kill_property(m
, field
, eq
);
1680 r
= bus_append_socket_property(m
, field
, eq
);
1686 r
= bus_append_timer_property(m
, field
, eq
);
1692 r
= bus_append_path_property(m
, field
, eq
);
1698 r
= bus_append_cgroup_property(m
, field
, eq
);
1705 if (streq(field
, "TimeoutStopSec"))
1706 return bus_append_parse_sec_rename(m
, field
, eq
);
1708 r
= bus_append_cgroup_property(m
, field
, eq
);
1712 r
= bus_append_kill_property(m
, field
, eq
);
1718 r
= bus_append_cgroup_property(m
, field
, eq
);
1722 r
= bus_append_execute_property(m
, field
, eq
);
1726 r
= bus_append_kill_property(m
, field
, eq
);
1730 r
= bus_append_mount_property(m
, field
, eq
);
1736 case UNIT_AUTOMOUNT
:
1737 r
= bus_append_automount_property(m
, field
, eq
);
1746 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1747 "Not supported unit type");
1750 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1751 "Invalid unit type");
1754 r
= bus_append_unit_property(m
, field
, eq
);
1758 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1759 "Unknown assignment: %s", assignment
);
1762 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1768 STRV_FOREACH(i
, l
) {
1769 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1777 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
1778 const char *type
, *path
, *source
;
1781 /* changes is dereferenced when calling unit_file_dump_changes() later,
1782 * so we have to make sure this is not NULL. */
1786 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1788 return bus_log_parse_error(r
);
1790 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1791 /* We expect only "success" changes to be sent over the bus.
1792 Hence, reject anything negative. */
1793 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1796 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1800 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1805 return bus_log_parse_error(r
);
1807 r
= sd_bus_message_exit_container(m
);
1809 return bus_log_parse_error(r
);
1811 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
1815 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
1816 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1817 _cleanup_free_
char *path
= NULL
;
1820 path
= unit_dbus_path_from_name(name
);
1824 /* This function warns on it's own, because otherwise it'd be awkward to pass
1825 * the dbus error message around. */
1827 r
= sd_bus_get_property_string(
1829 "org.freedesktop.systemd1",
1831 "org.freedesktop.systemd1.Unit",
1836 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));