1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
5 #include "bus-unit-util.h"
8 #include "cgroup-util.h"
10 #include "cpu-set-util.h"
12 #include "exec-util.h"
13 #include "hexdecoct.h"
14 #include "hostname-util.h"
15 #include "in-addr-util.h"
16 #include "ip-protocol-list.h"
17 #include "locale-util.h"
19 #include "missing_fs.h"
20 #include "mountpoint-util.h"
22 #include "parse-util.h"
23 #include "process-util.h"
24 #include "rlimit-util.h"
25 #include "securebits-util.h"
26 #include "signal-util.h"
27 #include "socket-util.h"
28 #include "sort-util.h"
29 #include "string-util.h"
30 #include "syslog-util.h"
31 #include "terminal-util.h"
33 #include "user-util.h"
36 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
42 return sd_bus_message_read(
57 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
58 static int bus_append_##parse_func( \
65 r = parse_func(eq, &val); \
67 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
69 r = sd_bus_message_append(m, "(sv)", field, \
70 bus_type, (cast_type) val); \
72 return bus_log_create_error(r); \
77 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
78 static int bus_append_##parse_func( \
86 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
88 r = sd_bus_message_append(m, "(sv)", field, \
89 bus_type, (int32_t) r); \
91 return bus_log_create_error(r); \
96 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
97 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
98 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
99 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
100 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
101 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
102 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
103 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
104 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
105 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
106 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
107 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
108 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
109 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
110 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
111 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
112 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
113 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
114 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
115 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
116 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
117 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
119 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
122 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
124 return bus_log_create_error(r
);
129 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
133 r
= sd_bus_message_open_container(m
, 'r', "sv");
135 return bus_log_create_error(r
);
137 r
= sd_bus_message_append_basic(m
, 's', field
);
139 return bus_log_create_error(r
);
141 r
= sd_bus_message_open_container(m
, 'v', "as");
143 return bus_log_create_error(r
);
145 r
= sd_bus_message_open_container(m
, 'a', "s");
147 return bus_log_create_error(r
);
150 _cleanup_free_
char *word
= NULL
;
152 r
= extract_first_word(&p
, &word
, NULL
, flags
);
158 return log_error_errno(r
, "Invalid syntax: %s", eq
);
160 r
= sd_bus_message_append_basic(m
, 's', word
);
162 return bus_log_create_error(r
);
165 r
= sd_bus_message_close_container(m
);
167 return bus_log_create_error(r
);
169 r
= sd_bus_message_close_container(m
);
171 return bus_log_create_error(r
);
173 r
= sd_bus_message_close_container(m
);
175 return bus_log_create_error(r
);
180 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
183 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
185 return bus_log_create_error(r
);
187 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
189 return bus_log_create_error(r
);
191 r
= sd_bus_message_open_container(m
, 'v', "ay");
193 return bus_log_create_error(r
);
195 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
197 return bus_log_create_error(r
);
199 r
= sd_bus_message_close_container(m
);
201 return bus_log_create_error(r
);
203 r
= sd_bus_message_close_container(m
);
205 return bus_log_create_error(r
);
210 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
216 r
= parse_sec(eq
, &t
);
218 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
221 n
= newa(char, l
+ 2);
222 /* Change suffix Sec → USec */
223 strcpy(mempcpy(n
, field
, l
- 3), "USec");
225 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
227 return bus_log_create_error(r
);
232 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
236 r
= parse_size(eq
, base
, &v
);
238 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
240 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
242 return bus_log_create_error(r
);
247 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
248 bool explicit_path
= false, done
= false;
249 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
250 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
251 ExecCommandFlags flags
= 0;
252 bool is_ex_prop
= endswith(field
, "Ex");
259 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
262 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
271 explicit_path
= true;
277 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
280 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
286 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
289 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
295 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
297 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
298 flags
&= ~EXEC_COMMAND_NO_SETUID
;
299 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
302 flags
|= EXEC_COMMAND_NO_SETUID
;
313 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
314 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
316 upgraded_name
= strappend(field
, "Ex");
322 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
324 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
328 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
330 return log_error_errno(r
, "Failed to parse path: %m");
333 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
335 return log_error_errno(r
, "Failed to parse command line: %m");
337 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
339 return bus_log_create_error(r
);
341 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
343 return bus_log_create_error(r
);
345 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
347 return bus_log_create_error(r
);
349 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
351 return bus_log_create_error(r
);
353 if (!strv_isempty(l
)) {
355 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
357 return bus_log_create_error(r
);
359 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
361 return bus_log_create_error(r
);
363 r
= sd_bus_message_append_strv(m
, l
);
365 return bus_log_create_error(r
);
367 r
= is_ex_prop
? sd_bus_message_append_strv(m
, ex_opts
) : sd_bus_message_append(m
, "b", FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
));
369 return bus_log_create_error(r
);
371 r
= sd_bus_message_close_container(m
);
373 return bus_log_create_error(r
);
376 r
= sd_bus_message_close_container(m
);
378 return bus_log_create_error(r
);
380 r
= sd_bus_message_close_container(m
);
382 return bus_log_create_error(r
);
384 r
= sd_bus_message_close_container(m
);
386 return bus_log_create_error(r
);
391 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
397 r
= sd_bus_message_open_container(m
, 'r', "iayu");
401 r
= sd_bus_message_append(m
, "i", family
);
405 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
409 r
= sd_bus_message_append(m
, "u", prefixlen
);
413 return sd_bus_message_close_container(m
);
416 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
419 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
421 return bus_append_string(m
, field
, eq
);
423 if (STR_IN_SET(field
,
424 "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
425 "TasksAccounting", "IPAccounting"))
427 return bus_append_parse_boolean(m
, field
, eq
);
429 if (STR_IN_SET(field
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
431 return bus_append_cg_weight_parse(m
, field
, eq
);
433 if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares"))
435 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
437 if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight"))
439 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
441 if (streq(field
, "DisableControllers"))
443 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_QUOTES
);
445 if (streq(field
, "Delegate")) {
447 r
= parse_boolean(eq
);
449 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_QUOTES
);
451 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
453 return bus_log_create_error(r
);
458 if (STR_IN_SET(field
, "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
460 if (isempty(eq
) || streq(eq
, "infinity")) {
461 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
463 return bus_log_create_error(r
);
467 r
= parse_permille(eq
);
471 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
472 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
473 * size can be determined server-side. */
475 n
= strjoina(field
, "Scale");
476 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
478 return bus_log_create_error(r
);
483 if (streq(field
, "TasksMax"))
484 return bus_append_safe_atou64(m
, field
, eq
);
486 return bus_append_parse_size(m
, field
, eq
, 1024);
489 if (streq(field
, "CPUQuota")) {
492 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
494 r
= parse_permille_unbounded(eq
);
496 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
497 "CPU quota too small.");
499 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
501 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
505 return bus_log_create_error(r
);
510 if (streq(field
, "CPUQuotaPeriodSec")) {
511 usec_t u
= USEC_INFINITY
;
513 r
= parse_sec_def_infinity(eq
, &u
);
515 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
517 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
519 return bus_log_create_error(r
);
524 if (streq(field
, "DeviceAllow")) {
527 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
529 const char *path
= eq
, *rwm
= NULL
, *e
;
533 path
= strndupa(eq
, e
- eq
);
537 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
541 return bus_log_create_error(r
);
546 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
549 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
551 const char *path
, *bandwidth
, *e
;
556 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
557 "Failed to parse %s value %s.",
560 path
= strndupa(eq
, e
- eq
);
563 if (streq(bandwidth
, "infinity"))
564 bytes
= CGROUP_LIMIT_MAX
;
566 r
= parse_size(bandwidth
, 1000, &bytes
);
568 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
571 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
575 return bus_log_create_error(r
);
580 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
583 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
585 const char *path
, *weight
, *e
;
590 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
591 "Failed to parse %s value %s.",
594 path
= strndupa(eq
, e
- eq
);
597 r
= safe_atou64(weight
, &u
);
599 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
601 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
605 return bus_log_create_error(r
);
610 if (streq(field
, "IODeviceLatencyTargetSec")) {
611 const char *field_usec
= "IODeviceLatencyTargetUSec";
614 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
616 const char *path
, *target
, *e
;
621 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
622 "Failed to parse %s value %s.",
625 path
= strndupa(eq
, e
- eq
);
628 r
= parse_sec(target
, &usec
);
630 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
632 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
636 return bus_log_create_error(r
);
641 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
642 unsigned char prefixlen
;
643 union in_addr_union prefix
= {};
647 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
649 return bus_log_create_error(r
);
654 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
656 return bus_log_create_error(r
);
658 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
660 return bus_log_create_error(r
);
662 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
664 return bus_log_create_error(r
);
666 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
668 return bus_log_create_error(r
);
670 if (streq(eq
, "any")) {
671 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
673 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
675 return bus_log_create_error(r
);
677 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
679 return bus_log_create_error(r
);
681 } else if (is_localhost(eq
)) {
682 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
684 prefix
.in
.s_addr
= htobe32(0x7f000000);
685 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
687 return bus_log_create_error(r
);
689 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
690 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
694 } else if (streq(eq
, "link-local")) {
695 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
697 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
698 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
700 return bus_log_create_error(r
);
702 prefix
.in6
= (struct in6_addr
) {
703 .s6_addr32
[0] = htobe32(0xfe800000)
705 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
707 return bus_log_create_error(r
);
709 } else if (streq(eq
, "multicast")) {
710 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
712 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
713 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
715 return bus_log_create_error(r
);
717 prefix
.in6
= (struct in6_addr
) {
718 .s6_addr32
[0] = htobe32(0xff000000)
720 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
722 return bus_log_create_error(r
);
726 _cleanup_free_
char *word
= NULL
;
728 r
= extract_first_word(&eq
, &word
, NULL
, 0);
734 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
736 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
738 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
740 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
742 return bus_log_create_error(r
);
746 r
= sd_bus_message_close_container(m
);
748 return bus_log_create_error(r
);
750 r
= sd_bus_message_close_container(m
);
752 return bus_log_create_error(r
);
754 r
= sd_bus_message_close_container(m
);
756 return bus_log_create_error(r
);
764 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
766 if (streq(field
, "Where"))
768 return bus_append_string(m
, field
, eq
);
770 if (streq(field
, "DirectoryMode"))
772 return bus_append_parse_mode(m
, field
, eq
);
774 if (streq(field
, "TimeoutIdleSec"))
776 return bus_append_parse_sec_rename(m
, field
, eq
);
781 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
785 if (STR_IN_SET(field
,
787 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
788 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
789 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
790 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
792 return bus_append_string(m
, field
, eq
);
794 if (STR_IN_SET(field
,
795 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
796 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
797 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
798 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
799 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
800 "ProtectHostname", "RestrictSUIDSGID"))
802 return bus_append_parse_boolean(m
, field
, eq
);
804 if (STR_IN_SET(field
,
805 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
806 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
807 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
808 "SupplementaryGroups", "SystemCallArchitectures"))
810 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
812 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
814 return bus_append_log_level_from_string(m
, field
, eq
);
816 if (streq(field
, "SyslogFacility"))
818 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
820 if (streq(field
, "SecureBits"))
822 return bus_append_secure_bits_from_string(m
, field
, eq
);
824 if (streq(field
, "CPUSchedulingPolicy"))
826 return bus_append_sched_policy_from_string(m
, field
, eq
);
828 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
830 return bus_append_safe_atoi(m
, field
, eq
);
832 if (streq(field
, "Nice"))
834 return bus_append_parse_nice(m
, field
, eq
);
836 if (streq(field
, "SystemCallErrorNumber"))
838 return bus_append_parse_errno(m
, field
, eq
);
840 if (streq(field
, "IOSchedulingClass"))
842 return bus_append_ioprio_class_from_string(m
, field
, eq
);
844 if (streq(field
, "IOSchedulingPriority"))
846 return bus_append_ioprio_parse_priority(m
, field
, eq
);
848 if (STR_IN_SET(field
,
849 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
850 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
852 return bus_append_parse_mode(m
, field
, eq
);
854 if (streq(field
, "TimerSlackNSec"))
856 return bus_append_parse_nsec(m
, field
, eq
);
858 if (streq(field
, "LogRateLimitIntervalSec"))
860 return bus_append_parse_sec_rename(m
, field
, eq
);
862 if (streq(field
, "LogRateLimitBurst"))
864 return bus_append_safe_atou(m
, field
, eq
);
866 if (streq(field
, "MountFlags"))
868 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
870 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
872 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
874 if (streq(field
, "EnvironmentFile")) {
877 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
879 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
880 eq
[0] == '-' ? eq
+ 1 : eq
,
883 return bus_log_create_error(r
);
888 if (streq(field
, "LogExtraFields")) {
890 r
= sd_bus_message_open_container(m
, 'r', "sv");
892 return bus_log_create_error(r
);
894 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
896 return bus_log_create_error(r
);
898 r
= sd_bus_message_open_container(m
, 'v', "aay");
900 return bus_log_create_error(r
);
902 r
= sd_bus_message_open_container(m
, 'a', "ay");
904 return bus_log_create_error(r
);
906 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
908 return bus_log_create_error(r
);
910 r
= sd_bus_message_close_container(m
);
912 return bus_log_create_error(r
);
914 r
= sd_bus_message_close_container(m
);
916 return bus_log_create_error(r
);
918 r
= sd_bus_message_close_container(m
);
920 return bus_log_create_error(r
);
925 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
926 const char *n
, *appended
;
928 if ((n
= startswith(eq
, "fd:"))) {
929 appended
= strjoina(field
, "FileDescriptorName");
930 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
931 } else if ((n
= startswith(eq
, "file:"))) {
932 appended
= strjoina(field
, "File");
933 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
934 } else if ((n
= startswith(eq
, "append:"))) {
935 appended
= strjoina(field
, "FileToAppend");
936 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
938 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
940 return bus_log_create_error(r
);
945 if (streq(field
, "StandardInputText")) {
946 _cleanup_free_
char *unescaped
= NULL
;
948 r
= cunescape(eq
, 0, &unescaped
);
950 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
952 if (!strextend(&unescaped
, "\n", NULL
))
955 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
956 * interface anyway */
958 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
961 if (streq(field
, "StandardInputData")) {
962 _cleanup_free_
void *decoded
= NULL
;
965 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
967 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
969 return bus_append_byte_array(m
, field
, decoded
, sz
);
972 if ((suffix
= startswith(field
, "Limit"))) {
975 rl
= rlimit_from_string(suffix
);
980 r
= rlimit_parse(rl
, eq
, &l
);
982 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
984 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
986 return bus_log_create_error(r
);
988 sn
= strjoina(field
, "Soft");
989 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
991 return bus_log_create_error(r
);
997 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
1006 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1008 return bus_log_create_error(r
);
1013 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
1015 bool invert
= false;
1023 r
= capability_set_from_string(p
, &sum
);
1025 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1027 sum
= invert
? ~sum
: sum
;
1029 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1031 return bus_log_create_error(r
);
1036 if (streq(field
, "CPUAffinity")) {
1037 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1038 _cleanup_free_
uint8_t *array
= NULL
;
1041 r
= parse_cpu_set(eq
, &cpuset
);
1043 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1045 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1047 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1049 return bus_append_byte_array(m
, field
, array
, allocated
);
1052 if (streq(field
, "NUMAPolicy")) {
1053 r
= mpol_from_string(eq
);
1055 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1057 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1059 return bus_log_create_error(r
);
1064 if (streq(field
, "NUMAMask")) {
1065 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1066 _cleanup_free_
uint8_t *array
= NULL
;
1069 r
= parse_cpu_set(eq
, &nodes
);
1071 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1073 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1075 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1077 return bus_append_byte_array(m
, field
, array
, allocated
);
1080 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
1089 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1091 return bus_log_create_error(r
);
1093 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1095 return bus_log_create_error(r
);
1097 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1099 return bus_log_create_error(r
);
1101 r
= sd_bus_message_open_container(m
, 'r', "bas");
1103 return bus_log_create_error(r
);
1105 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
1107 return bus_log_create_error(r
);
1109 r
= sd_bus_message_open_container(m
, 'a', "s");
1111 return bus_log_create_error(r
);
1114 _cleanup_free_
char *word
= NULL
;
1116 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1122 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1124 r
= sd_bus_message_append_basic(m
, 's', word
);
1126 return bus_log_create_error(r
);
1129 r
= sd_bus_message_close_container(m
);
1131 return bus_log_create_error(r
);
1133 r
= sd_bus_message_close_container(m
);
1135 return bus_log_create_error(r
);
1137 r
= sd_bus_message_close_container(m
);
1139 return bus_log_create_error(r
);
1141 r
= sd_bus_message_close_container(m
);
1143 return bus_log_create_error(r
);
1148 if (streq(field
, "RestrictNamespaces")) {
1149 bool invert
= false;
1150 unsigned long flags
;
1152 r
= parse_boolean(eq
);
1156 flags
= NAMESPACE_FLAGS_ALL
;
1163 r
= namespace_flags_from_string(eq
, &flags
);
1165 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1169 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1171 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1173 return bus_log_create_error(r
);
1178 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1181 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1183 return bus_log_create_error(r
);
1185 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1187 return bus_log_create_error(r
);
1189 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1191 return bus_log_create_error(r
);
1193 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1195 return bus_log_create_error(r
);
1198 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1199 char *s
= NULL
, *d
= NULL
;
1200 bool ignore_enoent
= false;
1201 uint64_t flags
= MS_REC
;
1203 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1205 return log_error_errno(r
, "Failed to parse argument: %m");
1211 ignore_enoent
= true;
1215 if (p
&& p
[-1] == ':') {
1216 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1218 return log_error_errno(r
, "Failed to parse argument: %m");
1220 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1221 "Missing argument after ':': %s",
1226 if (p
&& p
[-1] == ':') {
1227 _cleanup_free_
char *options
= NULL
;
1229 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
1231 return log_error_errno(r
, "Failed to parse argument: %m");
1233 if (isempty(options
) || streq(options
, "rbind"))
1235 else if (streq(options
, "norbind"))
1238 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1239 "Unknown options: %s",
1245 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1247 return bus_log_create_error(r
);
1250 r
= sd_bus_message_close_container(m
);
1252 return bus_log_create_error(r
);
1254 r
= sd_bus_message_close_container(m
);
1256 return bus_log_create_error(r
);
1258 r
= sd_bus_message_close_container(m
);
1260 return bus_log_create_error(r
);
1265 if (streq(field
, "TemporaryFileSystem")) {
1268 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1270 return bus_log_create_error(r
);
1272 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1274 return bus_log_create_error(r
);
1276 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1278 return bus_log_create_error(r
);
1280 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1282 return bus_log_create_error(r
);
1285 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1288 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1290 return log_error_errno(r
, "Failed to parse argument: %m");
1295 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1297 return log_error_errno(r
, "Failed to parse argument: %m");
1299 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1300 "Failed to parse argument: %s",
1303 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1305 return bus_log_create_error(r
);
1308 r
= sd_bus_message_close_container(m
);
1310 return bus_log_create_error(r
);
1312 r
= sd_bus_message_close_container(m
);
1314 return bus_log_create_error(r
);
1316 r
= sd_bus_message_close_container(m
);
1318 return bus_log_create_error(r
);
1326 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1328 if (streq(field
, "KillMode"))
1330 return bus_append_string(m
, field
, eq
);
1332 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1334 return bus_append_parse_boolean(m
, field
, eq
);
1336 if (STR_IN_SET(field
, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1338 return bus_append_signal_from_string(m
, field
, eq
);
1343 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1345 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1347 return bus_append_string(m
, field
, eq
);
1349 if (streq(field
, "TimeoutSec"))
1351 return bus_append_parse_sec_rename(m
, field
, eq
);
1353 if (streq(field
, "DirectoryMode"))
1355 return bus_append_parse_mode(m
, field
, eq
);
1357 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1359 return bus_append_parse_boolean(m
, field
, eq
);
1364 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1367 if (streq(field
, "MakeDirectory"))
1369 return bus_append_parse_boolean(m
, field
, eq
);
1371 if (streq(field
, "DirectoryMode"))
1373 return bus_append_parse_mode(m
, field
, eq
);
1375 if (STR_IN_SET(field
,
1376 "PathExists", "PathExistsGlob", "PathChanged",
1377 "PathModified", "DirectoryNotEmpty")) {
1380 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1382 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1384 return bus_log_create_error(r
);
1392 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1395 if (STR_IN_SET(field
,
1396 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1397 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
1399 return bus_append_string(m
, field
, eq
);
1401 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1403 return bus_append_parse_boolean(m
, field
, eq
);
1405 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1407 return bus_append_parse_sec_rename(m
, field
, eq
);
1409 if (streq(field
, "TimeoutSec")) {
1411 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1415 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1418 if (streq(field
, "FileDescriptorStoreMax"))
1420 return bus_append_safe_atou(m
, field
, eq
);
1422 if (STR_IN_SET(field
,
1423 "ExecStartPre", "ExecStart", "ExecStartPost",
1424 "ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
1425 "ExecReload", "ExecStop", "ExecStopPost"))
1426 return bus_append_exec_command(m
, field
, eq
);
1428 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1429 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1430 size_t sz_status
= 0, sz_signal
= 0;
1434 _cleanup_free_
char *word
= NULL
;
1437 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1443 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1445 r
= safe_atoi(word
, &val
);
1447 val
= signal_from_string(word
);
1449 return log_error_errno(r
, "Invalid status or signal %s in %s: %m", word
, field
);
1451 signal
= reallocarray(signal
, sz_signal
+ 1, sizeof(int));
1455 signal
[sz_signal
++] = val
;
1457 status
= reallocarray(status
, sz_status
+ 1, sizeof(int));
1461 status
[sz_status
++] = val
;
1465 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1467 return bus_log_create_error(r
);
1469 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1471 return bus_log_create_error(r
);
1473 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1475 return bus_log_create_error(r
);
1477 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1479 return bus_log_create_error(r
);
1481 r
= sd_bus_message_append_array(m
, 'i', status
, sz_status
);
1483 return bus_log_create_error(r
);
1485 r
= sd_bus_message_append_array(m
, 'i', signal
, sz_signal
);
1487 return bus_log_create_error(r
);
1489 r
= sd_bus_message_close_container(m
);
1491 return bus_log_create_error(r
);
1493 r
= sd_bus_message_close_container(m
);
1495 return bus_log_create_error(r
);
1497 r
= sd_bus_message_close_container(m
);
1499 return bus_log_create_error(r
);
1507 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1510 if (STR_IN_SET(field
,
1511 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1512 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1514 return bus_append_parse_boolean(m
, field
, eq
);
1516 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1518 return bus_append_safe_atoi(m
, field
, eq
);
1520 if (streq(field
, "IPTOS"))
1522 return bus_append_ip_tos_from_string(m
, field
, eq
);
1524 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1526 return bus_append_safe_atou(m
, field
, eq
);
1528 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1530 return bus_append_parse_mode(m
, field
, eq
);
1532 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1534 return bus_append_safe_atoi64(m
, field
, eq
);
1536 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1538 return bus_append_parse_sec_rename(m
, field
, eq
);
1540 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1542 return bus_append_parse_size(m
, field
, eq
, 1024);
1544 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1546 return bus_append_exec_command(m
, field
, eq
);
1548 if (STR_IN_SET(field
,
1549 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1550 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1551 "SocketUser", "SocketGroup"))
1553 return bus_append_string(m
, field
, eq
);
1555 if (streq(field
, "Symlinks"))
1557 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1559 if (streq(field
, "SocketProtocol"))
1561 return bus_append_parse_ip_protocol(m
, field
, eq
);
1563 if (STR_IN_SET(field
,
1564 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1565 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1568 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1570 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1572 return bus_log_create_error(r
);
1579 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1582 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent",
1583 "OnTimezoneChange", "OnClockChange"))
1585 return bus_append_parse_boolean(m
, field
, eq
);
1587 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1589 return bus_append_parse_sec_rename(m
, field
, eq
);
1591 if (STR_IN_SET(field
,
1592 "OnActiveSec", "OnBootSec", "OnStartupSec",
1593 "OnUnitActiveSec","OnUnitInactiveSec")) {
1596 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1599 r
= parse_sec(eq
, &t
);
1601 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1603 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1606 return bus_log_create_error(r
);
1611 if (streq(field
, "OnCalendar")) {
1614 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1616 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1618 return bus_log_create_error(r
);
1626 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1627 ConditionType t
= _CONDITION_TYPE_INVALID
;
1628 bool is_condition
= false;
1631 if (STR_IN_SET(field
,
1632 "Description", "SourcePath", "OnFailureJobMode",
1633 "JobTimeoutAction", "JobTimeoutRebootArgument",
1634 "StartLimitAction", "FailureAction", "SuccessAction",
1635 "RebootArgument", "CollectMode"))
1637 return bus_append_string(m
, field
, eq
);
1639 if (STR_IN_SET(field
,
1640 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1641 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1643 return bus_append_parse_boolean(m
, field
, eq
);
1645 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1647 return bus_append_parse_sec_rename(m
, field
, eq
);
1649 if (streq(field
, "StartLimitBurst"))
1651 return bus_append_safe_atou(m
, field
, eq
);
1653 if (STR_IN_SET(field
, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1656 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1660 r
= safe_atou8(eq
, &u
);
1662 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1664 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1667 return bus_log_create_error(r
);
1672 if (unit_dependency_from_string(field
) >= 0 ||
1673 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1675 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1677 t
= condition_type_from_string(field
);
1679 is_condition
= true;
1681 t
= assert_type_from_string(field
);
1684 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1687 int trigger
, negate
;
1689 trigger
= *p
== '|';
1697 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1698 field
, trigger
, negate
, p
);
1701 return bus_log_create_error(r
);
1709 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1710 const char *eq
, *field
;
1716 eq
= strchr(assignment
, '=');
1718 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1719 "Not an assignment: %s", assignment
);
1721 field
= strndupa(assignment
, eq
- assignment
);
1726 r
= bus_append_cgroup_property(m
, field
, eq
);
1730 r
= bus_append_execute_property(m
, field
, eq
);
1734 r
= bus_append_kill_property(m
, field
, eq
);
1738 r
= bus_append_service_property(m
, field
, eq
);
1744 r
= bus_append_cgroup_property(m
, field
, eq
);
1748 r
= bus_append_execute_property(m
, field
, eq
);
1752 r
= bus_append_kill_property(m
, field
, eq
);
1756 r
= bus_append_socket_property(m
, field
, eq
);
1762 r
= bus_append_timer_property(m
, field
, eq
);
1768 r
= bus_append_path_property(m
, field
, eq
);
1774 r
= bus_append_cgroup_property(m
, field
, eq
);
1781 if (streq(field
, "TimeoutStopSec"))
1782 return bus_append_parse_sec_rename(m
, field
, eq
);
1784 r
= bus_append_cgroup_property(m
, field
, eq
);
1788 r
= bus_append_kill_property(m
, field
, eq
);
1794 r
= bus_append_cgroup_property(m
, field
, eq
);
1798 r
= bus_append_execute_property(m
, field
, eq
);
1802 r
= bus_append_kill_property(m
, field
, eq
);
1806 r
= bus_append_mount_property(m
, field
, eq
);
1812 case UNIT_AUTOMOUNT
:
1813 r
= bus_append_automount_property(m
, field
, eq
);
1822 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1823 "Not supported unit type");
1826 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1827 "Invalid unit type");
1830 r
= bus_append_unit_property(m
, field
, eq
);
1834 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1835 "Unknown assignment: %s", assignment
);
1838 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1844 STRV_FOREACH(i
, l
) {
1845 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1853 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
1854 const char *type
, *path
, *source
;
1857 /* changes is dereferenced when calling unit_file_dump_changes() later,
1858 * so we have to make sure this is not NULL. */
1862 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1864 return bus_log_parse_error(r
);
1866 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1867 /* We expect only "success" changes to be sent over the bus.
1868 Hence, reject anything negative. */
1869 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1872 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1876 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1881 return bus_log_parse_error(r
);
1883 r
= sd_bus_message_exit_container(m
);
1885 return bus_log_parse_error(r
);
1887 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
1891 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
1892 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1893 _cleanup_free_
char *path
= NULL
;
1896 path
= unit_dbus_path_from_name(name
);
1900 /* This function warns on it's own, because otherwise it'd be awkward to pass
1901 * the dbus error message around. */
1903 r
= sd_bus_get_property_string(
1905 "org.freedesktop.systemd1",
1907 "org.freedesktop.systemd1.Unit",
1912 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));