1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "alloc-util.h"
6 #include "bus-unit-util.h"
9 #include "cgroup-setup.h"
10 #include "cgroup-util.h"
11 #include "condition.h"
12 #include "coredump-util.h"
13 #include "cpu-set-util.h"
14 #include "dissect-image.h"
16 #include "exec-util.h"
17 #include "exit-status.h"
19 #include "hexdecoct.h"
20 #include "hostname-util.h"
21 #include "in-addr-util.h"
22 #include "ip-protocol-list.h"
23 #include "libmount-util.h"
24 #include "locale-util.h"
26 #include "missing_fs.h"
27 #include "mountpoint-util.h"
29 #include "numa-util.h"
30 #include "parse-socket-bind-item.h"
31 #include "parse-util.h"
32 #include "path-util.h"
33 #include "percent-util.h"
34 #include "process-util.h"
35 #include "rlimit-util.h"
37 #include "seccomp-util.h"
39 #include "securebits-util.h"
40 #include "signal-util.h"
41 #include "socket-util.h"
42 #include "sort-util.h"
43 #include "stdio-util.h"
44 #include "string-util.h"
45 #include "syslog-util.h"
46 #include "terminal-util.h"
48 #include "user-util.h"
51 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
57 return sd_bus_message_read(
72 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
73 static int bus_append_##parse_func( \
80 r = parse_func(eq, &val); \
82 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
84 r = sd_bus_message_append(m, "(sv)", field, \
85 bus_type, (cast_type) val); \
87 return bus_log_create_error(r); \
92 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
93 static int bus_append_##parse_func( \
101 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
103 r = sd_bus_message_append(m, "(sv)", field, \
104 bus_type, (int32_t) r); \
106 return bus_log_create_error(r); \
111 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
112 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
113 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
114 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
115 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
117 static inline int seccomp_parse_errno_or_action(const char *eq
) { return -EINVAL
; }
119 DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action
);
120 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
121 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
122 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
123 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
124 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
125 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
126 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
127 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
128 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
129 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
130 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
131 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
132 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
133 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
134 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
135 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
136 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
138 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
141 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
143 return bus_log_create_error(r
);
148 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
152 r
= sd_bus_message_open_container(m
, 'r', "sv");
154 return bus_log_create_error(r
);
156 r
= sd_bus_message_append_basic(m
, 's', field
);
158 return bus_log_create_error(r
);
160 r
= sd_bus_message_open_container(m
, 'v', "as");
162 return bus_log_create_error(r
);
164 r
= sd_bus_message_open_container(m
, 'a', "s");
166 return bus_log_create_error(r
);
169 _cleanup_free_
char *word
= NULL
;
171 r
= extract_first_word(&p
, &word
, NULL
, flags
);
177 return log_error_errno(r
, "Invalid syntax: %s", eq
);
179 r
= sd_bus_message_append_basic(m
, 's', word
);
181 return bus_log_create_error(r
);
184 r
= sd_bus_message_close_container(m
);
186 return bus_log_create_error(r
);
188 r
= sd_bus_message_close_container(m
);
190 return bus_log_create_error(r
);
192 r
= sd_bus_message_close_container(m
);
194 return bus_log_create_error(r
);
199 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
202 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
204 return bus_log_create_error(r
);
206 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
208 return bus_log_create_error(r
);
210 r
= sd_bus_message_open_container(m
, 'v', "ay");
212 return bus_log_create_error(r
);
214 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
216 return bus_log_create_error(r
);
218 r
= sd_bus_message_close_container(m
);
220 return bus_log_create_error(r
);
222 r
= sd_bus_message_close_container(m
);
224 return bus_log_create_error(r
);
229 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
235 r
= parse_sec(eq
, &t
);
237 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
240 n
= newa(char, l
+ 2);
241 /* Change suffix Sec → USec */
242 strcpy(mempcpy(n
, field
, l
- 3), "USec");
244 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
246 return bus_log_create_error(r
);
251 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
255 r
= parse_size(eq
, base
, &v
);
257 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
259 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
261 return bus_log_create_error(r
);
266 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
267 bool explicit_path
= false, done
= false;
268 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
269 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
270 ExecCommandFlags flags
= 0;
271 bool is_ex_prop
= endswith(field
, "Ex");
278 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
281 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
290 explicit_path
= true;
296 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
299 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
305 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
308 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
314 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
316 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
317 flags
&= ~EXEC_COMMAND_NO_SETUID
;
318 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
321 flags
|= EXEC_COMMAND_NO_SETUID
;
332 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
333 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
335 upgraded_name
= strjoin(field
, "Ex");
341 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
343 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
347 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
349 return log_error_errno(r
, "Failed to parse path: %m");
352 r
= strv_split_full(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
354 return log_error_errno(r
, "Failed to parse command line: %m");
356 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
358 return bus_log_create_error(r
);
360 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
362 return bus_log_create_error(r
);
364 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
366 return bus_log_create_error(r
);
368 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
370 return bus_log_create_error(r
);
372 if (!strv_isempty(l
)) {
374 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
376 return bus_log_create_error(r
);
378 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
380 return bus_log_create_error(r
);
382 r
= sd_bus_message_append_strv(m
, l
);
384 return bus_log_create_error(r
);
386 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
));
388 return bus_log_create_error(r
);
390 r
= sd_bus_message_close_container(m
);
392 return bus_log_create_error(r
);
395 r
= sd_bus_message_close_container(m
);
397 return bus_log_create_error(r
);
399 r
= sd_bus_message_close_container(m
);
401 return bus_log_create_error(r
);
403 r
= sd_bus_message_close_container(m
);
405 return bus_log_create_error(r
);
410 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
416 r
= sd_bus_message_open_container(m
, 'r', "iayu");
420 r
= sd_bus_message_append(m
, "i", family
);
424 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
428 r
= sd_bus_message_append(m
, "u", prefixlen
);
432 return sd_bus_message_close_container(m
);
435 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
438 if (STR_IN_SET(field
, "DevicePolicy",
441 "ManagedOOMMemoryPressure",
442 "ManagedOOMPreference"))
443 return bus_append_string(m
, field
, eq
);
445 if (STR_IN_SET(field
, "ManagedOOMMemoryPressureLimit")) {
446 r
= parse_permyriad(eq
);
448 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
450 /* Pass around scaled to 2^32-1 == 100% */
451 r
= sd_bus_message_append(m
, "(sv)", field
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
453 return bus_log_create_error(r
);
458 if (STR_IN_SET(field
, "CPUAccounting",
464 return bus_append_parse_boolean(m
, field
, eq
);
466 if (STR_IN_SET(field
, "CPUWeight",
470 return bus_append_cg_weight_parse(m
, field
, eq
);
472 if (STR_IN_SET(field
, "CPUShares",
474 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
476 if (STR_IN_SET(field
, "AllowedCPUs",
477 "StartupAllowedCPUs",
478 "AllowedMemoryNodes",
479 "StartupAllowedMemoryNodes")) {
480 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
481 _cleanup_free_
uint8_t *array
= NULL
;
484 r
= parse_cpu_set(eq
, &cpuset
);
486 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
488 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
490 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
492 return bus_append_byte_array(m
, field
, array
, allocated
);
495 if (STR_IN_SET(field
, "BlockIOWeight",
496 "StartupBlockIOWeight"))
497 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
499 if (streq(field
, "DisableControllers"))
500 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
502 if (streq(field
, "Delegate")) {
503 r
= parse_boolean(eq
);
505 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
507 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
509 return bus_log_create_error(r
);
514 if (STR_IN_SET(field
, "MemoryMin",
524 if (streq(eq
, "infinity")) {
525 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
527 return bus_log_create_error(r
);
529 } else if (isempty(eq
)) {
530 uint64_t empty_value
= STR_IN_SET(field
,
538 r
= sd_bus_message_append(m
, "(sv)", field
, "t", empty_value
);
540 return bus_log_create_error(r
);
544 r
= parse_permyriad(eq
);
548 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
549 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
550 * size can be determined server-side. */
552 n
= strjoina(field
, "Scale");
553 r
= sd_bus_message_append(m
, "(sv)", n
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
555 return bus_log_create_error(r
);
560 if (streq(field
, "TasksMax"))
561 return bus_append_safe_atou64(m
, field
, eq
);
563 return bus_append_parse_size(m
, field
, eq
, 1024);
566 if (streq(field
, "CPUQuota")) {
568 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
570 r
= parse_permyriad_unbounded(eq
);
572 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
573 "CPU quota too small.");
575 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
577 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 10000U));
581 return bus_log_create_error(r
);
586 if (streq(field
, "CPUQuotaPeriodSec")) {
587 usec_t u
= USEC_INFINITY
;
589 r
= parse_sec_def_infinity(eq
, &u
);
591 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
593 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
595 return bus_log_create_error(r
);
600 if (streq(field
, "DeviceAllow")) {
602 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
604 const char *path
= eq
, *rwm
= NULL
, *e
;
608 path
= strndupa_safe(eq
, e
- eq
);
612 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
616 return bus_log_create_error(r
);
621 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
623 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
625 const char *path
, *bandwidth
, *e
;
630 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
631 "Failed to parse %s value %s.",
634 path
= strndupa_safe(eq
, e
- eq
);
637 if (streq(bandwidth
, "infinity"))
638 bytes
= CGROUP_LIMIT_MAX
;
640 r
= parse_size(bandwidth
, 1000, &bytes
);
642 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
645 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
649 return bus_log_create_error(r
);
654 if (STR_IN_SET(field
, "IODeviceWeight",
655 "BlockIODeviceWeight")) {
657 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
659 const char *path
, *weight
, *e
;
664 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
665 "Failed to parse %s value %s.",
668 path
= strndupa_safe(eq
, e
- eq
);
671 r
= safe_atou64(weight
, &u
);
673 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
675 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
679 return bus_log_create_error(r
);
684 if (streq(field
, "IODeviceLatencyTargetSec")) {
685 const char *field_usec
= "IODeviceLatencyTargetUSec";
688 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
690 const char *path
, *target
, *e
;
695 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
696 "Failed to parse %s value %s.",
699 path
= strndupa_safe(eq
, e
- eq
);
702 r
= parse_sec(target
, &usec
);
704 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
706 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
710 return bus_log_create_error(r
);
715 if (STR_IN_SET(field
, "IPAddressAllow",
717 unsigned char prefixlen
;
718 union in_addr_union prefix
= {};
722 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
724 return bus_log_create_error(r
);
729 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
731 return bus_log_create_error(r
);
733 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
735 return bus_log_create_error(r
);
737 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
739 return bus_log_create_error(r
);
741 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
743 return bus_log_create_error(r
);
745 if (streq(eq
, "any")) {
746 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
748 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
750 return bus_log_create_error(r
);
752 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
754 return bus_log_create_error(r
);
756 } else if (is_localhost(eq
)) {
757 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
759 prefix
.in
.s_addr
= htobe32(0x7f000000);
760 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
762 return bus_log_create_error(r
);
764 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
765 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
769 } else if (streq(eq
, "link-local")) {
770 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
772 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
773 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
775 return bus_log_create_error(r
);
777 prefix
.in6
= (struct in6_addr
) {
778 .s6_addr32
[0] = htobe32(0xfe800000)
780 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
782 return bus_log_create_error(r
);
784 } else if (streq(eq
, "multicast")) {
785 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
787 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
788 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
790 return bus_log_create_error(r
);
792 prefix
.in6
= (struct in6_addr
) {
793 .s6_addr32
[0] = htobe32(0xff000000)
795 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
797 return bus_log_create_error(r
);
801 _cleanup_free_
char *word
= NULL
;
803 r
= extract_first_word(&eq
, &word
, NULL
, 0);
809 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
811 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
813 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
815 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
817 return bus_log_create_error(r
);
821 r
= sd_bus_message_close_container(m
);
823 return bus_log_create_error(r
);
825 r
= sd_bus_message_close_container(m
);
827 return bus_log_create_error(r
);
829 r
= sd_bus_message_close_container(m
);
831 return bus_log_create_error(r
);
836 if (STR_IN_SET(field
, "IPIngressFilterPath",
837 "IPEgressFilterPath")) {
839 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
841 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
844 return bus_log_create_error(r
);
849 if (streq(field
, "BPFProgram")) {
851 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
853 _cleanup_free_
char *word
= NULL
;
855 r
= extract_first_word(&eq
, &word
, ":", 0);
859 return log_error_errno(r
, "Failed to parse %s: %m", field
);
861 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, word
, eq
);
864 return bus_log_create_error(r
);
869 if (STR_IN_SET(field
, "SocketBindAllow",
872 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iiqq)", 0);
874 int32_t family
, ip_protocol
;
875 uint16_t nr_ports
, port_min
;
877 r
= parse_socket_bind_item(eq
, &family
, &ip_protocol
, &nr_ports
, &port_min
);
881 return log_error_errno(r
, "Failed to parse %s", field
);
883 r
= sd_bus_message_append(
884 m
, "(sv)", field
, "a(iiqq)", 1, family
, ip_protocol
, nr_ports
, port_min
);
887 return bus_log_create_error(r
);
895 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
896 if (streq(field
, "Where"))
897 return bus_append_string(m
, field
, eq
);
899 if (streq(field
, "DirectoryMode"))
900 return bus_append_parse_mode(m
, field
, eq
);
902 if (streq(field
, "TimeoutIdleSec"))
903 return bus_append_parse_sec_rename(m
, field
, eq
);
908 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
912 if (STR_IN_SET(field
, "User",
926 "RuntimeDirectoryPreserve",
931 "NetworkNamespacePath",
934 return bus_append_string(m
, field
, eq
);
936 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
948 "MemoryDenyWriteExecute",
952 "ProtectKernelTunables",
953 "ProtectKernelModules",
956 "ProtectControlGroups",
958 "CPUSchedulingResetOnFork",
962 return bus_append_parse_boolean(m
, field
, eq
);
964 if (STR_IN_SET(field
, "ReadWriteDirectories",
965 "ReadOnlyDirectories",
966 "InaccessibleDirectories",
977 "ConfigurationDirectory",
978 "SupplementaryGroups",
979 "SystemCallArchitectures"))
980 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
982 if (STR_IN_SET(field
, "SyslogLevel",
984 return bus_append_log_level_from_string(m
, field
, eq
);
986 if (streq(field
, "SyslogFacility"))
987 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
989 if (streq(field
, "SecureBits"))
990 return bus_append_secure_bits_from_string(m
, field
, eq
);
992 if (streq(field
, "CPUSchedulingPolicy"))
993 return bus_append_sched_policy_from_string(m
, field
, eq
);
995 if (STR_IN_SET(field
, "CPUSchedulingPriority",
997 return bus_append_safe_atoi(m
, field
, eq
);
999 if (streq(field
, "CoredumpFilter"))
1000 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
1002 if (streq(field
, "Nice"))
1003 return bus_append_parse_nice(m
, field
, eq
);
1005 if (streq(field
, "SystemCallErrorNumber"))
1006 return bus_append_seccomp_parse_errno_or_action(m
, field
, eq
);
1008 if (streq(field
, "IOSchedulingClass"))
1009 return bus_append_ioprio_class_from_string(m
, field
, eq
);
1011 if (streq(field
, "IOSchedulingPriority"))
1012 return bus_append_ioprio_parse_priority(m
, field
, eq
);
1014 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
1015 "StateDirectoryMode",
1016 "CacheDirectoryMode",
1017 "LogsDirectoryMode",
1018 "ConfigurationDirectoryMode",
1020 return bus_append_parse_mode(m
, field
, eq
);
1022 if (streq(field
, "TimerSlackNSec"))
1023 return bus_append_parse_nsec(m
, field
, eq
);
1025 if (streq(field
, "LogRateLimitIntervalSec"))
1026 return bus_append_parse_sec_rename(m
, field
, eq
);
1028 if (streq(field
, "LogRateLimitBurst"))
1029 return bus_append_safe_atou(m
, field
, eq
);
1031 if (streq(field
, "MountFlags"))
1032 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
1034 if (STR_IN_SET(field
, "Environment",
1037 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
1039 if (streq(field
, "EnvironmentFile")) {
1041 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1043 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1044 eq
[0] == '-' ? eq
+ 1 : eq
,
1047 return bus_log_create_error(r
);
1052 if (STR_IN_SET(field
, "SetCredential", "SetCredentialEncrypted")) {
1053 r
= sd_bus_message_open_container(m
, 'r', "sv");
1055 return bus_log_create_error(r
);
1057 r
= sd_bus_message_append_basic(m
, 's', field
);
1059 return bus_log_create_error(r
);
1061 r
= sd_bus_message_open_container(m
, 'v', "a(say)");
1063 return bus_log_create_error(r
);
1066 r
= sd_bus_message_append(m
, "a(say)", 0);
1068 _cleanup_free_
char *word
= NULL
;
1071 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1075 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1077 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1079 r
= sd_bus_message_open_container(m
, 'a', "(say)");
1081 return bus_log_create_error(r
);
1083 r
= sd_bus_message_open_container(m
, 'r', "say");
1085 return bus_log_create_error(r
);
1087 r
= sd_bus_message_append(m
, "s", word
);
1089 return bus_log_create_error(r
);
1091 if (streq(field
, "SetCredentialEncrypted")) {
1092 _cleanup_free_
void *decoded
= NULL
;
1093 size_t decoded_size
;
1095 r
= unbase64mem(p
, SIZE_MAX
, &decoded
, &decoded_size
);
1097 return log_error_errno(r
, "Failed to base64 decode encrypted credential: %m");
1099 r
= sd_bus_message_append_array(m
, 'y', decoded
, decoded_size
);
1101 _cleanup_free_
char *unescaped
= NULL
;
1104 l
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &unescaped
);
1106 return log_error_errno(l
, "Failed to unescape %s= value: %s", field
, p
);
1108 r
= sd_bus_message_append_array(m
, 'y', unescaped
, l
);
1111 return bus_log_create_error(r
);
1113 r
= sd_bus_message_close_container(m
);
1115 return bus_log_create_error(r
);
1117 r
= sd_bus_message_close_container(m
);
1120 return bus_log_create_error(r
);
1122 r
= sd_bus_message_close_container(m
);
1124 return bus_log_create_error(r
);
1126 r
= sd_bus_message_close_container(m
);
1128 return bus_log_create_error(r
);
1133 if (STR_IN_SET(field
, "LoadCredential", "LoadCredentialEncrypted")) {
1134 r
= sd_bus_message_open_container(m
, 'r', "sv");
1136 return bus_log_create_error(r
);
1138 r
= sd_bus_message_append_basic(m
, 's', field
);
1140 return bus_log_create_error(r
);
1142 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1144 return bus_log_create_error(r
);
1147 r
= sd_bus_message_append(m
, "a(ss)", 0);
1149 _cleanup_free_
char *word
= NULL
;
1152 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1156 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1158 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1160 r
= sd_bus_message_append(m
, "a(ss)", 1, word
, p
);
1163 return bus_log_create_error(r
);
1165 r
= sd_bus_message_close_container(m
);
1167 return bus_log_create_error(r
);
1169 r
= sd_bus_message_close_container(m
);
1171 return bus_log_create_error(r
);
1176 if (streq(field
, "LogExtraFields")) {
1177 r
= sd_bus_message_open_container(m
, 'r', "sv");
1179 return bus_log_create_error(r
);
1181 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
1183 return bus_log_create_error(r
);
1185 r
= sd_bus_message_open_container(m
, 'v', "aay");
1187 return bus_log_create_error(r
);
1189 r
= sd_bus_message_open_container(m
, 'a', "ay");
1191 return bus_log_create_error(r
);
1193 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
1195 return bus_log_create_error(r
);
1197 r
= sd_bus_message_close_container(m
);
1199 return bus_log_create_error(r
);
1201 r
= sd_bus_message_close_container(m
);
1203 return bus_log_create_error(r
);
1205 r
= sd_bus_message_close_container(m
);
1207 return bus_log_create_error(r
);
1212 if (STR_IN_SET(field
, "StandardInput",
1215 const char *n
, *appended
;
1217 if ((n
= startswith(eq
, "fd:"))) {
1218 appended
= strjoina(field
, "FileDescriptorName");
1219 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1220 } else if ((n
= startswith(eq
, "file:"))) {
1221 appended
= strjoina(field
, "File");
1222 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1223 } else if ((n
= startswith(eq
, "append:"))) {
1224 appended
= strjoina(field
, "FileToAppend");
1225 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1226 } else if ((n
= startswith(eq
, "truncate:"))) {
1227 appended
= strjoina(field
, "FileToTruncate");
1228 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1230 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1232 return bus_log_create_error(r
);
1237 if (streq(field
, "StandardInputText")) {
1238 _cleanup_free_
char *unescaped
= NULL
;
1241 l
= cunescape(eq
, 0, &unescaped
);
1243 return log_error_errno(l
, "Failed to unescape text '%s': %m", eq
);
1245 if (!strextend(&unescaped
, "\n"))
1248 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1249 * programmatic interface anyway */
1251 return bus_append_byte_array(m
, field
, unescaped
, l
+ 1);
1254 if (streq(field
, "StandardInputData")) {
1255 _cleanup_free_
void *decoded
= NULL
;
1258 r
= unbase64mem(eq
, SIZE_MAX
, &decoded
, &sz
);
1260 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1262 return bus_append_byte_array(m
, field
, decoded
, sz
);
1265 if ((suffix
= startswith(field
, "Limit"))) {
1268 rl
= rlimit_from_string(suffix
);
1273 r
= rlimit_parse(rl
, eq
, &l
);
1275 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1277 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
1279 return bus_log_create_error(r
);
1281 sn
= strjoina(field
, "Soft");
1282 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1284 return bus_log_create_error(r
);
1290 if (STR_IN_SET(field
, "AppArmorProfile",
1291 "SmackProcessLabel")) {
1300 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1302 return bus_log_create_error(r
);
1307 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1308 "AmbientCapabilities")) {
1310 bool invert
= false;
1318 r
= capability_set_from_string(p
, &sum
);
1320 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1322 sum
= invert
? ~sum
: sum
;
1324 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1326 return bus_log_create_error(r
);
1331 if (streq(field
, "CPUAffinity")) {
1332 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1333 _cleanup_free_
uint8_t *array
= NULL
;
1336 if (eq
&& streq(eq
, "numa")) {
1337 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1339 return bus_log_create_error(r
);
1343 r
= parse_cpu_set(eq
, &cpuset
);
1345 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1347 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1349 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1351 return bus_append_byte_array(m
, field
, array
, allocated
);
1354 if (streq(field
, "NUMAPolicy")) {
1355 r
= mpol_from_string(eq
);
1357 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1359 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1361 return bus_log_create_error(r
);
1366 if (streq(field
, "NUMAMask")) {
1367 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1368 _cleanup_free_
uint8_t *array
= NULL
;
1371 if (eq
&& streq(eq
, "all")) {
1372 r
= numa_mask_add_all(&nodes
);
1374 return log_error_errno(r
, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1376 r
= parse_cpu_set(eq
, &nodes
);
1378 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1381 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1383 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1385 return bus_append_byte_array(m
, field
, array
, allocated
);
1388 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1389 "RestrictFileSystems",
1392 "RestrictNetworkInterfaces")) {
1401 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1403 return bus_log_create_error(r
);
1405 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1407 return bus_log_create_error(r
);
1409 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1411 return bus_log_create_error(r
);
1413 r
= sd_bus_message_open_container(m
, 'r', "bas");
1415 return bus_log_create_error(r
);
1417 r
= sd_bus_message_append_basic(m
, 'b', &allow_list
);
1419 return bus_log_create_error(r
);
1421 r
= sd_bus_message_open_container(m
, 'a', "s");
1423 return bus_log_create_error(r
);
1426 _cleanup_free_
char *word
= NULL
;
1428 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1434 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1436 r
= sd_bus_message_append_basic(m
, 's', word
);
1438 return bus_log_create_error(r
);
1441 r
= sd_bus_message_close_container(m
);
1443 return bus_log_create_error(r
);
1445 r
= sd_bus_message_close_container(m
);
1447 return bus_log_create_error(r
);
1449 r
= sd_bus_message_close_container(m
);
1451 return bus_log_create_error(r
);
1453 r
= sd_bus_message_close_container(m
);
1455 return bus_log_create_error(r
);
1460 if (streq(field
, "RestrictNamespaces")) {
1461 bool invert
= false;
1462 unsigned long flags
;
1464 r
= parse_boolean(eq
);
1468 flags
= NAMESPACE_FLAGS_ALL
;
1475 r
= namespace_flags_from_string(eq
, &flags
);
1477 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1481 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1483 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1485 return bus_log_create_error(r
);
1490 if (STR_IN_SET(field
, "BindPaths",
1491 "BindReadOnlyPaths")) {
1494 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1496 return bus_log_create_error(r
);
1498 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1500 return bus_log_create_error(r
);
1502 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1504 return bus_log_create_error(r
);
1506 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1508 return bus_log_create_error(r
);
1511 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1512 char *s
= NULL
, *d
= NULL
;
1513 bool ignore_enoent
= false;
1514 uint64_t flags
= MS_REC
;
1516 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1518 return log_error_errno(r
, "Failed to parse argument: %m");
1524 ignore_enoent
= true;
1528 if (p
&& p
[-1] == ':') {
1529 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1531 return log_error_errno(r
, "Failed to parse argument: %m");
1533 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1534 "Missing argument after ':': %s",
1539 if (p
&& p
[-1] == ':') {
1540 _cleanup_free_
char *options
= NULL
;
1542 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1544 return log_error_errno(r
, "Failed to parse argument: %m");
1546 if (isempty(options
) || streq(options
, "rbind"))
1548 else if (streq(options
, "norbind"))
1551 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1552 "Unknown options: %s",
1558 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1560 return bus_log_create_error(r
);
1563 r
= sd_bus_message_close_container(m
);
1565 return bus_log_create_error(r
);
1567 r
= sd_bus_message_close_container(m
);
1569 return bus_log_create_error(r
);
1571 r
= sd_bus_message_close_container(m
);
1573 return bus_log_create_error(r
);
1578 if (streq(field
, "TemporaryFileSystem")) {
1581 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1583 return bus_log_create_error(r
);
1585 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1587 return bus_log_create_error(r
);
1589 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1591 return bus_log_create_error(r
);
1593 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1595 return bus_log_create_error(r
);
1598 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1601 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1603 return log_error_errno(r
, "Failed to parse argument: %m");
1608 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1610 return log_error_errno(r
, "Failed to parse argument: %m");
1612 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1613 "Failed to parse argument: %s",
1616 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1618 return bus_log_create_error(r
);
1621 r
= sd_bus_message_close_container(m
);
1623 return bus_log_create_error(r
);
1625 r
= sd_bus_message_close_container(m
);
1627 return bus_log_create_error(r
);
1629 r
= sd_bus_message_close_container(m
);
1631 return bus_log_create_error(r
);
1636 if (streq(field
, "RootHash")) {
1637 _cleanup_free_
void *roothash_decoded
= NULL
;
1638 size_t roothash_decoded_size
= 0;
1640 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1641 if (path_is_absolute(eq
))
1642 return bus_append_string(m
, "RootHashPath", eq
);
1644 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1645 r
= unhexmem(eq
, strlen(eq
), &roothash_decoded
, &roothash_decoded_size
);
1647 return log_error_errno(r
, "Failed to decode RootHash= '%s': %m", eq
);
1648 if (roothash_decoded_size
< sizeof(sd_id128_t
))
1649 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "RootHash= '%s' is too short: %m", eq
);
1651 return bus_append_byte_array(m
, field
, roothash_decoded
, roothash_decoded_size
);
1654 if (streq(field
, "RootHashSignature")) {
1655 _cleanup_free_
void *roothash_sig_decoded
= NULL
;
1657 size_t roothash_sig_decoded_size
= 0;
1659 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1660 if (path_is_absolute(eq
))
1661 return bus_append_string(m
, "RootHashSignaturePath", eq
);
1663 if (!(value
= startswith(eq
, "base64:")))
1664 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq
);
1666 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1667 r
= unbase64mem(value
, strlen(value
), &roothash_sig_decoded
, &roothash_sig_decoded_size
);
1669 return log_error_errno(r
, "Failed to decode RootHashSignature= '%s': %m", eq
);
1671 return bus_append_byte_array(m
, field
, roothash_sig_decoded
, roothash_sig_decoded_size
);
1674 if (streq(field
, "RootImageOptions")) {
1675 _cleanup_strv_free_
char **l
= NULL
;
1676 char **first
= NULL
, **second
= NULL
;
1679 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1681 return bus_log_create_error(r
);
1683 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1685 return bus_log_create_error(r
);
1687 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1689 return bus_log_create_error(r
);
1691 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1693 return bus_log_create_error(r
);
1695 r
= strv_split_colon_pairs(&l
, p
);
1697 return log_error_errno(r
, "Failed to parse argument: %m");
1699 STRV_FOREACH_PAIR(first
, second
, l
) {
1700 r
= sd_bus_message_append(m
, "(ss)",
1701 !isempty(*second
) ? *first
: "root",
1702 !isempty(*second
) ? *second
: *first
);
1704 return bus_log_create_error(r
);
1707 r
= sd_bus_message_close_container(m
);
1709 return bus_log_create_error(r
);
1711 r
= sd_bus_message_close_container(m
);
1713 return bus_log_create_error(r
);
1715 r
= sd_bus_message_close_container(m
);
1717 return bus_log_create_error(r
);
1722 if (streq(field
, "MountImages")) {
1725 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1727 return bus_log_create_error(r
);
1729 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1731 return bus_log_create_error(r
);
1733 r
= sd_bus_message_open_container(m
, 'v', "a(ssba(ss))");
1735 return bus_log_create_error(r
);
1737 r
= sd_bus_message_open_container(m
, 'a', "(ssba(ss))");
1739 return bus_log_create_error(r
);
1742 _cleanup_free_
char *first
= NULL
, *second
= NULL
, *tuple
= NULL
;
1743 const char *q
= NULL
, *source
= NULL
;
1744 bool permissive
= false;
1746 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1748 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1753 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &first
, &second
, NULL
);
1755 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1760 if (source
[0] == '-') {
1765 if (isempty(second
))
1766 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1767 "Missing argument after ':': %s",
1770 r
= sd_bus_message_open_container(m
, 'r', "ssba(ss)");
1772 return bus_log_create_error(r
);
1774 r
= sd_bus_message_append(m
, "ssb", source
, second
, permissive
);
1776 return bus_log_create_error(r
);
1778 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1780 return bus_log_create_error(r
);
1783 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1785 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
1787 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1790 /* Single set of options, applying to the root partition/single filesystem */
1792 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1794 return bus_log_create_error(r
);
1799 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
1801 return bus_log_create_error(r
);
1804 r
= sd_bus_message_close_container(m
);
1806 return bus_log_create_error(r
);
1808 r
= sd_bus_message_close_container(m
);
1810 return bus_log_create_error(r
);
1813 r
= sd_bus_message_close_container(m
);
1815 return bus_log_create_error(r
);
1817 r
= sd_bus_message_close_container(m
);
1819 return bus_log_create_error(r
);
1821 r
= sd_bus_message_close_container(m
);
1823 return bus_log_create_error(r
);
1828 if (streq(field
, "ExtensionImages")) {
1831 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1833 return bus_log_create_error(r
);
1835 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1837 return bus_log_create_error(r
);
1839 r
= sd_bus_message_open_container(m
, 'v', "a(sba(ss))");
1841 return bus_log_create_error(r
);
1843 r
= sd_bus_message_open_container(m
, 'a', "(sba(ss))");
1845 return bus_log_create_error(r
);
1848 _cleanup_free_
char *source
= NULL
, *tuple
= NULL
;
1849 const char *q
= NULL
, *s
= NULL
;
1850 bool permissive
= false;
1852 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1854 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1859 r
= extract_first_word(&q
, &source
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
);
1861 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1871 r
= sd_bus_message_open_container(m
, 'r', "sba(ss)");
1873 return bus_log_create_error(r
);
1875 r
= sd_bus_message_append(m
, "sb", s
, permissive
);
1877 return bus_log_create_error(r
);
1879 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1881 return bus_log_create_error(r
);
1884 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1886 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
1888 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1891 /* Single set of options, applying to the root partition/single filesystem */
1893 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1895 return bus_log_create_error(r
);
1900 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
1902 return bus_log_create_error(r
);
1905 r
= sd_bus_message_close_container(m
);
1907 return bus_log_create_error(r
);
1909 r
= sd_bus_message_close_container(m
);
1911 return bus_log_create_error(r
);
1914 r
= sd_bus_message_close_container(m
);
1916 return bus_log_create_error(r
);
1918 r
= sd_bus_message_close_container(m
);
1920 return bus_log_create_error(r
);
1922 r
= sd_bus_message_close_container(m
);
1924 return bus_log_create_error(r
);
1932 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1933 if (streq(field
, "KillMode"))
1934 return bus_append_string(m
, field
, eq
);
1936 if (STR_IN_SET(field
, "SendSIGHUP",
1938 return bus_append_parse_boolean(m
, field
, eq
);
1940 if (STR_IN_SET(field
, "KillSignal",
1941 "RestartKillSignal",
1944 return bus_append_signal_from_string(m
, field
, eq
);
1949 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1951 if (STR_IN_SET(field
, "What",
1955 return bus_append_string(m
, field
, eq
);
1957 if (streq(field
, "TimeoutSec"))
1958 return bus_append_parse_sec_rename(m
, field
, eq
);
1960 if (streq(field
, "DirectoryMode"))
1961 return bus_append_parse_mode(m
, field
, eq
);
1963 if (STR_IN_SET(field
, "SloppyOptions",
1967 return bus_append_parse_boolean(m
, field
, eq
);
1972 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1975 if (streq(field
, "MakeDirectory"))
1976 return bus_append_parse_boolean(m
, field
, eq
);
1978 if (streq(field
, "DirectoryMode"))
1979 return bus_append_parse_mode(m
, field
, eq
);
1981 if (STR_IN_SET(field
, "PathExists",
1985 "DirectoryNotEmpty")) {
1987 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1989 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1991 return bus_log_create_error(r
);
1999 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2000 if (streq(field
, "RuntimeMaxSec"))
2001 return bus_append_parse_sec_rename(m
, field
, eq
);
2003 if (streq(field
, "RuntimeRandomizedExtraSec"))
2004 return bus_append_parse_sec_rename(m
, field
, eq
);
2006 if (streq(field
, "TimeoutStopSec"))
2007 return bus_append_parse_sec_rename(m
, field
, eq
);
2012 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2015 if (STR_IN_SET(field
, "PIDFile",
2020 "USBFunctionDescriptors",
2021 "USBFunctionStrings",
2023 "TimeoutStartFailureMode",
2024 "TimeoutStopFailureMode"))
2025 return bus_append_string(m
, field
, eq
);
2027 if (STR_IN_SET(field
, "PermissionsStartOnly",
2028 "RootDirectoryStartOnly",
2031 return bus_append_parse_boolean(m
, field
, eq
);
2033 if (STR_IN_SET(field
, "RestartSec",
2038 "RuntimeRandomizedExtraSec",
2040 return bus_append_parse_sec_rename(m
, field
, eq
);
2042 if (streq(field
, "TimeoutSec")) {
2043 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
2047 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
2050 if (streq(field
, "FileDescriptorStoreMax"))
2051 return bus_append_safe_atou(m
, field
, eq
);
2053 if (STR_IN_SET(field
, "ExecCondition",
2067 return bus_append_exec_command(m
, field
, eq
);
2069 if (STR_IN_SET(field
, "RestartPreventExitStatus",
2070 "RestartForceExitStatus",
2071 "SuccessExitStatus")) {
2072 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
2073 size_t n_status
= 0, n_signal
= 0;
2077 _cleanup_free_
char *word
= NULL
;
2079 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
2085 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
2087 /* We need to call exit_status_from_string() first, because we want
2088 * to parse numbers as exit statuses, not signals. */
2090 r
= exit_status_from_string(word
);
2092 assert(r
>= 0 && r
< 256);
2094 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
2098 status
[n_status
++] = r
;
2100 } else if ((r
= signal_from_string(word
)) >= 0) {
2101 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
2105 signal
[n_signal
++] = r
;
2108 /* original r from exit_status_to_string() */
2109 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
2113 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2115 return bus_log_create_error(r
);
2117 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2119 return bus_log_create_error(r
);
2121 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
2123 return bus_log_create_error(r
);
2125 r
= sd_bus_message_open_container(m
, 'r', "aiai");
2127 return bus_log_create_error(r
);
2129 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
2131 return bus_log_create_error(r
);
2133 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
2135 return bus_log_create_error(r
);
2137 r
= sd_bus_message_close_container(m
);
2139 return bus_log_create_error(r
);
2141 r
= sd_bus_message_close_container(m
);
2143 return bus_log_create_error(r
);
2145 r
= sd_bus_message_close_container(m
);
2147 return bus_log_create_error(r
);
2155 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2158 if (STR_IN_SET(field
, "Accept",
2171 "SELinuxContextFromNet"))
2172 return bus_append_parse_boolean(m
, field
, eq
);
2174 if (STR_IN_SET(field
, "Priority",
2177 return bus_append_safe_atoi(m
, field
, eq
);
2179 if (streq(field
, "IPTOS"))
2180 return bus_append_ip_tos_from_string(m
, field
, eq
);
2182 if (STR_IN_SET(field
, "Backlog",
2184 "MaxConnectionsPerSource",
2186 "TriggerLimitBurst"))
2187 return bus_append_safe_atou(m
, field
, eq
);
2189 if (STR_IN_SET(field
, "SocketMode",
2191 return bus_append_parse_mode(m
, field
, eq
);
2193 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
2194 "MessageQueueMessageSize"))
2195 return bus_append_safe_atoi64(m
, field
, eq
);
2197 if (STR_IN_SET(field
, "TimeoutSec",
2199 "KeepAliveIntervalSec",
2201 "TriggerLimitIntervalSec"))
2202 return bus_append_parse_sec_rename(m
, field
, eq
);
2204 if (STR_IN_SET(field
, "ReceiveBuffer",
2207 return bus_append_parse_size(m
, field
, eq
, 1024);
2209 if (STR_IN_SET(field
, "ExecStartPre",
2213 return bus_append_exec_command(m
, field
, eq
);
2215 if (STR_IN_SET(field
, "SmackLabel",
2221 "FileDescriptorName",
2225 return bus_append_string(m
, field
, eq
);
2227 if (streq(field
, "Symlinks"))
2228 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2230 if (streq(field
, "SocketProtocol"))
2231 return bus_append_parse_ip_protocol(m
, field
, eq
);
2233 if (STR_IN_SET(field
, "ListenStream",
2235 "ListenSequentialPacket",
2238 "ListenMessageQueue",
2240 "ListenUSBFunction")) {
2242 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
2244 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
2246 return bus_log_create_error(r
);
2253 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2256 if (STR_IN_SET(field
, "WakeSystem",
2257 "RemainAfterElapse",
2261 "FixedRandomDelay"))
2262 return bus_append_parse_boolean(m
, field
, eq
);
2264 if (STR_IN_SET(field
, "AccuracySec",
2265 "RandomizedDelaySec"))
2266 return bus_append_parse_sec_rename(m
, field
, eq
);
2268 if (STR_IN_SET(field
, "OnActiveSec",
2272 "OnUnitInactiveSec")) {
2274 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
2277 r
= parse_sec(eq
, &t
);
2279 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
2281 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
2284 return bus_log_create_error(r
);
2289 if (streq(field
, "OnCalendar")) {
2291 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
2293 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
2295 return bus_log_create_error(r
);
2303 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2304 ConditionType t
= _CONDITION_TYPE_INVALID
;
2305 bool is_condition
= false;
2308 if (STR_IN_SET(field
, "Description",
2312 "JobTimeoutRebootArgument",
2318 return bus_append_string(m
, field
, eq
);
2320 if (STR_IN_SET(field
, "StopWhenUnneeded",
2321 "RefuseManualStart",
2325 "DefaultDependencies"))
2326 return bus_append_parse_boolean(m
, field
, eq
);
2328 if (STR_IN_SET(field
, "JobTimeoutSec",
2329 "JobRunningTimeoutSec",
2330 "StartLimitIntervalSec"))
2331 return bus_append_parse_sec_rename(m
, field
, eq
);
2333 if (streq(field
, "StartLimitBurst"))
2334 return bus_append_safe_atou(m
, field
, eq
);
2336 if (STR_IN_SET(field
, "SuccessActionExitStatus",
2337 "FailureActionExitStatus")) {
2339 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
2343 r
= safe_atou8(eq
, &u
);
2345 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
2347 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
2350 return bus_log_create_error(r
);
2355 if (unit_dependency_from_string(field
) >= 0 ||
2356 STR_IN_SET(field
, "Documentation",
2357 "RequiresMountsFor",
2359 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2361 t
= condition_type_from_string(field
);
2363 is_condition
= true;
2365 t
= assert_type_from_string(field
);
2368 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
2371 int trigger
, negate
;
2373 trigger
= *p
== '|';
2381 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
2382 field
, trigger
, negate
, p
);
2385 return bus_log_create_error(r
);
2393 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
2394 const char *eq
, *field
;
2400 eq
= strchr(assignment
, '=');
2402 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2403 "Not an assignment: %s", assignment
);
2405 field
= strndupa_safe(assignment
, eq
- assignment
);
2410 r
= bus_append_cgroup_property(m
, field
, eq
);
2414 r
= bus_append_execute_property(m
, field
, eq
);
2418 r
= bus_append_kill_property(m
, field
, eq
);
2422 r
= bus_append_service_property(m
, field
, eq
);
2428 r
= bus_append_cgroup_property(m
, field
, eq
);
2432 r
= bus_append_execute_property(m
, field
, eq
);
2436 r
= bus_append_kill_property(m
, field
, eq
);
2440 r
= bus_append_socket_property(m
, field
, eq
);
2446 r
= bus_append_timer_property(m
, field
, eq
);
2452 r
= bus_append_path_property(m
, field
, eq
);
2458 r
= bus_append_cgroup_property(m
, field
, eq
);
2464 r
= bus_append_cgroup_property(m
, field
, eq
);
2468 r
= bus_append_kill_property(m
, field
, eq
);
2472 r
= bus_append_scope_property(m
, field
, eq
);
2478 r
= bus_append_cgroup_property(m
, field
, eq
);
2482 r
= bus_append_execute_property(m
, field
, eq
);
2486 r
= bus_append_kill_property(m
, field
, eq
);
2490 r
= bus_append_mount_property(m
, field
, eq
);
2496 case UNIT_AUTOMOUNT
:
2497 r
= bus_append_automount_property(m
, field
, eq
);
2506 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2507 "Not supported unit type");
2510 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2511 "Invalid unit type");
2514 r
= bus_append_unit_property(m
, field
, eq
);
2518 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2519 "Unknown assignment: %s", assignment
);
2522 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
2528 STRV_FOREACH(i
, l
) {
2529 r
= bus_append_unit_property_assignment(m
, t
, *i
);
2537 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
2538 const char *type
, *path
, *source
;
2541 /* changes is dereferenced when calling unit_file_dump_changes() later,
2542 * so we have to make sure this is not NULL. */
2546 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2548 return bus_log_parse_error(r
);
2550 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2551 /* We expect only "success" changes to be sent over the bus.
2552 Hence, reject anything negative. */
2553 int ch
= unit_file_change_type_from_string(type
);
2555 log_notice_errno(ch
, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2560 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2565 return bus_log_parse_error(r
);
2567 r
= sd_bus_message_exit_container(m
);
2569 return bus_log_parse_error(r
);
2571 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2575 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2576 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2577 _cleanup_free_
char *path
= NULL
;
2580 path
= unit_dbus_path_from_name(name
);
2584 /* This function warns on it's own, because otherwise it'd be awkward to pass
2585 * the dbus error message around. */
2587 r
= sd_bus_get_property_string(
2589 "org.freedesktop.systemd1",
2591 "org.freedesktop.systemd1.Unit",
2596 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));
2601 int unit_info_compare(const UnitInfo
*a
, const UnitInfo
*b
) {
2604 /* First, order by machine */
2605 r
= strcasecmp_ptr(a
->machine
, b
->machine
);
2609 /* Second, order by unit type */
2610 r
= strcasecmp_ptr(strrchr(a
->id
, '.'), strrchr(b
->id
, '.'));
2614 /* Third, order by name */
2615 return strcasecmp(a
->id
, b
->id
);