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 "exit-status.h"
14 #include "hexdecoct.h"
15 #include "hostname-util.h"
16 #include "in-addr-util.h"
17 #include "ip-protocol-list.h"
18 #include "locale-util.h"
20 #include "missing_fs.h"
21 #include "mountpoint-util.h"
23 #include "parse-util.h"
24 #include "process-util.h"
25 #include "rlimit-util.h"
26 #include "securebits-util.h"
27 #include "signal-util.h"
28 #include "socket-util.h"
29 #include "sort-util.h"
30 #include "string-util.h"
31 #include "syslog-util.h"
32 #include "terminal-util.h"
34 #include "user-util.h"
37 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
43 return sd_bus_message_read(
58 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
59 static int bus_append_##parse_func( \
66 r = parse_func(eq, &val); \
68 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
70 r = sd_bus_message_append(m, "(sv)", field, \
71 bus_type, (cast_type) val); \
73 return bus_log_create_error(r); \
78 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
79 static int bus_append_##parse_func( \
87 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
89 r = sd_bus_message_append(m, "(sv)", field, \
90 bus_type, (int32_t) r); \
92 return bus_log_create_error(r); \
97 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
98 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
99 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
100 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
101 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
102 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
103 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
104 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
105 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
106 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
107 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
108 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
109 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
110 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
111 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
112 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
113 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
114 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
115 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
116 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
117 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
118 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
120 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
123 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
125 return bus_log_create_error(r
);
130 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
134 r
= sd_bus_message_open_container(m
, 'r', "sv");
136 return bus_log_create_error(r
);
138 r
= sd_bus_message_append_basic(m
, 's', field
);
140 return bus_log_create_error(r
);
142 r
= sd_bus_message_open_container(m
, 'v', "as");
144 return bus_log_create_error(r
);
146 r
= sd_bus_message_open_container(m
, 'a', "s");
148 return bus_log_create_error(r
);
151 _cleanup_free_
char *word
= NULL
;
153 r
= extract_first_word(&p
, &word
, NULL
, flags
);
159 return log_error_errno(r
, "Invalid syntax: %s", eq
);
161 r
= sd_bus_message_append_basic(m
, 's', word
);
163 return bus_log_create_error(r
);
166 r
= sd_bus_message_close_container(m
);
168 return bus_log_create_error(r
);
170 r
= sd_bus_message_close_container(m
);
172 return bus_log_create_error(r
);
174 r
= sd_bus_message_close_container(m
);
176 return bus_log_create_error(r
);
181 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
184 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
186 return bus_log_create_error(r
);
188 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
190 return bus_log_create_error(r
);
192 r
= sd_bus_message_open_container(m
, 'v', "ay");
194 return bus_log_create_error(r
);
196 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
198 return bus_log_create_error(r
);
200 r
= sd_bus_message_close_container(m
);
202 return bus_log_create_error(r
);
204 r
= sd_bus_message_close_container(m
);
206 return bus_log_create_error(r
);
211 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
217 r
= parse_sec(eq
, &t
);
219 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
222 n
= newa(char, l
+ 2);
223 /* Change suffix Sec → USec */
224 strcpy(mempcpy(n
, field
, l
- 3), "USec");
226 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
228 return bus_log_create_error(r
);
233 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
237 r
= parse_size(eq
, base
, &v
);
239 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
241 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
243 return bus_log_create_error(r
);
248 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
249 bool explicit_path
= false, done
= false;
250 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
251 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
252 ExecCommandFlags flags
= 0;
253 bool is_ex_prop
= endswith(field
, "Ex");
260 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
263 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
272 explicit_path
= true;
278 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
281 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
287 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
290 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
296 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
298 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
299 flags
&= ~EXEC_COMMAND_NO_SETUID
;
300 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
303 flags
|= EXEC_COMMAND_NO_SETUID
;
314 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
315 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
317 upgraded_name
= strjoin(field
, "Ex");
323 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
325 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
329 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
331 return log_error_errno(r
, "Failed to parse path: %m");
334 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
336 return log_error_errno(r
, "Failed to parse command line: %m");
338 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
340 return bus_log_create_error(r
);
342 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
344 return bus_log_create_error(r
);
346 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
348 return bus_log_create_error(r
);
350 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
352 return bus_log_create_error(r
);
354 if (!strv_isempty(l
)) {
356 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
358 return bus_log_create_error(r
);
360 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
362 return bus_log_create_error(r
);
364 r
= sd_bus_message_append_strv(m
, l
);
366 return bus_log_create_error(r
);
368 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
));
370 return bus_log_create_error(r
);
372 r
= sd_bus_message_close_container(m
);
374 return bus_log_create_error(r
);
377 r
= sd_bus_message_close_container(m
);
379 return bus_log_create_error(r
);
381 r
= sd_bus_message_close_container(m
);
383 return bus_log_create_error(r
);
385 r
= sd_bus_message_close_container(m
);
387 return bus_log_create_error(r
);
392 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
398 r
= sd_bus_message_open_container(m
, 'r', "iayu");
402 r
= sd_bus_message_append(m
, "i", family
);
406 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
410 r
= sd_bus_message_append(m
, "u", prefixlen
);
414 return sd_bus_message_close_container(m
);
417 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
420 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"))
428 return bus_append_parse_boolean(m
, field
, eq
);
430 if (STR_IN_SET(field
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
432 return bus_append_cg_weight_parse(m
, field
, eq
);
434 if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares"))
436 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
438 if (STR_IN_SET(field
, "AllowedCPUs", "AllowedMemoryNodes")) {
439 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
440 _cleanup_free_
uint8_t *array
= NULL
;
443 r
= parse_cpu_set(eq
, &cpuset
);
445 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
447 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
449 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
451 return bus_append_byte_array(m
, field
, array
, allocated
);
454 if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight"))
456 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
458 if (streq(field
, "DisableControllers"))
460 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
462 if (streq(field
, "Delegate")) {
464 r
= parse_boolean(eq
);
466 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
468 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
470 return bus_log_create_error(r
);
475 if (STR_IN_SET(field
, "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
477 if (isempty(eq
) || streq(eq
, "infinity")) {
478 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
480 return bus_log_create_error(r
);
484 r
= parse_permille(eq
);
488 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
489 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
490 * size can be determined server-side. */
492 n
= strjoina(field
, "Scale");
493 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
495 return bus_log_create_error(r
);
500 if (streq(field
, "TasksMax"))
501 return bus_append_safe_atou64(m
, field
, eq
);
503 return bus_append_parse_size(m
, field
, eq
, 1024);
506 if (streq(field
, "CPUQuota")) {
509 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
511 r
= parse_permille_unbounded(eq
);
513 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
514 "CPU quota too small.");
516 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
518 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
522 return bus_log_create_error(r
);
527 if (streq(field
, "CPUQuotaPeriodSec")) {
528 usec_t u
= USEC_INFINITY
;
530 r
= parse_sec_def_infinity(eq
, &u
);
532 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
534 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
536 return bus_log_create_error(r
);
541 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")) {
566 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
568 const char *path
, *bandwidth
, *e
;
573 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
574 "Failed to parse %s value %s.",
577 path
= strndupa(eq
, e
- eq
);
580 if (streq(bandwidth
, "infinity"))
581 bytes
= CGROUP_LIMIT_MAX
;
583 r
= parse_size(bandwidth
, 1000, &bytes
);
585 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
588 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
592 return bus_log_create_error(r
);
597 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
600 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
602 const char *path
, *weight
, *e
;
607 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
608 "Failed to parse %s value %s.",
611 path
= strndupa(eq
, e
- eq
);
614 r
= safe_atou64(weight
, &u
);
616 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
618 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
622 return bus_log_create_error(r
);
627 if (streq(field
, "IODeviceLatencyTargetSec")) {
628 const char *field_usec
= "IODeviceLatencyTargetUSec";
631 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
633 const char *path
, *target
, *e
;
638 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
639 "Failed to parse %s value %s.",
642 path
= strndupa(eq
, e
- eq
);
645 r
= parse_sec(target
, &usec
);
647 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
649 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
653 return bus_log_create_error(r
);
658 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
659 unsigned char prefixlen
;
660 union in_addr_union prefix
= {};
664 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
666 return bus_log_create_error(r
);
671 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
673 return bus_log_create_error(r
);
675 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
677 return bus_log_create_error(r
);
679 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
681 return bus_log_create_error(r
);
683 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
685 return bus_log_create_error(r
);
687 if (streq(eq
, "any")) {
688 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
690 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
692 return bus_log_create_error(r
);
694 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
696 return bus_log_create_error(r
);
698 } else if (is_localhost(eq
)) {
699 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
701 prefix
.in
.s_addr
= htobe32(0x7f000000);
702 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
704 return bus_log_create_error(r
);
706 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
707 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
711 } else if (streq(eq
, "link-local")) {
712 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
714 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
715 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
717 return bus_log_create_error(r
);
719 prefix
.in6
= (struct in6_addr
) {
720 .s6_addr32
[0] = htobe32(0xfe800000)
722 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
724 return bus_log_create_error(r
);
726 } else if (streq(eq
, "multicast")) {
727 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
729 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
730 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
732 return bus_log_create_error(r
);
734 prefix
.in6
= (struct in6_addr
) {
735 .s6_addr32
[0] = htobe32(0xff000000)
737 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
739 return bus_log_create_error(r
);
743 _cleanup_free_
char *word
= NULL
;
745 r
= extract_first_word(&eq
, &word
, NULL
, 0);
751 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
753 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
755 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
757 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
759 return bus_log_create_error(r
);
763 r
= sd_bus_message_close_container(m
);
765 return bus_log_create_error(r
);
767 r
= sd_bus_message_close_container(m
);
769 return bus_log_create_error(r
);
771 r
= sd_bus_message_close_container(m
);
773 return bus_log_create_error(r
);
778 if (STR_IN_SET(field
, "IPIngressFilterPath", "IPEgressFilterPath")) {
780 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
782 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
785 return bus_log_create_error(r
);
793 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
795 if (streq(field
, "Where"))
797 return bus_append_string(m
, field
, eq
);
799 if (streq(field
, "DirectoryMode"))
801 return bus_append_parse_mode(m
, field
, eq
);
803 if (streq(field
, "TimeoutIdleSec"))
805 return bus_append_parse_sec_rename(m
, field
, eq
);
810 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
814 if (STR_IN_SET(field
,
816 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
817 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
818 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
819 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
821 return bus_append_string(m
, field
, eq
);
823 if (STR_IN_SET(field
,
824 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
825 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
826 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
827 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
828 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
829 "ProtectHostname", "RestrictSUIDSGID"))
831 return bus_append_parse_boolean(m
, field
, eq
);
833 if (STR_IN_SET(field
,
834 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
835 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
836 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
837 "SupplementaryGroups", "SystemCallArchitectures"))
839 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
841 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
843 return bus_append_log_level_from_string(m
, field
, eq
);
845 if (streq(field
, "SyslogFacility"))
847 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
849 if (streq(field
, "SecureBits"))
851 return bus_append_secure_bits_from_string(m
, field
, eq
);
853 if (streq(field
, "CPUSchedulingPolicy"))
855 return bus_append_sched_policy_from_string(m
, field
, eq
);
857 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
859 return bus_append_safe_atoi(m
, field
, eq
);
861 if (streq(field
, "Nice"))
863 return bus_append_parse_nice(m
, field
, eq
);
865 if (streq(field
, "SystemCallErrorNumber"))
867 return bus_append_parse_errno(m
, field
, eq
);
869 if (streq(field
, "IOSchedulingClass"))
871 return bus_append_ioprio_class_from_string(m
, field
, eq
);
873 if (streq(field
, "IOSchedulingPriority"))
875 return bus_append_ioprio_parse_priority(m
, field
, eq
);
877 if (STR_IN_SET(field
,
878 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
879 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
881 return bus_append_parse_mode(m
, field
, eq
);
883 if (streq(field
, "TimerSlackNSec"))
885 return bus_append_parse_nsec(m
, field
, eq
);
887 if (streq(field
, "LogRateLimitIntervalSec"))
889 return bus_append_parse_sec_rename(m
, field
, eq
);
891 if (streq(field
, "LogRateLimitBurst"))
893 return bus_append_safe_atou(m
, field
, eq
);
895 if (streq(field
, "MountFlags"))
897 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
899 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
901 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
903 if (streq(field
, "EnvironmentFile")) {
906 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
908 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
909 eq
[0] == '-' ? eq
+ 1 : eq
,
912 return bus_log_create_error(r
);
917 if (streq(field
, "LogExtraFields")) {
919 r
= sd_bus_message_open_container(m
, 'r', "sv");
921 return bus_log_create_error(r
);
923 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
925 return bus_log_create_error(r
);
927 r
= sd_bus_message_open_container(m
, 'v', "aay");
929 return bus_log_create_error(r
);
931 r
= sd_bus_message_open_container(m
, 'a', "ay");
933 return bus_log_create_error(r
);
935 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
937 return bus_log_create_error(r
);
939 r
= sd_bus_message_close_container(m
);
941 return bus_log_create_error(r
);
943 r
= sd_bus_message_close_container(m
);
945 return bus_log_create_error(r
);
947 r
= sd_bus_message_close_container(m
);
949 return bus_log_create_error(r
);
954 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
955 const char *n
, *appended
;
957 if ((n
= startswith(eq
, "fd:"))) {
958 appended
= strjoina(field
, "FileDescriptorName");
959 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
960 } else if ((n
= startswith(eq
, "file:"))) {
961 appended
= strjoina(field
, "File");
962 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
963 } else if ((n
= startswith(eq
, "append:"))) {
964 appended
= strjoina(field
, "FileToAppend");
965 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
967 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
969 return bus_log_create_error(r
);
974 if (streq(field
, "StandardInputText")) {
975 _cleanup_free_
char *unescaped
= NULL
;
977 r
= cunescape(eq
, 0, &unescaped
);
979 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
981 if (!strextend(&unescaped
, "\n", NULL
))
984 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
985 * interface anyway */
987 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
990 if (streq(field
, "StandardInputData")) {
991 _cleanup_free_
void *decoded
= NULL
;
994 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
996 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
998 return bus_append_byte_array(m
, field
, decoded
, sz
);
1001 if ((suffix
= startswith(field
, "Limit"))) {
1004 rl
= rlimit_from_string(suffix
);
1009 r
= rlimit_parse(rl
, eq
, &l
);
1011 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1013 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
1015 return bus_log_create_error(r
);
1017 sn
= strjoina(field
, "Soft");
1018 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1020 return bus_log_create_error(r
);
1026 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
1035 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1037 return bus_log_create_error(r
);
1042 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
1044 bool invert
= false;
1052 r
= capability_set_from_string(p
, &sum
);
1054 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1056 sum
= invert
? ~sum
: sum
;
1058 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1060 return bus_log_create_error(r
);
1065 if (streq(field
, "CPUAffinity")) {
1066 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1067 _cleanup_free_
uint8_t *array
= NULL
;
1070 r
= parse_cpu_set(eq
, &cpuset
);
1072 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1074 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1076 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1078 return bus_append_byte_array(m
, field
, array
, allocated
);
1081 if (streq(field
, "NUMAPolicy")) {
1082 r
= mpol_from_string(eq
);
1084 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1086 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1088 return bus_log_create_error(r
);
1093 if (streq(field
, "NUMAMask")) {
1094 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1095 _cleanup_free_
uint8_t *array
= NULL
;
1098 r
= parse_cpu_set(eq
, &nodes
);
1100 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1102 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1104 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1106 return bus_append_byte_array(m
, field
, array
, allocated
);
1109 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
1118 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1120 return bus_log_create_error(r
);
1122 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1124 return bus_log_create_error(r
);
1126 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1128 return bus_log_create_error(r
);
1130 r
= sd_bus_message_open_container(m
, 'r', "bas");
1132 return bus_log_create_error(r
);
1134 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
1136 return bus_log_create_error(r
);
1138 r
= sd_bus_message_open_container(m
, 'a', "s");
1140 return bus_log_create_error(r
);
1143 _cleanup_free_
char *word
= NULL
;
1145 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1151 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1153 r
= sd_bus_message_append_basic(m
, 's', word
);
1155 return bus_log_create_error(r
);
1158 r
= sd_bus_message_close_container(m
);
1160 return bus_log_create_error(r
);
1162 r
= sd_bus_message_close_container(m
);
1164 return bus_log_create_error(r
);
1166 r
= sd_bus_message_close_container(m
);
1168 return bus_log_create_error(r
);
1170 r
= sd_bus_message_close_container(m
);
1172 return bus_log_create_error(r
);
1177 if (streq(field
, "RestrictNamespaces")) {
1178 bool invert
= false;
1179 unsigned long flags
;
1181 r
= parse_boolean(eq
);
1185 flags
= NAMESPACE_FLAGS_ALL
;
1192 r
= namespace_flags_from_string(eq
, &flags
);
1194 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1198 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1200 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1202 return bus_log_create_error(r
);
1207 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1210 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1212 return bus_log_create_error(r
);
1214 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1216 return bus_log_create_error(r
);
1218 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1220 return bus_log_create_error(r
);
1222 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1224 return bus_log_create_error(r
);
1227 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1228 char *s
= NULL
, *d
= NULL
;
1229 bool ignore_enoent
= false;
1230 uint64_t flags
= MS_REC
;
1232 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1234 return log_error_errno(r
, "Failed to parse argument: %m");
1240 ignore_enoent
= true;
1244 if (p
&& p
[-1] == ':') {
1245 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1247 return log_error_errno(r
, "Failed to parse argument: %m");
1249 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1250 "Missing argument after ':': %s",
1255 if (p
&& p
[-1] == ':') {
1256 _cleanup_free_
char *options
= NULL
;
1258 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1260 return log_error_errno(r
, "Failed to parse argument: %m");
1262 if (isempty(options
) || streq(options
, "rbind"))
1264 else if (streq(options
, "norbind"))
1267 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1268 "Unknown options: %s",
1274 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1276 return bus_log_create_error(r
);
1279 r
= sd_bus_message_close_container(m
);
1281 return bus_log_create_error(r
);
1283 r
= sd_bus_message_close_container(m
);
1285 return bus_log_create_error(r
);
1287 r
= sd_bus_message_close_container(m
);
1289 return bus_log_create_error(r
);
1294 if (streq(field
, "TemporaryFileSystem")) {
1297 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1299 return bus_log_create_error(r
);
1301 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1303 return bus_log_create_error(r
);
1305 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1307 return bus_log_create_error(r
);
1309 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1311 return bus_log_create_error(r
);
1314 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1317 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1319 return log_error_errno(r
, "Failed to parse argument: %m");
1324 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1326 return log_error_errno(r
, "Failed to parse argument: %m");
1328 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1329 "Failed to parse argument: %s",
1332 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1334 return bus_log_create_error(r
);
1337 r
= sd_bus_message_close_container(m
);
1339 return bus_log_create_error(r
);
1341 r
= sd_bus_message_close_container(m
);
1343 return bus_log_create_error(r
);
1345 r
= sd_bus_message_close_container(m
);
1347 return bus_log_create_error(r
);
1355 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1357 if (streq(field
, "KillMode"))
1359 return bus_append_string(m
, field
, eq
);
1361 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1363 return bus_append_parse_boolean(m
, field
, eq
);
1365 if (STR_IN_SET(field
, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1367 return bus_append_signal_from_string(m
, field
, eq
);
1372 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1374 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1376 return bus_append_string(m
, field
, eq
);
1378 if (streq(field
, "TimeoutSec"))
1380 return bus_append_parse_sec_rename(m
, field
, eq
);
1382 if (streq(field
, "DirectoryMode"))
1384 return bus_append_parse_mode(m
, field
, eq
);
1386 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1388 return bus_append_parse_boolean(m
, field
, eq
);
1393 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1396 if (streq(field
, "MakeDirectory"))
1398 return bus_append_parse_boolean(m
, field
, eq
);
1400 if (streq(field
, "DirectoryMode"))
1402 return bus_append_parse_mode(m
, field
, eq
);
1404 if (STR_IN_SET(field
,
1405 "PathExists", "PathExistsGlob", "PathChanged",
1406 "PathModified", "DirectoryNotEmpty")) {
1409 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1411 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1413 return bus_log_create_error(r
);
1421 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1424 if (STR_IN_SET(field
,
1425 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1426 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
1428 return bus_append_string(m
, field
, eq
);
1430 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1432 return bus_append_parse_boolean(m
, field
, eq
);
1434 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1436 return bus_append_parse_sec_rename(m
, field
, eq
);
1438 if (streq(field
, "TimeoutSec")) {
1440 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1444 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1447 if (streq(field
, "FileDescriptorStoreMax"))
1449 return bus_append_safe_atou(m
, field
, eq
);
1451 if (STR_IN_SET(field
,
1452 "ExecCondition", "ExecStartPre", "ExecStart", "ExecStartPost",
1453 "ExecConditionEx", "ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
1454 "ExecReload", "ExecStop", "ExecStopPost",
1455 "ExecReloadEx", "ExecStopEx", "ExecStopPostEx"))
1456 return bus_append_exec_command(m
, field
, eq
);
1458 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1459 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1460 size_t n_status
= 0, n_signal
= 0;
1464 _cleanup_free_
char *word
= NULL
;
1466 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1472 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1474 /* We need to call exit_status_from_string() first, because we want
1475 * to parse numbers as exit statuses, not signals. */
1477 r
= exit_status_from_string(word
);
1479 assert(r
>= 0 && r
< 256);
1481 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
1485 status
[n_status
++] = r
;
1487 } else if ((r
= signal_from_string(word
)) >= 0) {
1488 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
1492 signal
[n_signal
++] = r
;
1495 /* original r from exit_status_to_string() */
1496 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
1500 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1502 return bus_log_create_error(r
);
1504 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1506 return bus_log_create_error(r
);
1508 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1510 return bus_log_create_error(r
);
1512 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1514 return bus_log_create_error(r
);
1516 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
1518 return bus_log_create_error(r
);
1520 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
1522 return bus_log_create_error(r
);
1524 r
= sd_bus_message_close_container(m
);
1526 return bus_log_create_error(r
);
1528 r
= sd_bus_message_close_container(m
);
1530 return bus_log_create_error(r
);
1532 r
= sd_bus_message_close_container(m
);
1534 return bus_log_create_error(r
);
1542 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1545 if (STR_IN_SET(field
,
1546 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1547 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1549 return bus_append_parse_boolean(m
, field
, eq
);
1551 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1553 return bus_append_safe_atoi(m
, field
, eq
);
1555 if (streq(field
, "IPTOS"))
1557 return bus_append_ip_tos_from_string(m
, field
, eq
);
1559 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1561 return bus_append_safe_atou(m
, field
, eq
);
1563 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1565 return bus_append_parse_mode(m
, field
, eq
);
1567 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1569 return bus_append_safe_atoi64(m
, field
, eq
);
1571 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1573 return bus_append_parse_sec_rename(m
, field
, eq
);
1575 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1577 return bus_append_parse_size(m
, field
, eq
, 1024);
1579 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1581 return bus_append_exec_command(m
, field
, eq
);
1583 if (STR_IN_SET(field
,
1584 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1585 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1586 "SocketUser", "SocketGroup"))
1588 return bus_append_string(m
, field
, eq
);
1590 if (streq(field
, "Symlinks"))
1592 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1594 if (streq(field
, "SocketProtocol"))
1596 return bus_append_parse_ip_protocol(m
, field
, eq
);
1598 if (STR_IN_SET(field
,
1599 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1600 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1603 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1605 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1607 return bus_log_create_error(r
);
1614 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1617 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent",
1618 "OnTimezoneChange", "OnClockChange"))
1620 return bus_append_parse_boolean(m
, field
, eq
);
1622 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1624 return bus_append_parse_sec_rename(m
, field
, eq
);
1626 if (STR_IN_SET(field
,
1627 "OnActiveSec", "OnBootSec", "OnStartupSec",
1628 "OnUnitActiveSec","OnUnitInactiveSec")) {
1631 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1634 r
= parse_sec(eq
, &t
);
1636 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1638 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1641 return bus_log_create_error(r
);
1646 if (streq(field
, "OnCalendar")) {
1649 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1651 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1653 return bus_log_create_error(r
);
1661 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1662 ConditionType t
= _CONDITION_TYPE_INVALID
;
1663 bool is_condition
= false;
1666 if (STR_IN_SET(field
,
1667 "Description", "SourcePath", "OnFailureJobMode",
1668 "JobTimeoutAction", "JobTimeoutRebootArgument",
1669 "StartLimitAction", "FailureAction", "SuccessAction",
1670 "RebootArgument", "CollectMode"))
1672 return bus_append_string(m
, field
, eq
);
1674 if (STR_IN_SET(field
,
1675 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1676 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1678 return bus_append_parse_boolean(m
, field
, eq
);
1680 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1682 return bus_append_parse_sec_rename(m
, field
, eq
);
1684 if (streq(field
, "StartLimitBurst"))
1686 return bus_append_safe_atou(m
, field
, eq
);
1688 if (STR_IN_SET(field
, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1691 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1695 r
= safe_atou8(eq
, &u
);
1697 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1699 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1702 return bus_log_create_error(r
);
1707 if (unit_dependency_from_string(field
) >= 0 ||
1708 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1710 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1712 t
= condition_type_from_string(field
);
1714 is_condition
= true;
1716 t
= assert_type_from_string(field
);
1719 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1722 int trigger
, negate
;
1724 trigger
= *p
== '|';
1732 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1733 field
, trigger
, negate
, p
);
1736 return bus_log_create_error(r
);
1744 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1745 const char *eq
, *field
;
1751 eq
= strchr(assignment
, '=');
1753 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1754 "Not an assignment: %s", assignment
);
1756 field
= strndupa(assignment
, eq
- assignment
);
1761 r
= bus_append_cgroup_property(m
, field
, eq
);
1765 r
= bus_append_execute_property(m
, field
, eq
);
1769 r
= bus_append_kill_property(m
, field
, eq
);
1773 r
= bus_append_service_property(m
, field
, eq
);
1779 r
= bus_append_cgroup_property(m
, field
, eq
);
1783 r
= bus_append_execute_property(m
, field
, eq
);
1787 r
= bus_append_kill_property(m
, field
, eq
);
1791 r
= bus_append_socket_property(m
, field
, eq
);
1797 r
= bus_append_timer_property(m
, field
, eq
);
1803 r
= bus_append_path_property(m
, field
, eq
);
1809 r
= bus_append_cgroup_property(m
, field
, eq
);
1816 if (streq(field
, "TimeoutStopSec"))
1817 return bus_append_parse_sec_rename(m
, field
, eq
);
1819 r
= bus_append_cgroup_property(m
, field
, eq
);
1823 r
= bus_append_kill_property(m
, field
, eq
);
1829 r
= bus_append_cgroup_property(m
, field
, eq
);
1833 r
= bus_append_execute_property(m
, field
, eq
);
1837 r
= bus_append_kill_property(m
, field
, eq
);
1841 r
= bus_append_mount_property(m
, field
, eq
);
1847 case UNIT_AUTOMOUNT
:
1848 r
= bus_append_automount_property(m
, field
, eq
);
1857 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1858 "Not supported unit type");
1861 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1862 "Invalid unit type");
1865 r
= bus_append_unit_property(m
, field
, eq
);
1869 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1870 "Unknown assignment: %s", assignment
);
1873 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1879 STRV_FOREACH(i
, l
) {
1880 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1888 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
1889 const char *type
, *path
, *source
;
1892 /* changes is dereferenced when calling unit_file_dump_changes() later,
1893 * so we have to make sure this is not NULL. */
1897 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1899 return bus_log_parse_error(r
);
1901 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1902 /* We expect only "success" changes to be sent over the bus.
1903 Hence, reject anything negative. */
1904 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1907 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1911 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1916 return bus_log_parse_error(r
);
1918 r
= sd_bus_message_exit_container(m
);
1920 return bus_log_parse_error(r
);
1922 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
1926 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
1927 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1928 _cleanup_free_
char *path
= NULL
;
1931 path
= unit_dbus_path_from_name(name
);
1935 /* This function warns on it's own, because otherwise it'd be awkward to pass
1936 * the dbus error message around. */
1938 r
= sd_bus_get_property_string(
1940 "org.freedesktop.systemd1",
1942 "org.freedesktop.systemd1.Unit",
1947 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));