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", "DefaultMemoryLow", "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", "PrivateTmp",
750 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
751 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
752 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
753 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
754 "ProtectHostname", "RestrictSUIDSGID"))
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", "OOMPolicy"))
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",
1503 "OnTimezoneChange", "OnClockChange"))
1505 return bus_append_parse_boolean(m
, field
, eq
);
1507 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1509 return bus_append_parse_sec_rename(m
, field
, eq
);
1511 if (STR_IN_SET(field
,
1512 "OnActiveSec", "OnBootSec", "OnStartupSec",
1513 "OnUnitActiveSec","OnUnitInactiveSec")) {
1516 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1519 r
= parse_sec(eq
, &t
);
1521 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1523 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1526 return bus_log_create_error(r
);
1531 if (streq(field
, "OnCalendar")) {
1534 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1536 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1538 return bus_log_create_error(r
);
1546 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1547 ConditionType t
= _CONDITION_TYPE_INVALID
;
1548 bool is_condition
= false;
1551 if (STR_IN_SET(field
,
1552 "Description", "SourcePath", "OnFailureJobMode",
1553 "JobTimeoutAction", "JobTimeoutRebootArgument",
1554 "StartLimitAction", "FailureAction", "SuccessAction",
1555 "RebootArgument", "CollectMode"))
1557 return bus_append_string(m
, field
, eq
);
1559 if (STR_IN_SET(field
,
1560 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1561 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1563 return bus_append_parse_boolean(m
, field
, eq
);
1565 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1567 return bus_append_parse_sec_rename(m
, field
, eq
);
1569 if (streq(field
, "StartLimitBurst"))
1571 return bus_append_safe_atou(m
, field
, eq
);
1573 if (STR_IN_SET(field
, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1576 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1580 r
= safe_atou8(eq
, &u
);
1582 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1584 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1587 return bus_log_create_error(r
);
1592 if (unit_dependency_from_string(field
) >= 0 ||
1593 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1595 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1597 t
= condition_type_from_string(field
);
1599 is_condition
= true;
1601 t
= assert_type_from_string(field
);
1604 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1607 int trigger
, negate
;
1609 trigger
= *p
== '|';
1617 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1618 field
, trigger
, negate
, p
);
1621 return bus_log_create_error(r
);
1629 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1630 const char *eq
, *field
;
1636 eq
= strchr(assignment
, '=');
1638 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1639 "Not an assignment: %s", assignment
);
1641 field
= strndupa(assignment
, eq
- assignment
);
1646 r
= bus_append_cgroup_property(m
, field
, eq
);
1650 r
= bus_append_execute_property(m
, field
, eq
);
1654 r
= bus_append_kill_property(m
, field
, eq
);
1658 r
= bus_append_service_property(m
, field
, eq
);
1664 r
= bus_append_cgroup_property(m
, field
, eq
);
1668 r
= bus_append_execute_property(m
, field
, eq
);
1672 r
= bus_append_kill_property(m
, field
, eq
);
1676 r
= bus_append_socket_property(m
, field
, eq
);
1682 r
= bus_append_timer_property(m
, field
, eq
);
1688 r
= bus_append_path_property(m
, field
, eq
);
1694 r
= bus_append_cgroup_property(m
, field
, eq
);
1701 if (streq(field
, "TimeoutStopSec"))
1702 return bus_append_parse_sec_rename(m
, field
, eq
);
1704 r
= bus_append_cgroup_property(m
, field
, eq
);
1708 r
= bus_append_kill_property(m
, field
, eq
);
1714 r
= bus_append_cgroup_property(m
, field
, eq
);
1718 r
= bus_append_execute_property(m
, field
, eq
);
1722 r
= bus_append_kill_property(m
, field
, eq
);
1726 r
= bus_append_mount_property(m
, field
, eq
);
1732 case UNIT_AUTOMOUNT
:
1733 r
= bus_append_automount_property(m
, field
, eq
);
1742 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1743 "Not supported unit type");
1746 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1747 "Invalid unit type");
1750 r
= bus_append_unit_property(m
, field
, eq
);
1754 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1755 "Unknown assignment: %s", assignment
);
1758 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1764 STRV_FOREACH(i
, l
) {
1765 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1773 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
1774 const char *type
, *path
, *source
;
1777 /* changes is dereferenced when calling unit_file_dump_changes() later,
1778 * so we have to make sure this is not NULL. */
1782 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1784 return bus_log_parse_error(r
);
1786 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1787 /* We expect only "success" changes to be sent over the bus.
1788 Hence, reject anything negative. */
1789 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1792 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1796 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1801 return bus_log_parse_error(r
);
1803 r
= sd_bus_message_exit_container(m
);
1805 return bus_log_parse_error(r
);
1807 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
1811 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
1812 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1813 _cleanup_free_
char *path
= NULL
;
1816 path
= unit_dbus_path_from_name(name
);
1820 /* This function warns on it's own, because otherwise it'd be awkward to pass
1821 * the dbus error message around. */
1823 r
= sd_bus_get_property_string(
1825 "org.freedesktop.systemd1",
1827 "org.freedesktop.systemd1.Unit",
1832 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));