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
= strjoin(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_UNQUOTE
|EXTRACT_CUNESCAPE
);
330 return log_error_errno(r
, "Failed to parse path: %m");
333 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|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_UNQUOTE
);
445 if (streq(field
, "Delegate")) {
447 r
= parse_boolean(eq
);
449 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
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
);
761 if (STR_IN_SET(field
, "IPIngressFilterPath", "IPEgressFilterPath")) {
763 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
765 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
768 return bus_log_create_error(r
);
776 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
778 if (streq(field
, "Where"))
780 return bus_append_string(m
, field
, eq
);
782 if (streq(field
, "DirectoryMode"))
784 return bus_append_parse_mode(m
, field
, eq
);
786 if (streq(field
, "TimeoutIdleSec"))
788 return bus_append_parse_sec_rename(m
, field
, eq
);
793 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
797 if (STR_IN_SET(field
,
799 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
800 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
801 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
802 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
804 return bus_append_string(m
, field
, eq
);
806 if (STR_IN_SET(field
,
807 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
808 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
809 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
810 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
811 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
812 "ProtectHostname", "RestrictSUIDSGID"))
814 return bus_append_parse_boolean(m
, field
, eq
);
816 if (STR_IN_SET(field
,
817 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
818 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
819 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
820 "SupplementaryGroups", "SystemCallArchitectures"))
822 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
824 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
826 return bus_append_log_level_from_string(m
, field
, eq
);
828 if (streq(field
, "SyslogFacility"))
830 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
832 if (streq(field
, "SecureBits"))
834 return bus_append_secure_bits_from_string(m
, field
, eq
);
836 if (streq(field
, "CPUSchedulingPolicy"))
838 return bus_append_sched_policy_from_string(m
, field
, eq
);
840 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
842 return bus_append_safe_atoi(m
, field
, eq
);
844 if (streq(field
, "Nice"))
846 return bus_append_parse_nice(m
, field
, eq
);
848 if (streq(field
, "SystemCallErrorNumber"))
850 return bus_append_parse_errno(m
, field
, eq
);
852 if (streq(field
, "IOSchedulingClass"))
854 return bus_append_ioprio_class_from_string(m
, field
, eq
);
856 if (streq(field
, "IOSchedulingPriority"))
858 return bus_append_ioprio_parse_priority(m
, field
, eq
);
860 if (STR_IN_SET(field
,
861 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
862 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
864 return bus_append_parse_mode(m
, field
, eq
);
866 if (streq(field
, "TimerSlackNSec"))
868 return bus_append_parse_nsec(m
, field
, eq
);
870 if (streq(field
, "LogRateLimitIntervalSec"))
872 return bus_append_parse_sec_rename(m
, field
, eq
);
874 if (streq(field
, "LogRateLimitBurst"))
876 return bus_append_safe_atou(m
, field
, eq
);
878 if (streq(field
, "MountFlags"))
880 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
882 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
884 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
886 if (streq(field
, "EnvironmentFile")) {
889 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
891 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
892 eq
[0] == '-' ? eq
+ 1 : eq
,
895 return bus_log_create_error(r
);
900 if (streq(field
, "LogExtraFields")) {
902 r
= sd_bus_message_open_container(m
, 'r', "sv");
904 return bus_log_create_error(r
);
906 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
908 return bus_log_create_error(r
);
910 r
= sd_bus_message_open_container(m
, 'v', "aay");
912 return bus_log_create_error(r
);
914 r
= sd_bus_message_open_container(m
, 'a', "ay");
916 return bus_log_create_error(r
);
918 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
920 return bus_log_create_error(r
);
922 r
= sd_bus_message_close_container(m
);
924 return bus_log_create_error(r
);
926 r
= sd_bus_message_close_container(m
);
928 return bus_log_create_error(r
);
930 r
= sd_bus_message_close_container(m
);
932 return bus_log_create_error(r
);
937 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
938 const char *n
, *appended
;
940 if ((n
= startswith(eq
, "fd:"))) {
941 appended
= strjoina(field
, "FileDescriptorName");
942 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
943 } else if ((n
= startswith(eq
, "file:"))) {
944 appended
= strjoina(field
, "File");
945 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
946 } else if ((n
= startswith(eq
, "append:"))) {
947 appended
= strjoina(field
, "FileToAppend");
948 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
950 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
952 return bus_log_create_error(r
);
957 if (streq(field
, "StandardInputText")) {
958 _cleanup_free_
char *unescaped
= NULL
;
960 r
= cunescape(eq
, 0, &unescaped
);
962 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
964 if (!strextend(&unescaped
, "\n", NULL
))
967 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
968 * interface anyway */
970 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
973 if (streq(field
, "StandardInputData")) {
974 _cleanup_free_
void *decoded
= NULL
;
977 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
979 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
981 return bus_append_byte_array(m
, field
, decoded
, sz
);
984 if ((suffix
= startswith(field
, "Limit"))) {
987 rl
= rlimit_from_string(suffix
);
992 r
= rlimit_parse(rl
, eq
, &l
);
994 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
996 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
998 return bus_log_create_error(r
);
1000 sn
= strjoina(field
, "Soft");
1001 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1003 return bus_log_create_error(r
);
1009 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
1018 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1020 return bus_log_create_error(r
);
1025 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
1027 bool invert
= false;
1035 r
= capability_set_from_string(p
, &sum
);
1037 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1039 sum
= invert
? ~sum
: sum
;
1041 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1043 return bus_log_create_error(r
);
1048 if (streq(field
, "CPUAffinity")) {
1049 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1050 _cleanup_free_
uint8_t *array
= NULL
;
1053 r
= parse_cpu_set(eq
, &cpuset
);
1055 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1057 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1059 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1061 return bus_append_byte_array(m
, field
, array
, allocated
);
1064 if (streq(field
, "NUMAPolicy")) {
1065 r
= mpol_from_string(eq
);
1067 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1069 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1071 return bus_log_create_error(r
);
1076 if (streq(field
, "NUMAMask")) {
1077 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1078 _cleanup_free_
uint8_t *array
= NULL
;
1081 r
= parse_cpu_set(eq
, &nodes
);
1083 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1085 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1087 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1089 return bus_append_byte_array(m
, field
, array
, allocated
);
1092 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
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', "(bas)");
1111 return bus_log_create_error(r
);
1113 r
= sd_bus_message_open_container(m
, 'r', "bas");
1115 return bus_log_create_error(r
);
1117 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
1119 return bus_log_create_error(r
);
1121 r
= sd_bus_message_open_container(m
, 'a', "s");
1123 return bus_log_create_error(r
);
1126 _cleanup_free_
char *word
= NULL
;
1128 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1134 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1136 r
= sd_bus_message_append_basic(m
, 's', word
);
1138 return bus_log_create_error(r
);
1141 r
= sd_bus_message_close_container(m
);
1143 return bus_log_create_error(r
);
1145 r
= sd_bus_message_close_container(m
);
1147 return bus_log_create_error(r
);
1149 r
= sd_bus_message_close_container(m
);
1151 return bus_log_create_error(r
);
1153 r
= sd_bus_message_close_container(m
);
1155 return bus_log_create_error(r
);
1160 if (streq(field
, "RestrictNamespaces")) {
1161 bool invert
= false;
1162 unsigned long flags
;
1164 r
= parse_boolean(eq
);
1168 flags
= NAMESPACE_FLAGS_ALL
;
1175 r
= namespace_flags_from_string(eq
, &flags
);
1177 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1181 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1183 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1185 return bus_log_create_error(r
);
1190 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1193 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1195 return bus_log_create_error(r
);
1197 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1199 return bus_log_create_error(r
);
1201 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1203 return bus_log_create_error(r
);
1205 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1207 return bus_log_create_error(r
);
1210 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1211 char *s
= NULL
, *d
= NULL
;
1212 bool ignore_enoent
= false;
1213 uint64_t flags
= MS_REC
;
1215 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1217 return log_error_errno(r
, "Failed to parse argument: %m");
1223 ignore_enoent
= true;
1227 if (p
&& p
[-1] == ':') {
1228 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1230 return log_error_errno(r
, "Failed to parse argument: %m");
1232 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1233 "Missing argument after ':': %s",
1238 if (p
&& p
[-1] == ':') {
1239 _cleanup_free_
char *options
= NULL
;
1241 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1243 return log_error_errno(r
, "Failed to parse argument: %m");
1245 if (isempty(options
) || streq(options
, "rbind"))
1247 else if (streq(options
, "norbind"))
1250 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1251 "Unknown options: %s",
1257 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1259 return bus_log_create_error(r
);
1262 r
= sd_bus_message_close_container(m
);
1264 return bus_log_create_error(r
);
1266 r
= sd_bus_message_close_container(m
);
1268 return bus_log_create_error(r
);
1270 r
= sd_bus_message_close_container(m
);
1272 return bus_log_create_error(r
);
1277 if (streq(field
, "TemporaryFileSystem")) {
1280 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1282 return bus_log_create_error(r
);
1284 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1286 return bus_log_create_error(r
);
1288 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1290 return bus_log_create_error(r
);
1292 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1294 return bus_log_create_error(r
);
1297 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1300 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1302 return log_error_errno(r
, "Failed to parse argument: %m");
1307 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1309 return log_error_errno(r
, "Failed to parse argument: %m");
1311 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1312 "Failed to parse argument: %s",
1315 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1317 return bus_log_create_error(r
);
1320 r
= sd_bus_message_close_container(m
);
1322 return bus_log_create_error(r
);
1324 r
= sd_bus_message_close_container(m
);
1326 return bus_log_create_error(r
);
1328 r
= sd_bus_message_close_container(m
);
1330 return bus_log_create_error(r
);
1338 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1340 if (streq(field
, "KillMode"))
1342 return bus_append_string(m
, field
, eq
);
1344 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1346 return bus_append_parse_boolean(m
, field
, eq
);
1348 if (STR_IN_SET(field
, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1350 return bus_append_signal_from_string(m
, field
, eq
);
1355 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1357 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1359 return bus_append_string(m
, field
, eq
);
1361 if (streq(field
, "TimeoutSec"))
1363 return bus_append_parse_sec_rename(m
, field
, eq
);
1365 if (streq(field
, "DirectoryMode"))
1367 return bus_append_parse_mode(m
, field
, eq
);
1369 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1371 return bus_append_parse_boolean(m
, field
, eq
);
1376 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1379 if (streq(field
, "MakeDirectory"))
1381 return bus_append_parse_boolean(m
, field
, eq
);
1383 if (streq(field
, "DirectoryMode"))
1385 return bus_append_parse_mode(m
, field
, eq
);
1387 if (STR_IN_SET(field
,
1388 "PathExists", "PathExistsGlob", "PathChanged",
1389 "PathModified", "DirectoryNotEmpty")) {
1392 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1394 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1396 return bus_log_create_error(r
);
1404 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1407 if (STR_IN_SET(field
,
1408 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1409 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
1411 return bus_append_string(m
, field
, eq
);
1413 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1415 return bus_append_parse_boolean(m
, field
, eq
);
1417 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1419 return bus_append_parse_sec_rename(m
, field
, eq
);
1421 if (streq(field
, "TimeoutSec")) {
1423 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1427 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1430 if (streq(field
, "FileDescriptorStoreMax"))
1432 return bus_append_safe_atou(m
, field
, eq
);
1434 if (STR_IN_SET(field
,
1435 "ExecCondition", "ExecStartPre", "ExecStart", "ExecStartPost",
1436 "ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
1437 "ExecReload", "ExecStop", "ExecStopPost"))
1438 return bus_append_exec_command(m
, field
, eq
);
1440 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1441 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1442 size_t n_status
= 0, n_signal
= 0;
1446 _cleanup_free_
char *word
= NULL
;
1449 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1455 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1457 r
= safe_atoi(word
, &val
);
1459 val
= signal_from_string(word
);
1461 return log_error_errno(r
, "Invalid status or signal %s in %s: %m", word
, field
);
1463 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
1467 signal
[n_signal
++] = val
;
1469 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
1473 status
[n_status
++] = val
;
1477 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1479 return bus_log_create_error(r
);
1481 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1483 return bus_log_create_error(r
);
1485 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1487 return bus_log_create_error(r
);
1489 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1491 return bus_log_create_error(r
);
1493 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
1495 return bus_log_create_error(r
);
1497 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
1499 return bus_log_create_error(r
);
1501 r
= sd_bus_message_close_container(m
);
1503 return bus_log_create_error(r
);
1505 r
= sd_bus_message_close_container(m
);
1507 return bus_log_create_error(r
);
1509 r
= sd_bus_message_close_container(m
);
1511 return bus_log_create_error(r
);
1519 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1522 if (STR_IN_SET(field
,
1523 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1524 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1526 return bus_append_parse_boolean(m
, field
, eq
);
1528 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1530 return bus_append_safe_atoi(m
, field
, eq
);
1532 if (streq(field
, "IPTOS"))
1534 return bus_append_ip_tos_from_string(m
, field
, eq
);
1536 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1538 return bus_append_safe_atou(m
, field
, eq
);
1540 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1542 return bus_append_parse_mode(m
, field
, eq
);
1544 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1546 return bus_append_safe_atoi64(m
, field
, eq
);
1548 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1550 return bus_append_parse_sec_rename(m
, field
, eq
);
1552 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1554 return bus_append_parse_size(m
, field
, eq
, 1024);
1556 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1558 return bus_append_exec_command(m
, field
, eq
);
1560 if (STR_IN_SET(field
,
1561 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1562 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1563 "SocketUser", "SocketGroup"))
1565 return bus_append_string(m
, field
, eq
);
1567 if (streq(field
, "Symlinks"))
1569 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1571 if (streq(field
, "SocketProtocol"))
1573 return bus_append_parse_ip_protocol(m
, field
, eq
);
1575 if (STR_IN_SET(field
,
1576 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1577 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1580 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1582 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1584 return bus_log_create_error(r
);
1591 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1594 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent",
1595 "OnTimezoneChange", "OnClockChange"))
1597 return bus_append_parse_boolean(m
, field
, eq
);
1599 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1601 return bus_append_parse_sec_rename(m
, field
, eq
);
1603 if (STR_IN_SET(field
,
1604 "OnActiveSec", "OnBootSec", "OnStartupSec",
1605 "OnUnitActiveSec","OnUnitInactiveSec")) {
1608 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1611 r
= parse_sec(eq
, &t
);
1613 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1615 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1618 return bus_log_create_error(r
);
1623 if (streq(field
, "OnCalendar")) {
1626 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1628 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1630 return bus_log_create_error(r
);
1638 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1639 ConditionType t
= _CONDITION_TYPE_INVALID
;
1640 bool is_condition
= false;
1643 if (STR_IN_SET(field
,
1644 "Description", "SourcePath", "OnFailureJobMode",
1645 "JobTimeoutAction", "JobTimeoutRebootArgument",
1646 "StartLimitAction", "FailureAction", "SuccessAction",
1647 "RebootArgument", "CollectMode"))
1649 return bus_append_string(m
, field
, eq
);
1651 if (STR_IN_SET(field
,
1652 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1653 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1655 return bus_append_parse_boolean(m
, field
, eq
);
1657 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1659 return bus_append_parse_sec_rename(m
, field
, eq
);
1661 if (streq(field
, "StartLimitBurst"))
1663 return bus_append_safe_atou(m
, field
, eq
);
1665 if (STR_IN_SET(field
, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1668 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1672 r
= safe_atou8(eq
, &u
);
1674 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1676 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1679 return bus_log_create_error(r
);
1684 if (unit_dependency_from_string(field
) >= 0 ||
1685 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1687 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1689 t
= condition_type_from_string(field
);
1691 is_condition
= true;
1693 t
= assert_type_from_string(field
);
1696 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1699 int trigger
, negate
;
1701 trigger
= *p
== '|';
1709 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1710 field
, trigger
, negate
, p
);
1713 return bus_log_create_error(r
);
1721 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1722 const char *eq
, *field
;
1728 eq
= strchr(assignment
, '=');
1730 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1731 "Not an assignment: %s", assignment
);
1733 field
= strndupa(assignment
, eq
- assignment
);
1738 r
= bus_append_cgroup_property(m
, field
, eq
);
1742 r
= bus_append_execute_property(m
, field
, eq
);
1746 r
= bus_append_kill_property(m
, field
, eq
);
1750 r
= bus_append_service_property(m
, field
, eq
);
1756 r
= bus_append_cgroup_property(m
, field
, eq
);
1760 r
= bus_append_execute_property(m
, field
, eq
);
1764 r
= bus_append_kill_property(m
, field
, eq
);
1768 r
= bus_append_socket_property(m
, field
, eq
);
1774 r
= bus_append_timer_property(m
, field
, eq
);
1780 r
= bus_append_path_property(m
, field
, eq
);
1786 r
= bus_append_cgroup_property(m
, field
, eq
);
1793 if (streq(field
, "TimeoutStopSec"))
1794 return bus_append_parse_sec_rename(m
, field
, eq
);
1796 r
= bus_append_cgroup_property(m
, field
, eq
);
1800 r
= bus_append_kill_property(m
, field
, eq
);
1806 r
= bus_append_cgroup_property(m
, field
, eq
);
1810 r
= bus_append_execute_property(m
, field
, eq
);
1814 r
= bus_append_kill_property(m
, field
, eq
);
1818 r
= bus_append_mount_property(m
, field
, eq
);
1824 case UNIT_AUTOMOUNT
:
1825 r
= bus_append_automount_property(m
, field
, eq
);
1834 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1835 "Not supported unit type");
1838 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1839 "Invalid unit type");
1842 r
= bus_append_unit_property(m
, field
, eq
);
1846 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1847 "Unknown assignment: %s", assignment
);
1850 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1856 STRV_FOREACH(i
, l
) {
1857 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1865 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
1866 const char *type
, *path
, *source
;
1869 /* changes is dereferenced when calling unit_file_dump_changes() later,
1870 * so we have to make sure this is not NULL. */
1874 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1876 return bus_log_parse_error(r
);
1878 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1879 /* We expect only "success" changes to be sent over the bus.
1880 Hence, reject anything negative. */
1881 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1884 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1888 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1893 return bus_log_parse_error(r
);
1895 r
= sd_bus_message_exit_container(m
);
1897 return bus_log_parse_error(r
);
1899 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
1903 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
1904 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1905 _cleanup_free_
char *path
= NULL
;
1908 path
= unit_dbus_path_from_name(name
);
1912 /* This function warns on it's own, because otherwise it'd be awkward to pass
1913 * the dbus error message around. */
1915 r
= sd_bus_get_property_string(
1917 "org.freedesktop.systemd1",
1919 "org.freedesktop.systemd1.Unit",
1924 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));