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 "coredump-util.h"
12 #include "cpu-set-util.h"
14 #include "exec-util.h"
15 #include "exit-status.h"
17 #include "hexdecoct.h"
18 #include "hostname-util.h"
19 #include "in-addr-util.h"
20 #include "ip-protocol-list.h"
21 #include "locale-util.h"
23 #include "missing_fs.h"
24 #include "mountpoint-util.h"
26 #include "numa-util.h"
27 #include "parse-util.h"
28 #include "path-util.h"
29 #include "process-util.h"
30 #include "rlimit-util.h"
31 #include "securebits-util.h"
32 #include "signal-util.h"
33 #include "socket-util.h"
34 #include "sort-util.h"
35 #include "stdio-util.h"
36 #include "string-util.h"
37 #include "syslog-util.h"
38 #include "terminal-util.h"
40 #include "user-util.h"
43 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
49 return sd_bus_message_read(
64 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
65 static int bus_append_##parse_func( \
72 r = parse_func(eq, &val); \
74 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
76 r = sd_bus_message_append(m, "(sv)", field, \
77 bus_type, (cast_type) val); \
79 return bus_log_create_error(r); \
84 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
85 static int bus_append_##parse_func( \
93 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
95 r = sd_bus_message_append(m, "(sv)", field, \
96 bus_type, (int32_t) r); \
98 return bus_log_create_error(r); \
103 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
104 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
105 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
106 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
107 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
108 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
109 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
110 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
111 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
112 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
113 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
114 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
115 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
116 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
117 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
118 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
119 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
120 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
121 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
122 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
123 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
124 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
125 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
127 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
130 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
132 return bus_log_create_error(r
);
137 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
141 r
= sd_bus_message_open_container(m
, 'r', "sv");
143 return bus_log_create_error(r
);
145 r
= sd_bus_message_append_basic(m
, 's', field
);
147 return bus_log_create_error(r
);
149 r
= sd_bus_message_open_container(m
, 'v', "as");
151 return bus_log_create_error(r
);
153 r
= sd_bus_message_open_container(m
, 'a', "s");
155 return bus_log_create_error(r
);
158 _cleanup_free_
char *word
= NULL
;
160 r
= extract_first_word(&p
, &word
, NULL
, flags
);
166 return log_error_errno(r
, "Invalid syntax: %s", eq
);
168 r
= sd_bus_message_append_basic(m
, 's', word
);
170 return bus_log_create_error(r
);
173 r
= sd_bus_message_close_container(m
);
175 return bus_log_create_error(r
);
177 r
= sd_bus_message_close_container(m
);
179 return bus_log_create_error(r
);
181 r
= sd_bus_message_close_container(m
);
183 return bus_log_create_error(r
);
188 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
191 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
193 return bus_log_create_error(r
);
195 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
197 return bus_log_create_error(r
);
199 r
= sd_bus_message_open_container(m
, 'v', "ay");
201 return bus_log_create_error(r
);
203 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
205 return bus_log_create_error(r
);
207 r
= sd_bus_message_close_container(m
);
209 return bus_log_create_error(r
);
211 r
= sd_bus_message_close_container(m
);
213 return bus_log_create_error(r
);
218 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
224 r
= parse_sec(eq
, &t
);
226 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
229 n
= newa(char, l
+ 2);
230 /* Change suffix Sec → USec */
231 strcpy(mempcpy(n
, field
, l
- 3), "USec");
233 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
235 return bus_log_create_error(r
);
240 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
244 r
= parse_size(eq
, base
, &v
);
246 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
248 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
250 return bus_log_create_error(r
);
255 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
256 bool explicit_path
= false, done
= false;
257 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
258 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
259 ExecCommandFlags flags
= 0;
260 bool is_ex_prop
= endswith(field
, "Ex");
267 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
270 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
279 explicit_path
= true;
285 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
288 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
294 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
297 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
303 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
305 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
306 flags
&= ~EXEC_COMMAND_NO_SETUID
;
307 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
310 flags
|= EXEC_COMMAND_NO_SETUID
;
321 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
322 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
324 upgraded_name
= strjoin(field
, "Ex");
330 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
332 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
336 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
338 return log_error_errno(r
, "Failed to parse path: %m");
341 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
343 return log_error_errno(r
, "Failed to parse command line: %m");
345 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
347 return bus_log_create_error(r
);
349 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
351 return bus_log_create_error(r
);
353 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
355 return bus_log_create_error(r
);
357 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
359 return bus_log_create_error(r
);
361 if (!strv_isempty(l
)) {
363 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
365 return bus_log_create_error(r
);
367 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
369 return bus_log_create_error(r
);
371 r
= sd_bus_message_append_strv(m
, l
);
373 return bus_log_create_error(r
);
375 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
));
377 return bus_log_create_error(r
);
379 r
= sd_bus_message_close_container(m
);
381 return bus_log_create_error(r
);
384 r
= sd_bus_message_close_container(m
);
386 return bus_log_create_error(r
);
388 r
= sd_bus_message_close_container(m
);
390 return bus_log_create_error(r
);
392 r
= sd_bus_message_close_container(m
);
394 return bus_log_create_error(r
);
399 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
405 r
= sd_bus_message_open_container(m
, 'r', "iayu");
409 r
= sd_bus_message_append(m
, "i", family
);
413 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
417 r
= sd_bus_message_append(m
, "u", prefixlen
);
421 return sd_bus_message_close_container(m
);
424 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
427 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
428 return bus_append_string(m
, field
, eq
);
430 if (STR_IN_SET(field
, "CPUAccounting",
436 return bus_append_parse_boolean(m
, field
, eq
);
438 if (STR_IN_SET(field
, "CPUWeight",
442 return bus_append_cg_weight_parse(m
, field
, eq
);
444 if (STR_IN_SET(field
, "CPUShares",
446 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
448 if (STR_IN_SET(field
, "AllowedCPUs",
449 "AllowedMemoryNodes")) {
450 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
451 _cleanup_free_
uint8_t *array
= NULL
;
454 r
= parse_cpu_set(eq
, &cpuset
);
456 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
458 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
460 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
462 return bus_append_byte_array(m
, field
, array
, allocated
);
465 if (STR_IN_SET(field
, "BlockIOWeight",
466 "StartupBlockIOWeight"))
467 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
469 if (streq(field
, "DisableControllers"))
470 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
472 if (streq(field
, "Delegate")) {
473 r
= parse_boolean(eq
);
475 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
477 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
479 return bus_log_create_error(r
);
484 if (STR_IN_SET(field
, "MemoryMin",
494 if (streq(eq
, "infinity")) {
495 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
497 return bus_log_create_error(r
);
499 } else if (isempty(eq
)) {
500 uint64_t empty_value
= STR_IN_SET(field
,
508 r
= sd_bus_message_append(m
, "(sv)", field
, "t", empty_value
);
510 return bus_log_create_error(r
);
514 r
= parse_permille(eq
);
518 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
519 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
520 * size can be determined server-side. */
522 n
= strjoina(field
, "Scale");
523 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
525 return bus_log_create_error(r
);
530 if (streq(field
, "TasksMax"))
531 return bus_append_safe_atou64(m
, field
, eq
);
533 return bus_append_parse_size(m
, field
, eq
, 1024);
536 if (streq(field
, "CPUQuota")) {
538 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
540 r
= parse_permille_unbounded(eq
);
542 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
543 "CPU quota too small.");
545 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
547 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
551 return bus_log_create_error(r
);
556 if (streq(field
, "CPUQuotaPeriodSec")) {
557 usec_t u
= USEC_INFINITY
;
559 r
= parse_sec_def_infinity(eq
, &u
);
561 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
563 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
565 return bus_log_create_error(r
);
570 if (streq(field
, "DeviceAllow")) {
572 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
574 const char *path
= eq
, *rwm
= NULL
, *e
;
578 path
= strndupa(eq
, e
- eq
);
582 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
586 return bus_log_create_error(r
);
591 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
593 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
595 const char *path
, *bandwidth
, *e
;
600 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
601 "Failed to parse %s value %s.",
604 path
= strndupa(eq
, e
- eq
);
607 if (streq(bandwidth
, "infinity"))
608 bytes
= CGROUP_LIMIT_MAX
;
610 r
= parse_size(bandwidth
, 1000, &bytes
);
612 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
615 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
619 return bus_log_create_error(r
);
624 if (STR_IN_SET(field
, "IODeviceWeight",
625 "BlockIODeviceWeight")) {
627 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
629 const char *path
, *weight
, *e
;
634 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
635 "Failed to parse %s value %s.",
638 path
= strndupa(eq
, e
- eq
);
641 r
= safe_atou64(weight
, &u
);
643 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
645 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
649 return bus_log_create_error(r
);
654 if (streq(field
, "IODeviceLatencyTargetSec")) {
655 const char *field_usec
= "IODeviceLatencyTargetUSec";
658 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
660 const char *path
, *target
, *e
;
665 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
666 "Failed to parse %s value %s.",
669 path
= strndupa(eq
, e
- eq
);
672 r
= parse_sec(target
, &usec
);
674 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
676 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
680 return bus_log_create_error(r
);
685 if (STR_IN_SET(field
, "IPAddressAllow",
687 unsigned char prefixlen
;
688 union in_addr_union prefix
= {};
692 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
694 return bus_log_create_error(r
);
699 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
701 return bus_log_create_error(r
);
703 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
705 return bus_log_create_error(r
);
707 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
709 return bus_log_create_error(r
);
711 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
713 return bus_log_create_error(r
);
715 if (streq(eq
, "any")) {
716 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
718 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
720 return bus_log_create_error(r
);
722 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
724 return bus_log_create_error(r
);
726 } else if (is_localhost(eq
)) {
727 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
729 prefix
.in
.s_addr
= htobe32(0x7f000000);
730 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
732 return bus_log_create_error(r
);
734 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
735 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
739 } else if (streq(eq
, "link-local")) {
740 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
742 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
743 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
745 return bus_log_create_error(r
);
747 prefix
.in6
= (struct in6_addr
) {
748 .s6_addr32
[0] = htobe32(0xfe800000)
750 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
752 return bus_log_create_error(r
);
754 } else if (streq(eq
, "multicast")) {
755 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
757 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
758 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
760 return bus_log_create_error(r
);
762 prefix
.in6
= (struct in6_addr
) {
763 .s6_addr32
[0] = htobe32(0xff000000)
765 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
767 return bus_log_create_error(r
);
771 _cleanup_free_
char *word
= NULL
;
773 r
= extract_first_word(&eq
, &word
, NULL
, 0);
779 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
781 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
783 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
785 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
787 return bus_log_create_error(r
);
791 r
= sd_bus_message_close_container(m
);
793 return bus_log_create_error(r
);
795 r
= sd_bus_message_close_container(m
);
797 return bus_log_create_error(r
);
799 r
= sd_bus_message_close_container(m
);
801 return bus_log_create_error(r
);
806 if (STR_IN_SET(field
, "IPIngressFilterPath",
807 "IPEgressFilterPath")) {
809 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
811 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
814 return bus_log_create_error(r
);
822 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
823 if (streq(field
, "Where"))
824 return bus_append_string(m
, field
, eq
);
826 if (streq(field
, "DirectoryMode"))
827 return bus_append_parse_mode(m
, field
, eq
);
829 if (streq(field
, "TimeoutIdleSec"))
830 return bus_append_parse_sec_rename(m
, field
, eq
);
835 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
839 if (STR_IN_SET(field
, "User",
853 "RuntimeDirectoryPreserve",
856 "NetworkNamespacePath",
858 return bus_append_string(m
, field
, eq
);
860 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
871 "MemoryDenyWriteExecute",
875 "ProtectKernelTunables",
876 "ProtectKernelModules",
879 "ProtectControlGroups",
881 "CPUSchedulingResetOnFork",
885 return bus_append_parse_boolean(m
, field
, eq
);
887 if (STR_IN_SET(field
, "ReadWriteDirectories",
888 "ReadOnlyDirectories",
889 "InaccessibleDirectories",
897 "ConfigurationDirectory",
898 "SupplementaryGroups",
899 "SystemCallArchitectures"))
900 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
902 if (STR_IN_SET(field
, "SyslogLevel",
904 return bus_append_log_level_from_string(m
, field
, eq
);
906 if (streq(field
, "SyslogFacility"))
907 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
909 if (streq(field
, "SecureBits"))
910 return bus_append_secure_bits_from_string(m
, field
, eq
);
912 if (streq(field
, "CPUSchedulingPolicy"))
913 return bus_append_sched_policy_from_string(m
, field
, eq
);
915 if (STR_IN_SET(field
, "CPUSchedulingPriority",
917 return bus_append_safe_atoi(m
, field
, eq
);
919 if (streq(field
, "CoredumpFilter"))
920 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
922 if (streq(field
, "Nice"))
923 return bus_append_parse_nice(m
, field
, eq
);
925 if (streq(field
, "SystemCallErrorNumber"))
926 return bus_append_parse_errno(m
, field
, eq
);
928 if (streq(field
, "IOSchedulingClass"))
929 return bus_append_ioprio_class_from_string(m
, field
, eq
);
931 if (streq(field
, "IOSchedulingPriority"))
932 return bus_append_ioprio_parse_priority(m
, field
, eq
);
934 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
935 "StateDirectoryMode",
936 "CacheDirectoryMode",
938 "ConfigurationDirectoryMode",
940 return bus_append_parse_mode(m
, field
, eq
);
942 if (streq(field
, "TimerSlackNSec"))
943 return bus_append_parse_nsec(m
, field
, eq
);
945 if (streq(field
, "LogRateLimitIntervalSec"))
946 return bus_append_parse_sec_rename(m
, field
, eq
);
948 if (streq(field
, "LogRateLimitBurst"))
949 return bus_append_safe_atou(m
, field
, eq
);
951 if (streq(field
, "MountFlags"))
952 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
954 if (STR_IN_SET(field
, "Environment",
957 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
959 if (streq(field
, "EnvironmentFile")) {
961 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
963 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
964 eq
[0] == '-' ? eq
+ 1 : eq
,
967 return bus_log_create_error(r
);
972 if (streq(field
, "LogExtraFields")) {
973 r
= sd_bus_message_open_container(m
, 'r', "sv");
975 return bus_log_create_error(r
);
977 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
979 return bus_log_create_error(r
);
981 r
= sd_bus_message_open_container(m
, 'v', "aay");
983 return bus_log_create_error(r
);
985 r
= sd_bus_message_open_container(m
, 'a', "ay");
987 return bus_log_create_error(r
);
989 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
991 return bus_log_create_error(r
);
993 r
= sd_bus_message_close_container(m
);
995 return bus_log_create_error(r
);
997 r
= sd_bus_message_close_container(m
);
999 return bus_log_create_error(r
);
1001 r
= sd_bus_message_close_container(m
);
1003 return bus_log_create_error(r
);
1008 if (STR_IN_SET(field
, "StandardInput",
1011 const char *n
, *appended
;
1013 if ((n
= startswith(eq
, "fd:"))) {
1014 appended
= strjoina(field
, "FileDescriptorName");
1015 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1016 } else if ((n
= startswith(eq
, "file:"))) {
1017 appended
= strjoina(field
, "File");
1018 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1019 } else if ((n
= startswith(eq
, "append:"))) {
1020 appended
= strjoina(field
, "FileToAppend");
1021 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1023 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1025 return bus_log_create_error(r
);
1030 if (streq(field
, "StandardInputText")) {
1031 _cleanup_free_
char *unescaped
= NULL
;
1033 r
= cunescape(eq
, 0, &unescaped
);
1035 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
1037 if (!strextend(&unescaped
, "\n", NULL
))
1040 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
1041 * interface anyway */
1043 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
1046 if (streq(field
, "StandardInputData")) {
1047 _cleanup_free_
void *decoded
= NULL
;
1050 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
1052 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1054 return bus_append_byte_array(m
, field
, decoded
, sz
);
1057 if ((suffix
= startswith(field
, "Limit"))) {
1060 rl
= rlimit_from_string(suffix
);
1065 r
= rlimit_parse(rl
, eq
, &l
);
1067 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1069 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
1071 return bus_log_create_error(r
);
1073 sn
= strjoina(field
, "Soft");
1074 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1076 return bus_log_create_error(r
);
1082 if (STR_IN_SET(field
, "AppArmorProfile",
1083 "SmackProcessLabel")) {
1092 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1094 return bus_log_create_error(r
);
1099 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1100 "AmbientCapabilities")) {
1102 bool invert
= false;
1110 r
= capability_set_from_string(p
, &sum
);
1112 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1114 sum
= invert
? ~sum
: sum
;
1116 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1118 return bus_log_create_error(r
);
1123 if (streq(field
, "CPUAffinity")) {
1124 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1125 _cleanup_free_
uint8_t *array
= NULL
;
1128 if (eq
&& streq(eq
, "numa")) {
1129 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1131 return bus_log_create_error(r
);
1135 r
= parse_cpu_set(eq
, &cpuset
);
1137 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1139 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1141 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1143 return bus_append_byte_array(m
, field
, array
, allocated
);
1146 if (streq(field
, "NUMAPolicy")) {
1147 r
= mpol_from_string(eq
);
1149 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1151 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1153 return bus_log_create_error(r
);
1158 if (streq(field
, "NUMAMask")) {
1159 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1160 _cleanup_free_
uint8_t *array
= NULL
;
1163 r
= parse_cpu_set(eq
, &nodes
);
1165 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1167 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1169 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1171 return bus_append_byte_array(m
, field
, array
, allocated
);
1174 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1175 "SystemCallFilter")) {
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', "(bas)");
1194 return bus_log_create_error(r
);
1196 r
= sd_bus_message_open_container(m
, 'r', "bas");
1198 return bus_log_create_error(r
);
1200 r
= sd_bus_message_append_basic(m
, 'b', &allow_list
);
1202 return bus_log_create_error(r
);
1204 r
= sd_bus_message_open_container(m
, 'a', "s");
1206 return bus_log_create_error(r
);
1209 _cleanup_free_
char *word
= NULL
;
1211 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1217 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1219 r
= sd_bus_message_append_basic(m
, 's', word
);
1221 return bus_log_create_error(r
);
1224 r
= sd_bus_message_close_container(m
);
1226 return bus_log_create_error(r
);
1228 r
= sd_bus_message_close_container(m
);
1230 return bus_log_create_error(r
);
1232 r
= sd_bus_message_close_container(m
);
1234 return bus_log_create_error(r
);
1236 r
= sd_bus_message_close_container(m
);
1238 return bus_log_create_error(r
);
1243 if (streq(field
, "RestrictNamespaces")) {
1244 bool invert
= false;
1245 unsigned long flags
;
1247 r
= parse_boolean(eq
);
1251 flags
= NAMESPACE_FLAGS_ALL
;
1258 r
= namespace_flags_from_string(eq
, &flags
);
1260 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1264 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1266 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1268 return bus_log_create_error(r
);
1273 if (STR_IN_SET(field
, "BindPaths",
1274 "BindReadOnlyPaths")) {
1277 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1279 return bus_log_create_error(r
);
1281 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1283 return bus_log_create_error(r
);
1285 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1287 return bus_log_create_error(r
);
1289 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1291 return bus_log_create_error(r
);
1294 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1295 char *s
= NULL
, *d
= NULL
;
1296 bool ignore_enoent
= false;
1297 uint64_t flags
= MS_REC
;
1299 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1301 return log_error_errno(r
, "Failed to parse argument: %m");
1307 ignore_enoent
= true;
1311 if (p
&& p
[-1] == ':') {
1312 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1314 return log_error_errno(r
, "Failed to parse argument: %m");
1316 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1317 "Missing argument after ':': %s",
1322 if (p
&& p
[-1] == ':') {
1323 _cleanup_free_
char *options
= NULL
;
1325 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1327 return log_error_errno(r
, "Failed to parse argument: %m");
1329 if (isempty(options
) || streq(options
, "rbind"))
1331 else if (streq(options
, "norbind"))
1334 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1335 "Unknown options: %s",
1341 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1343 return bus_log_create_error(r
);
1346 r
= sd_bus_message_close_container(m
);
1348 return bus_log_create_error(r
);
1350 r
= sd_bus_message_close_container(m
);
1352 return bus_log_create_error(r
);
1354 r
= sd_bus_message_close_container(m
);
1356 return bus_log_create_error(r
);
1361 if (streq(field
, "TemporaryFileSystem")) {
1364 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1366 return bus_log_create_error(r
);
1368 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1370 return bus_log_create_error(r
);
1372 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1374 return bus_log_create_error(r
);
1376 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1378 return bus_log_create_error(r
);
1381 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1384 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1386 return log_error_errno(r
, "Failed to parse argument: %m");
1391 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1393 return log_error_errno(r
, "Failed to parse argument: %m");
1395 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1396 "Failed to parse argument: %s",
1399 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1401 return bus_log_create_error(r
);
1404 r
= sd_bus_message_close_container(m
);
1406 return bus_log_create_error(r
);
1408 r
= sd_bus_message_close_container(m
);
1410 return bus_log_create_error(r
);
1412 r
= sd_bus_message_close_container(m
);
1414 return bus_log_create_error(r
);
1419 if (streq(field
, "RootHash")) {
1420 _cleanup_free_
void *roothash_decoded
= NULL
;
1421 size_t roothash_decoded_size
= 0;
1423 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1424 if (path_is_absolute(eq
))
1425 return bus_append_string(m
, "RootHashPath", eq
);
1427 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1428 r
= unhexmem(eq
, strlen(eq
), &roothash_decoded
, &roothash_decoded_size
);
1430 return log_error_errno(r
, "Failed to decode RootHash= '%s': %m", eq
);
1431 if (roothash_decoded_size
< sizeof(sd_id128_t
))
1432 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "RootHash= '%s' is too short: %m", eq
);
1434 return bus_append_byte_array(m
, field
, roothash_decoded
, roothash_decoded_size
);
1437 if (streq(field
, "RootHashSignature")) {
1438 _cleanup_free_
void *roothash_sig_decoded
= NULL
;
1440 size_t roothash_sig_decoded_size
= 0;
1442 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1443 if (path_is_absolute(eq
))
1444 return bus_append_string(m
, "RootHashSignaturePath", eq
);
1446 if (!(value
= startswith(eq
, "base64:")))
1447 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq
);
1449 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1450 r
= unbase64mem(value
, strlen(value
), &roothash_sig_decoded
, &roothash_sig_decoded_size
);
1452 return log_error_errno(r
, "Failed to decode RootHashSignature= '%s': %m", eq
);
1454 return bus_append_byte_array(m
, field
, roothash_sig_decoded
, roothash_sig_decoded_size
);
1457 if (streq(field
, "RootImageOptions")) {
1460 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1462 return bus_log_create_error(r
);
1464 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1466 return bus_log_create_error(r
);
1468 r
= sd_bus_message_open_container(m
, 'v', "a(us)");
1470 return bus_log_create_error(r
);
1472 r
= sd_bus_message_open_container(m
, 'a', "(us)");
1474 return bus_log_create_error(r
);
1477 _cleanup_free_
char *first
= NULL
, *tuple
= NULL
;
1478 const char *mount_options
= NULL
, *second
= NULL
;
1479 unsigned partition_number
= 0;
1481 r
= extract_first_word(&p
, &tuple
, WHITESPACE
, EXTRACT_UNQUOTE
);
1485 return log_error_errno(r
, "Failed to parse argument: %m");
1488 r
= extract_first_word(&second
, &first
, ":", EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1492 return log_error_errno(r
, "Failed to parse argument: %m");
1494 /* Format is either '0:foo' or 'foo' (0 is implied) */
1495 if (!isempty(second
) && second
[-1] == ':') {
1496 mount_options
= second
;
1497 r
= safe_atou(first
, &partition_number
);
1499 log_error_errno(r
, "Failed to parse partition number from %s: %m", first
);
1503 mount_options
= first
;
1505 r
= sd_bus_message_append(m
, "(us)", partition_number
, mount_options
);
1507 return bus_log_create_error(r
);
1510 r
= sd_bus_message_close_container(m
);
1512 return bus_log_create_error(r
);
1514 r
= sd_bus_message_close_container(m
);
1516 return bus_log_create_error(r
);
1518 r
= sd_bus_message_close_container(m
);
1520 return bus_log_create_error(r
);
1528 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1529 if (streq(field
, "KillMode"))
1530 return bus_append_string(m
, field
, eq
);
1532 if (STR_IN_SET(field
, "SendSIGHUP",
1534 return bus_append_parse_boolean(m
, field
, eq
);
1536 if (STR_IN_SET(field
, "KillSignal",
1537 "RestartKillSignal",
1540 return bus_append_signal_from_string(m
, field
, eq
);
1545 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1547 if (STR_IN_SET(field
, "What",
1551 return bus_append_string(m
, field
, eq
);
1553 if (streq(field
, "TimeoutSec"))
1554 return bus_append_parse_sec_rename(m
, field
, eq
);
1556 if (streq(field
, "DirectoryMode"))
1557 return bus_append_parse_mode(m
, field
, eq
);
1559 if (STR_IN_SET(field
, "SloppyOptions",
1563 return bus_append_parse_boolean(m
, field
, eq
);
1568 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1571 if (streq(field
, "MakeDirectory"))
1572 return bus_append_parse_boolean(m
, field
, eq
);
1574 if (streq(field
, "DirectoryMode"))
1575 return bus_append_parse_mode(m
, field
, eq
);
1577 if (STR_IN_SET(field
, "PathExists",
1581 "DirectoryNotEmpty")) {
1583 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1585 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1587 return bus_log_create_error(r
);
1595 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1596 if (streq(field
, "RuntimeMaxSec"))
1597 return bus_append_parse_sec_rename(m
, field
, eq
);
1599 if (streq(field
, "TimeoutStopSec"))
1600 return bus_append_parse_sec_rename(m
, field
, eq
);
1605 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1608 if (STR_IN_SET(field
, "PIDFile",
1613 "USBFunctionDescriptors",
1614 "USBFunctionStrings",
1616 "TimeoutStartFailureMode",
1617 "TimeoutStopFailureMode"))
1618 return bus_append_string(m
, field
, eq
);
1620 if (STR_IN_SET(field
, "PermissionsStartOnly",
1621 "RootDirectoryStartOnly",
1624 return bus_append_parse_boolean(m
, field
, eq
);
1626 if (STR_IN_SET(field
, "RestartSec",
1632 return bus_append_parse_sec_rename(m
, field
, eq
);
1634 if (streq(field
, "TimeoutSec")) {
1635 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1639 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1642 if (streq(field
, "FileDescriptorStoreMax"))
1643 return bus_append_safe_atou(m
, field
, eq
);
1645 if (STR_IN_SET(field
, "ExecCondition",
1659 return bus_append_exec_command(m
, field
, eq
);
1661 if (STR_IN_SET(field
, "RestartPreventExitStatus",
1662 "RestartForceExitStatus",
1663 "SuccessExitStatus")) {
1664 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1665 size_t n_status
= 0, n_signal
= 0;
1669 _cleanup_free_
char *word
= NULL
;
1671 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1677 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1679 /* We need to call exit_status_from_string() first, because we want
1680 * to parse numbers as exit statuses, not signals. */
1682 r
= exit_status_from_string(word
);
1684 assert(r
>= 0 && r
< 256);
1686 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
1690 status
[n_status
++] = r
;
1692 } else if ((r
= signal_from_string(word
)) >= 0) {
1693 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
1697 signal
[n_signal
++] = r
;
1700 /* original r from exit_status_to_string() */
1701 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
1705 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1707 return bus_log_create_error(r
);
1709 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1711 return bus_log_create_error(r
);
1713 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1715 return bus_log_create_error(r
);
1717 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1719 return bus_log_create_error(r
);
1721 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
1723 return bus_log_create_error(r
);
1725 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
1727 return bus_log_create_error(r
);
1729 r
= sd_bus_message_close_container(m
);
1731 return bus_log_create_error(r
);
1733 r
= sd_bus_message_close_container(m
);
1735 return bus_log_create_error(r
);
1737 r
= sd_bus_message_close_container(m
);
1739 return bus_log_create_error(r
);
1747 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1750 if (STR_IN_SET(field
, "Accept",
1762 "SELinuxContextFromNet"))
1763 return bus_append_parse_boolean(m
, field
, eq
);
1765 if (STR_IN_SET(field
, "Priority",
1768 return bus_append_safe_atoi(m
, field
, eq
);
1770 if (streq(field
, "IPTOS"))
1771 return bus_append_ip_tos_from_string(m
, field
, eq
);
1773 if (STR_IN_SET(field
, "Backlog",
1775 "MaxConnectionsPerSource",
1777 "TriggerLimitBurst"))
1778 return bus_append_safe_atou(m
, field
, eq
);
1780 if (STR_IN_SET(field
, "SocketMode",
1782 return bus_append_parse_mode(m
, field
, eq
);
1784 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
1785 "MessageQueueMessageSize"))
1786 return bus_append_safe_atoi64(m
, field
, eq
);
1788 if (STR_IN_SET(field
, "TimeoutSec",
1790 "KeepAliveIntervalSec",
1792 "TriggerLimitIntervalSec"))
1793 return bus_append_parse_sec_rename(m
, field
, eq
);
1795 if (STR_IN_SET(field
, "ReceiveBuffer",
1798 return bus_append_parse_size(m
, field
, eq
, 1024);
1800 if (STR_IN_SET(field
, "ExecStartPre",
1804 return bus_append_exec_command(m
, field
, eq
);
1806 if (STR_IN_SET(field
, "SmackLabel",
1812 "FileDescriptorName",
1815 return bus_append_string(m
, field
, eq
);
1817 if (streq(field
, "Symlinks"))
1818 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1820 if (streq(field
, "SocketProtocol"))
1821 return bus_append_parse_ip_protocol(m
, field
, eq
);
1823 if (STR_IN_SET(field
, "ListenStream",
1825 "ListenSequentialPacket",
1828 "ListenMessageQueue",
1830 "ListenUSBFunction")) {
1832 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1834 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1836 return bus_log_create_error(r
);
1843 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1846 if (STR_IN_SET(field
, "WakeSystem",
1847 "RemainAfterElapse",
1851 return bus_append_parse_boolean(m
, field
, eq
);
1853 if (STR_IN_SET(field
, "AccuracySec",
1854 "RandomizedDelaySec"))
1855 return bus_append_parse_sec_rename(m
, field
, eq
);
1857 if (STR_IN_SET(field
, "OnActiveSec",
1861 "OnUnitInactiveSec")) {
1863 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1866 r
= parse_sec(eq
, &t
);
1868 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1870 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1873 return bus_log_create_error(r
);
1878 if (streq(field
, "OnCalendar")) {
1880 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1882 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1884 return bus_log_create_error(r
);
1892 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1893 ConditionType t
= _CONDITION_TYPE_INVALID
;
1894 bool is_condition
= false;
1897 if (STR_IN_SET(field
, "Description",
1901 "JobTimeoutRebootArgument",
1907 return bus_append_string(m
, field
, eq
);
1909 if (STR_IN_SET(field
, "StopWhenUnneeded",
1910 "RefuseManualStart",
1914 "DefaultDependencies"))
1915 return bus_append_parse_boolean(m
, field
, eq
);
1917 if (STR_IN_SET(field
, "JobTimeoutSec",
1918 "JobRunningTimeoutSec",
1919 "StartLimitIntervalSec"))
1920 return bus_append_parse_sec_rename(m
, field
, eq
);
1922 if (streq(field
, "StartLimitBurst"))
1923 return bus_append_safe_atou(m
, field
, eq
);
1925 if (STR_IN_SET(field
, "SuccessActionExitStatus",
1926 "FailureActionExitStatus")) {
1928 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1932 r
= safe_atou8(eq
, &u
);
1934 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1936 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1939 return bus_log_create_error(r
);
1944 if (unit_dependency_from_string(field
) >= 0 ||
1945 STR_IN_SET(field
, "Documentation",
1946 "RequiresMountsFor"))
1947 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1949 t
= condition_type_from_string(field
);
1951 is_condition
= true;
1953 t
= assert_type_from_string(field
);
1956 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1959 int trigger
, negate
;
1961 trigger
= *p
== '|';
1969 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1970 field
, trigger
, negate
, p
);
1973 return bus_log_create_error(r
);
1981 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1982 const char *eq
, *field
;
1988 eq
= strchr(assignment
, '=');
1990 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1991 "Not an assignment: %s", assignment
);
1993 field
= strndupa(assignment
, eq
- assignment
);
1998 r
= bus_append_cgroup_property(m
, field
, eq
);
2002 r
= bus_append_execute_property(m
, field
, eq
);
2006 r
= bus_append_kill_property(m
, field
, eq
);
2010 r
= bus_append_service_property(m
, field
, eq
);
2016 r
= bus_append_cgroup_property(m
, field
, eq
);
2020 r
= bus_append_execute_property(m
, field
, eq
);
2024 r
= bus_append_kill_property(m
, field
, eq
);
2028 r
= bus_append_socket_property(m
, field
, eq
);
2034 r
= bus_append_timer_property(m
, field
, eq
);
2040 r
= bus_append_path_property(m
, field
, eq
);
2046 r
= bus_append_cgroup_property(m
, field
, eq
);
2052 r
= bus_append_cgroup_property(m
, field
, eq
);
2056 r
= bus_append_kill_property(m
, field
, eq
);
2060 r
= bus_append_scope_property(m
, field
, eq
);
2066 r
= bus_append_cgroup_property(m
, field
, eq
);
2070 r
= bus_append_execute_property(m
, field
, eq
);
2074 r
= bus_append_kill_property(m
, field
, eq
);
2078 r
= bus_append_mount_property(m
, field
, eq
);
2084 case UNIT_AUTOMOUNT
:
2085 r
= bus_append_automount_property(m
, field
, eq
);
2094 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2095 "Not supported unit type");
2098 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2099 "Invalid unit type");
2102 r
= bus_append_unit_property(m
, field
, eq
);
2106 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2107 "Unknown assignment: %s", assignment
);
2110 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
2116 STRV_FOREACH(i
, l
) {
2117 r
= bus_append_unit_property_assignment(m
, t
, *i
);
2125 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
2126 const char *type
, *path
, *source
;
2129 /* changes is dereferenced when calling unit_file_dump_changes() later,
2130 * so we have to make sure this is not NULL. */
2134 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2136 return bus_log_parse_error(r
);
2138 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2139 /* We expect only "success" changes to be sent over the bus.
2140 Hence, reject anything negative. */
2141 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
2144 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
2148 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2153 return bus_log_parse_error(r
);
2155 r
= sd_bus_message_exit_container(m
);
2157 return bus_log_parse_error(r
);
2159 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2163 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2164 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2165 _cleanup_free_
char *path
= NULL
;
2168 path
= unit_dbus_path_from_name(name
);
2172 /* This function warns on it's own, because otherwise it'd be awkward to pass
2173 * the dbus error message around. */
2175 r
= sd_bus_get_property_string(
2177 "org.freedesktop.systemd1",
2179 "org.freedesktop.systemd1.Unit",
2184 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));