1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
5 #include "bus-unit-util.h"
8 #include "cgroup-setup.h"
9 #include "cgroup-util.h"
10 #include "condition.h"
11 #include "cpu-set-util.h"
13 #include "exec-util.h"
14 #include "exit-status.h"
15 #include "hexdecoct.h"
16 #include "hostname-util.h"
17 #include "in-addr-util.h"
18 #include "ip-protocol-list.h"
19 #include "locale-util.h"
21 #include "missing_fs.h"
22 #include "mountpoint-util.h"
24 #include "parse-util.h"
25 #include "process-util.h"
26 #include "rlimit-util.h"
27 #include "securebits-util.h"
28 #include "signal-util.h"
29 #include "socket-util.h"
30 #include "sort-util.h"
31 #include "string-util.h"
32 #include "syslog-util.h"
33 #include "terminal-util.h"
35 #include "user-util.h"
38 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
44 return sd_bus_message_read(
59 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
60 static int bus_append_##parse_func( \
67 r = parse_func(eq, &val); \
69 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
71 r = sd_bus_message_append(m, "(sv)", field, \
72 bus_type, (cast_type) val); \
74 return bus_log_create_error(r); \
79 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
80 static int bus_append_##parse_func( \
88 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
90 r = sd_bus_message_append(m, "(sv)", field, \
91 bus_type, (int32_t) r); \
93 return bus_log_create_error(r); \
98 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
99 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
100 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
101 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
102 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
103 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
104 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
105 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
106 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
107 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
108 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
109 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
110 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
111 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
112 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
113 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
114 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
115 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
116 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
117 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
118 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
119 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
121 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
124 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
126 return bus_log_create_error(r
);
131 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
135 r
= sd_bus_message_open_container(m
, 'r', "sv");
137 return bus_log_create_error(r
);
139 r
= sd_bus_message_append_basic(m
, 's', field
);
141 return bus_log_create_error(r
);
143 r
= sd_bus_message_open_container(m
, 'v', "as");
145 return bus_log_create_error(r
);
147 r
= sd_bus_message_open_container(m
, 'a', "s");
149 return bus_log_create_error(r
);
152 _cleanup_free_
char *word
= NULL
;
154 r
= extract_first_word(&p
, &word
, NULL
, flags
);
160 return log_error_errno(r
, "Invalid syntax: %s", eq
);
162 r
= sd_bus_message_append_basic(m
, 's', word
);
164 return bus_log_create_error(r
);
167 r
= sd_bus_message_close_container(m
);
169 return bus_log_create_error(r
);
171 r
= sd_bus_message_close_container(m
);
173 return bus_log_create_error(r
);
175 r
= sd_bus_message_close_container(m
);
177 return bus_log_create_error(r
);
182 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
185 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
187 return bus_log_create_error(r
);
189 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
191 return bus_log_create_error(r
);
193 r
= sd_bus_message_open_container(m
, 'v', "ay");
195 return bus_log_create_error(r
);
197 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
199 return bus_log_create_error(r
);
201 r
= sd_bus_message_close_container(m
);
203 return bus_log_create_error(r
);
205 r
= sd_bus_message_close_container(m
);
207 return bus_log_create_error(r
);
212 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
218 r
= parse_sec(eq
, &t
);
220 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
223 n
= newa(char, l
+ 2);
224 /* Change suffix Sec → USec */
225 strcpy(mempcpy(n
, field
, l
- 3), "USec");
227 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
229 return bus_log_create_error(r
);
234 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
238 r
= parse_size(eq
, base
, &v
);
240 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
242 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
244 return bus_log_create_error(r
);
249 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
250 bool explicit_path
= false, done
= false;
251 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
252 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
253 ExecCommandFlags flags
= 0;
254 bool is_ex_prop
= endswith(field
, "Ex");
261 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
264 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
273 explicit_path
= true;
279 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
282 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
288 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
291 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
297 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
299 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
300 flags
&= ~EXEC_COMMAND_NO_SETUID
;
301 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
304 flags
|= EXEC_COMMAND_NO_SETUID
;
315 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
316 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
318 upgraded_name
= strjoin(field
, "Ex");
324 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
326 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
330 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
332 return log_error_errno(r
, "Failed to parse path: %m");
335 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
337 return log_error_errno(r
, "Failed to parse command line: %m");
339 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
341 return bus_log_create_error(r
);
343 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
345 return bus_log_create_error(r
);
347 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
349 return bus_log_create_error(r
);
351 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
353 return bus_log_create_error(r
);
355 if (!strv_isempty(l
)) {
357 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
359 return bus_log_create_error(r
);
361 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
363 return bus_log_create_error(r
);
365 r
= sd_bus_message_append_strv(m
, l
);
367 return bus_log_create_error(r
);
369 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
));
371 return bus_log_create_error(r
);
373 r
= sd_bus_message_close_container(m
);
375 return bus_log_create_error(r
);
378 r
= sd_bus_message_close_container(m
);
380 return bus_log_create_error(r
);
382 r
= sd_bus_message_close_container(m
);
384 return bus_log_create_error(r
);
386 r
= sd_bus_message_close_container(m
);
388 return bus_log_create_error(r
);
393 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
399 r
= sd_bus_message_open_container(m
, 'r', "iayu");
403 r
= sd_bus_message_append(m
, "i", family
);
407 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
411 r
= sd_bus_message_append(m
, "u", prefixlen
);
415 return sd_bus_message_close_container(m
);
418 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
421 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
422 return bus_append_string(m
, field
, eq
);
424 if (STR_IN_SET(field
,
425 "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
426 "TasksAccounting", "IPAccounting"))
427 return bus_append_parse_boolean(m
, field
, eq
);
429 if (STR_IN_SET(field
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
430 return bus_append_cg_weight_parse(m
, field
, eq
);
432 if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares"))
433 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
435 if (STR_IN_SET(field
, "AllowedCPUs", "AllowedMemoryNodes")) {
436 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
437 _cleanup_free_
uint8_t *array
= NULL
;
440 r
= parse_cpu_set(eq
, &cpuset
);
442 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
444 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
446 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
448 return bus_append_byte_array(m
, field
, array
, allocated
);
451 if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight"))
452 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
454 if (streq(field
, "DisableControllers"))
455 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
457 if (streq(field
, "Delegate")) {
458 r
= parse_boolean(eq
);
460 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
462 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
464 return bus_log_create_error(r
);
469 if (STR_IN_SET(field
, "MemoryMin",
479 if (isempty(eq
) || streq(eq
, "infinity")) {
480 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
482 return bus_log_create_error(r
);
486 r
= parse_permille(eq
);
490 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
491 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
492 * size can be determined server-side. */
494 n
= strjoina(field
, "Scale");
495 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
497 return bus_log_create_error(r
);
502 if (streq(field
, "TasksMax"))
503 return bus_append_safe_atou64(m
, field
, eq
);
505 return bus_append_parse_size(m
, field
, eq
, 1024);
508 if (streq(field
, "CPUQuota")) {
510 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
512 r
= parse_permille_unbounded(eq
);
514 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
515 "CPU quota too small.");
517 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
519 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
523 return bus_log_create_error(r
);
528 if (streq(field
, "CPUQuotaPeriodSec")) {
529 usec_t u
= USEC_INFINITY
;
531 r
= parse_sec_def_infinity(eq
, &u
);
533 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
535 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
537 return bus_log_create_error(r
);
542 if (streq(field
, "DeviceAllow")) {
544 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
546 const char *path
= eq
, *rwm
= NULL
, *e
;
550 path
= strndupa(eq
, e
- eq
);
554 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
558 return bus_log_create_error(r
);
563 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
565 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
567 const char *path
, *bandwidth
, *e
;
572 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
573 "Failed to parse %s value %s.",
576 path
= strndupa(eq
, e
- eq
);
579 if (streq(bandwidth
, "infinity"))
580 bytes
= CGROUP_LIMIT_MAX
;
582 r
= parse_size(bandwidth
, 1000, &bytes
);
584 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
587 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
591 return bus_log_create_error(r
);
596 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
598 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
600 const char *path
, *weight
, *e
;
605 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
606 "Failed to parse %s value %s.",
609 path
= strndupa(eq
, e
- eq
);
612 r
= safe_atou64(weight
, &u
);
614 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
616 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
620 return bus_log_create_error(r
);
625 if (streq(field
, "IODeviceLatencyTargetSec")) {
626 const char *field_usec
= "IODeviceLatencyTargetUSec";
629 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
631 const char *path
, *target
, *e
;
636 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
637 "Failed to parse %s value %s.",
640 path
= strndupa(eq
, e
- eq
);
643 r
= parse_sec(target
, &usec
);
645 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
647 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
651 return bus_log_create_error(r
);
656 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
657 unsigned char prefixlen
;
658 union in_addr_union prefix
= {};
662 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
664 return bus_log_create_error(r
);
669 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
671 return bus_log_create_error(r
);
673 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
675 return bus_log_create_error(r
);
677 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
679 return bus_log_create_error(r
);
681 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
683 return bus_log_create_error(r
);
685 if (streq(eq
, "any")) {
686 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
688 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
690 return bus_log_create_error(r
);
692 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
694 return bus_log_create_error(r
);
696 } else if (is_localhost(eq
)) {
697 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
699 prefix
.in
.s_addr
= htobe32(0x7f000000);
700 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
702 return bus_log_create_error(r
);
704 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
705 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
709 } else if (streq(eq
, "link-local")) {
710 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
712 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
713 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
715 return bus_log_create_error(r
);
717 prefix
.in6
= (struct in6_addr
) {
718 .s6_addr32
[0] = htobe32(0xfe800000)
720 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
722 return bus_log_create_error(r
);
724 } else if (streq(eq
, "multicast")) {
725 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
727 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
728 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
730 return bus_log_create_error(r
);
732 prefix
.in6
= (struct in6_addr
) {
733 .s6_addr32
[0] = htobe32(0xff000000)
735 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
737 return bus_log_create_error(r
);
741 _cleanup_free_
char *word
= NULL
;
743 r
= extract_first_word(&eq
, &word
, NULL
, 0);
749 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
751 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
753 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
755 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
757 return bus_log_create_error(r
);
761 r
= sd_bus_message_close_container(m
);
763 return bus_log_create_error(r
);
765 r
= sd_bus_message_close_container(m
);
767 return bus_log_create_error(r
);
769 r
= sd_bus_message_close_container(m
);
771 return bus_log_create_error(r
);
776 if (STR_IN_SET(field
, "IPIngressFilterPath", "IPEgressFilterPath")) {
778 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
780 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
783 return bus_log_create_error(r
);
791 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
792 if (streq(field
, "Where"))
793 return bus_append_string(m
, field
, eq
);
795 if (streq(field
, "DirectoryMode"))
796 return bus_append_parse_mode(m
, field
, eq
);
798 if (streq(field
, "TimeoutIdleSec"))
799 return bus_append_parse_sec_rename(m
, field
, eq
);
804 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
808 if (STR_IN_SET(field
,
810 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
811 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
812 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
813 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
814 return bus_append_string(m
, field
, eq
);
816 if (STR_IN_SET(field
,
817 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
818 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
819 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
820 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
821 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
822 "ProtectHostname", "RestrictSUIDSGID"))
823 return bus_append_parse_boolean(m
, field
, eq
);
825 if (STR_IN_SET(field
,
826 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
827 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
828 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
829 "SupplementaryGroups", "SystemCallArchitectures"))
830 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
832 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
833 return bus_append_log_level_from_string(m
, field
, eq
);
835 if (streq(field
, "SyslogFacility"))
836 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
838 if (streq(field
, "SecureBits"))
839 return bus_append_secure_bits_from_string(m
, field
, eq
);
841 if (streq(field
, "CPUSchedulingPolicy"))
842 return bus_append_sched_policy_from_string(m
, field
, eq
);
844 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
845 return bus_append_safe_atoi(m
, field
, eq
);
847 if (streq(field
, "Nice"))
848 return bus_append_parse_nice(m
, field
, eq
);
850 if (streq(field
, "SystemCallErrorNumber"))
851 return bus_append_parse_errno(m
, field
, eq
);
853 if (streq(field
, "IOSchedulingClass"))
854 return bus_append_ioprio_class_from_string(m
, field
, eq
);
856 if (streq(field
, "IOSchedulingPriority"))
857 return bus_append_ioprio_parse_priority(m
, field
, eq
);
859 if (STR_IN_SET(field
,
860 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
861 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
862 return bus_append_parse_mode(m
, field
, eq
);
864 if (streq(field
, "TimerSlackNSec"))
865 return bus_append_parse_nsec(m
, field
, eq
);
867 if (streq(field
, "LogRateLimitIntervalSec"))
868 return bus_append_parse_sec_rename(m
, field
, eq
);
870 if (streq(field
, "LogRateLimitBurst"))
871 return bus_append_safe_atou(m
, field
, eq
);
873 if (streq(field
, "MountFlags"))
874 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
876 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
877 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
879 if (streq(field
, "EnvironmentFile")) {
881 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
883 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
884 eq
[0] == '-' ? eq
+ 1 : eq
,
887 return bus_log_create_error(r
);
892 if (streq(field
, "LogExtraFields")) {
893 r
= sd_bus_message_open_container(m
, 'r', "sv");
895 return bus_log_create_error(r
);
897 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
899 return bus_log_create_error(r
);
901 r
= sd_bus_message_open_container(m
, 'v', "aay");
903 return bus_log_create_error(r
);
905 r
= sd_bus_message_open_container(m
, 'a', "ay");
907 return bus_log_create_error(r
);
909 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
911 return bus_log_create_error(r
);
913 r
= sd_bus_message_close_container(m
);
915 return bus_log_create_error(r
);
917 r
= sd_bus_message_close_container(m
);
919 return bus_log_create_error(r
);
921 r
= sd_bus_message_close_container(m
);
923 return bus_log_create_error(r
);
928 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
929 const char *n
, *appended
;
931 if ((n
= startswith(eq
, "fd:"))) {
932 appended
= strjoina(field
, "FileDescriptorName");
933 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
934 } else if ((n
= startswith(eq
, "file:"))) {
935 appended
= strjoina(field
, "File");
936 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
937 } else if ((n
= startswith(eq
, "append:"))) {
938 appended
= strjoina(field
, "FileToAppend");
939 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
941 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
943 return bus_log_create_error(r
);
948 if (streq(field
, "StandardInputText")) {
949 _cleanup_free_
char *unescaped
= NULL
;
951 r
= cunescape(eq
, 0, &unescaped
);
953 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
955 if (!strextend(&unescaped
, "\n", NULL
))
958 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
959 * interface anyway */
961 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
964 if (streq(field
, "StandardInputData")) {
965 _cleanup_free_
void *decoded
= NULL
;
968 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
970 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
972 return bus_append_byte_array(m
, field
, decoded
, sz
);
975 if ((suffix
= startswith(field
, "Limit"))) {
978 rl
= rlimit_from_string(suffix
);
983 r
= rlimit_parse(rl
, eq
, &l
);
985 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
987 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
989 return bus_log_create_error(r
);
991 sn
= strjoina(field
, "Soft");
992 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
994 return bus_log_create_error(r
);
1000 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
1009 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1011 return bus_log_create_error(r
);
1016 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
1018 bool invert
= false;
1026 r
= capability_set_from_string(p
, &sum
);
1028 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1030 sum
= invert
? ~sum
: sum
;
1032 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1034 return bus_log_create_error(r
);
1039 if (streq(field
, "CPUAffinity")) {
1040 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1041 _cleanup_free_
uint8_t *array
= NULL
;
1044 r
= parse_cpu_set(eq
, &cpuset
);
1046 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1048 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1050 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1052 return bus_append_byte_array(m
, field
, array
, allocated
);
1055 if (streq(field
, "NUMAPolicy")) {
1056 r
= mpol_from_string(eq
);
1058 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1060 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1062 return bus_log_create_error(r
);
1067 if (streq(field
, "NUMAMask")) {
1068 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1069 _cleanup_free_
uint8_t *array
= NULL
;
1072 r
= parse_cpu_set(eq
, &nodes
);
1074 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1076 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1078 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1080 return bus_append_byte_array(m
, field
, array
, allocated
);
1083 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
1092 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1094 return bus_log_create_error(r
);
1096 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1098 return bus_log_create_error(r
);
1100 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1102 return bus_log_create_error(r
);
1104 r
= sd_bus_message_open_container(m
, 'r', "bas");
1106 return bus_log_create_error(r
);
1108 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
1110 return bus_log_create_error(r
);
1112 r
= sd_bus_message_open_container(m
, 'a', "s");
1114 return bus_log_create_error(r
);
1117 _cleanup_free_
char *word
= NULL
;
1119 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1125 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1127 r
= sd_bus_message_append_basic(m
, 's', word
);
1129 return bus_log_create_error(r
);
1132 r
= sd_bus_message_close_container(m
);
1134 return bus_log_create_error(r
);
1136 r
= sd_bus_message_close_container(m
);
1138 return bus_log_create_error(r
);
1140 r
= sd_bus_message_close_container(m
);
1142 return bus_log_create_error(r
);
1144 r
= sd_bus_message_close_container(m
);
1146 return bus_log_create_error(r
);
1151 if (streq(field
, "RestrictNamespaces")) {
1152 bool invert
= false;
1153 unsigned long flags
;
1155 r
= parse_boolean(eq
);
1159 flags
= NAMESPACE_FLAGS_ALL
;
1166 r
= namespace_flags_from_string(eq
, &flags
);
1168 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1172 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1174 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1176 return bus_log_create_error(r
);
1181 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1184 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1186 return bus_log_create_error(r
);
1188 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1190 return bus_log_create_error(r
);
1192 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1194 return bus_log_create_error(r
);
1196 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1198 return bus_log_create_error(r
);
1201 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1202 char *s
= NULL
, *d
= NULL
;
1203 bool ignore_enoent
= false;
1204 uint64_t flags
= MS_REC
;
1206 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1208 return log_error_errno(r
, "Failed to parse argument: %m");
1214 ignore_enoent
= true;
1218 if (p
&& p
[-1] == ':') {
1219 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1221 return log_error_errno(r
, "Failed to parse argument: %m");
1223 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1224 "Missing argument after ':': %s",
1229 if (p
&& p
[-1] == ':') {
1230 _cleanup_free_
char *options
= NULL
;
1232 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1234 return log_error_errno(r
, "Failed to parse argument: %m");
1236 if (isempty(options
) || streq(options
, "rbind"))
1238 else if (streq(options
, "norbind"))
1241 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1242 "Unknown options: %s",
1248 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1250 return bus_log_create_error(r
);
1253 r
= sd_bus_message_close_container(m
);
1255 return bus_log_create_error(r
);
1257 r
= sd_bus_message_close_container(m
);
1259 return bus_log_create_error(r
);
1261 r
= sd_bus_message_close_container(m
);
1263 return bus_log_create_error(r
);
1268 if (streq(field
, "TemporaryFileSystem")) {
1271 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1273 return bus_log_create_error(r
);
1275 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1277 return bus_log_create_error(r
);
1279 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1281 return bus_log_create_error(r
);
1283 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1285 return bus_log_create_error(r
);
1288 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1291 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1293 return log_error_errno(r
, "Failed to parse argument: %m");
1298 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1300 return log_error_errno(r
, "Failed to parse argument: %m");
1302 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1303 "Failed to parse argument: %s",
1306 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1308 return bus_log_create_error(r
);
1311 r
= sd_bus_message_close_container(m
);
1313 return bus_log_create_error(r
);
1315 r
= sd_bus_message_close_container(m
);
1317 return bus_log_create_error(r
);
1319 r
= sd_bus_message_close_container(m
);
1321 return bus_log_create_error(r
);
1329 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1330 if (streq(field
, "KillMode"))
1331 return bus_append_string(m
, field
, eq
);
1333 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1334 return bus_append_parse_boolean(m
, field
, eq
);
1336 if (STR_IN_SET(field
, "KillSignal", "RestartKillSignal", "FinalKillSignal", "WatchdogSignal"))
1337 return bus_append_signal_from_string(m
, field
, eq
);
1342 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1344 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1345 return bus_append_string(m
, field
, eq
);
1347 if (streq(field
, "TimeoutSec"))
1348 return bus_append_parse_sec_rename(m
, field
, eq
);
1350 if (streq(field
, "DirectoryMode"))
1351 return bus_append_parse_mode(m
, field
, eq
);
1353 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1354 return bus_append_parse_boolean(m
, field
, eq
);
1359 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1362 if (streq(field
, "MakeDirectory"))
1363 return bus_append_parse_boolean(m
, field
, eq
);
1365 if (streq(field
, "DirectoryMode"))
1366 return bus_append_parse_mode(m
, field
, eq
);
1368 if (STR_IN_SET(field
,
1369 "PathExists", "PathExistsGlob", "PathChanged",
1370 "PathModified", "DirectoryNotEmpty")) {
1372 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1374 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1376 return bus_log_create_error(r
);
1384 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1385 if (streq(field
, "RuntimeMaxSec"))
1387 return bus_append_parse_sec_rename(m
, field
, eq
);
1389 if (streq(field
, "TimeoutStopSec"))
1391 return bus_append_parse_sec_rename(m
, field
, eq
);
1396 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1399 if (STR_IN_SET(field
,
1400 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1401 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
1402 return bus_append_string(m
, field
, eq
);
1404 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1405 return bus_append_parse_boolean(m
, field
, eq
);
1407 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1408 return bus_append_parse_sec_rename(m
, field
, eq
);
1410 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"))
1419 return bus_append_safe_atou(m
, field
, eq
);
1421 if (STR_IN_SET(field
,
1422 "ExecCondition", "ExecStartPre", "ExecStart", "ExecStartPost",
1423 "ExecConditionEx", "ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
1424 "ExecReload", "ExecStop", "ExecStopPost",
1425 "ExecReloadEx", "ExecStopEx", "ExecStopPostEx"))
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 n_status
= 0, n_signal
= 0;
1434 _cleanup_free_
char *word
= NULL
;
1436 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1442 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1444 /* We need to call exit_status_from_string() first, because we want
1445 * to parse numbers as exit statuses, not signals. */
1447 r
= exit_status_from_string(word
);
1449 assert(r
>= 0 && r
< 256);
1451 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
1455 status
[n_status
++] = r
;
1457 } else if ((r
= signal_from_string(word
)) >= 0) {
1458 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
1462 signal
[n_signal
++] = r
;
1465 /* original r from exit_status_to_string() */
1466 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
1470 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1472 return bus_log_create_error(r
);
1474 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1476 return bus_log_create_error(r
);
1478 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1480 return bus_log_create_error(r
);
1482 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1484 return bus_log_create_error(r
);
1486 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
1488 return bus_log_create_error(r
);
1490 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
1492 return bus_log_create_error(r
);
1494 r
= sd_bus_message_close_container(m
);
1496 return bus_log_create_error(r
);
1498 r
= sd_bus_message_close_container(m
);
1500 return bus_log_create_error(r
);
1502 r
= sd_bus_message_close_container(m
);
1504 return bus_log_create_error(r
);
1512 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1515 if (STR_IN_SET(field
,
1516 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1517 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1518 return bus_append_parse_boolean(m
, field
, eq
);
1520 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1521 return bus_append_safe_atoi(m
, field
, eq
);
1523 if (streq(field
, "IPTOS"))
1524 return bus_append_ip_tos_from_string(m
, field
, eq
);
1526 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1527 return bus_append_safe_atou(m
, field
, eq
);
1529 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1530 return bus_append_parse_mode(m
, field
, eq
);
1532 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1533 return bus_append_safe_atoi64(m
, field
, eq
);
1535 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1536 return bus_append_parse_sec_rename(m
, field
, eq
);
1538 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1539 return bus_append_parse_size(m
, field
, eq
, 1024);
1541 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1542 return bus_append_exec_command(m
, field
, eq
);
1544 if (STR_IN_SET(field
,
1545 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1546 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1547 "SocketUser", "SocketGroup"))
1548 return bus_append_string(m
, field
, eq
);
1550 if (streq(field
, "Symlinks"))
1551 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1553 if (streq(field
, "SocketProtocol"))
1554 return bus_append_parse_ip_protocol(m
, field
, eq
);
1556 if (STR_IN_SET(field
,
1557 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1558 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1560 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1562 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1564 return bus_log_create_error(r
);
1571 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1574 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent",
1575 "OnTimezoneChange", "OnClockChange"))
1576 return bus_append_parse_boolean(m
, field
, eq
);
1578 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1579 return bus_append_parse_sec_rename(m
, field
, eq
);
1581 if (STR_IN_SET(field
,
1582 "OnActiveSec", "OnBootSec", "OnStartupSec",
1583 "OnUnitActiveSec","OnUnitInactiveSec")) {
1585 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1588 r
= parse_sec(eq
, &t
);
1590 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1592 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1595 return bus_log_create_error(r
);
1600 if (streq(field
, "OnCalendar")) {
1602 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1604 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1606 return bus_log_create_error(r
);
1614 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1615 ConditionType t
= _CONDITION_TYPE_INVALID
;
1616 bool is_condition
= false;
1619 if (STR_IN_SET(field
,
1620 "Description", "SourcePath", "OnFailureJobMode",
1621 "JobTimeoutAction", "JobTimeoutRebootArgument",
1622 "StartLimitAction", "FailureAction", "SuccessAction",
1623 "RebootArgument", "CollectMode"))
1624 return bus_append_string(m
, field
, eq
);
1626 if (STR_IN_SET(field
,
1627 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1628 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1629 return bus_append_parse_boolean(m
, field
, eq
);
1631 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1632 return bus_append_parse_sec_rename(m
, field
, eq
);
1634 if (streq(field
, "StartLimitBurst"))
1635 return bus_append_safe_atou(m
, field
, eq
);
1637 if (STR_IN_SET(field
, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1639 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1643 r
= safe_atou8(eq
, &u
);
1645 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1647 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1650 return bus_log_create_error(r
);
1655 if (unit_dependency_from_string(field
) >= 0 ||
1656 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1657 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1659 t
= condition_type_from_string(field
);
1661 is_condition
= true;
1663 t
= assert_type_from_string(field
);
1666 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1669 int trigger
, negate
;
1671 trigger
= *p
== '|';
1679 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1680 field
, trigger
, negate
, p
);
1683 return bus_log_create_error(r
);
1691 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1692 const char *eq
, *field
;
1698 eq
= strchr(assignment
, '=');
1700 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1701 "Not an assignment: %s", assignment
);
1703 field
= strndupa(assignment
, eq
- assignment
);
1708 r
= bus_append_cgroup_property(m
, field
, eq
);
1712 r
= bus_append_execute_property(m
, field
, eq
);
1716 r
= bus_append_kill_property(m
, field
, eq
);
1720 r
= bus_append_service_property(m
, field
, eq
);
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_socket_property(m
, field
, eq
);
1744 r
= bus_append_timer_property(m
, field
, eq
);
1750 r
= bus_append_path_property(m
, field
, eq
);
1756 r
= bus_append_cgroup_property(m
, field
, eq
);
1762 r
= bus_append_cgroup_property(m
, field
, eq
);
1766 r
= bus_append_kill_property(m
, field
, eq
);
1770 r
= bus_append_scope_property(m
, field
, eq
);
1776 r
= bus_append_cgroup_property(m
, field
, eq
);
1780 r
= bus_append_execute_property(m
, field
, eq
);
1784 r
= bus_append_kill_property(m
, field
, eq
);
1788 r
= bus_append_mount_property(m
, field
, eq
);
1794 case UNIT_AUTOMOUNT
:
1795 r
= bus_append_automount_property(m
, field
, eq
);
1804 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1805 "Not supported unit type");
1808 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1809 "Invalid unit type");
1812 r
= bus_append_unit_property(m
, field
, eq
);
1816 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1817 "Unknown assignment: %s", assignment
);
1820 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1826 STRV_FOREACH(i
, l
) {
1827 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1835 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
1836 const char *type
, *path
, *source
;
1839 /* changes is dereferenced when calling unit_file_dump_changes() later,
1840 * so we have to make sure this is not NULL. */
1844 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1846 return bus_log_parse_error(r
);
1848 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1849 /* We expect only "success" changes to be sent over the bus.
1850 Hence, reject anything negative. */
1851 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1854 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1858 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1863 return bus_log_parse_error(r
);
1865 r
= sd_bus_message_exit_container(m
);
1867 return bus_log_parse_error(r
);
1869 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
1873 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
1874 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1875 _cleanup_free_
char *path
= NULL
;
1878 path
= unit_dbus_path_from_name(name
);
1882 /* This function warns on it's own, because otherwise it'd be awkward to pass
1883 * the dbus error message around. */
1885 r
= sd_bus_get_property_string(
1887 "org.freedesktop.systemd1",
1889 "org.freedesktop.systemd1.Unit",
1894 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));