1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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"
13 #include "dissect-image.h"
15 #include "exec-util.h"
16 #include "exit-status.h"
18 #include "hexdecoct.h"
19 #include "hostname-util.h"
20 #include "in-addr-util.h"
21 #include "ip-protocol-list.h"
22 #include "libmount-util.h"
23 #include "locale-util.h"
25 #include "missing_fs.h"
26 #include "mountpoint-util.h"
28 #include "numa-util.h"
29 #include "parse-util.h"
30 #include "path-util.h"
31 #include "percent-util.h"
32 #include "process-util.h"
33 #include "rlimit-util.h"
35 #include "seccomp-util.h"
37 #include "securebits-util.h"
38 #include "signal-util.h"
39 #include "socket-util.h"
40 #include "sort-util.h"
41 #include "stdio-util.h"
42 #include "string-util.h"
43 #include "syslog-util.h"
44 #include "terminal-util.h"
46 #include "user-util.h"
49 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
55 return sd_bus_message_read(
70 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
71 static int bus_append_##parse_func( \
78 r = parse_func(eq, &val); \
80 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
82 r = sd_bus_message_append(m, "(sv)", field, \
83 bus_type, (cast_type) val); \
85 return bus_log_create_error(r); \
90 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
91 static int bus_append_##parse_func( \
99 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
101 r = sd_bus_message_append(m, "(sv)", field, \
102 bus_type, (int32_t) r); \
104 return bus_log_create_error(r); \
109 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
110 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
111 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
112 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
113 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
115 static inline int seccomp_parse_errno_or_action(const char *eq
) { return -EINVAL
; }
117 DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action
);
118 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
119 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
120 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
121 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
122 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
123 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
124 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
125 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
126 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
127 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
128 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
129 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
130 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
131 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
132 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
133 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
134 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
136 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
139 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
141 return bus_log_create_error(r
);
146 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
150 r
= sd_bus_message_open_container(m
, 'r', "sv");
152 return bus_log_create_error(r
);
154 r
= sd_bus_message_append_basic(m
, 's', field
);
156 return bus_log_create_error(r
);
158 r
= sd_bus_message_open_container(m
, 'v', "as");
160 return bus_log_create_error(r
);
162 r
= sd_bus_message_open_container(m
, 'a', "s");
164 return bus_log_create_error(r
);
167 _cleanup_free_
char *word
= NULL
;
169 r
= extract_first_word(&p
, &word
, NULL
, flags
);
175 return log_error_errno(r
, "Invalid syntax: %s", eq
);
177 r
= sd_bus_message_append_basic(m
, 's', word
);
179 return bus_log_create_error(r
);
182 r
= sd_bus_message_close_container(m
);
184 return bus_log_create_error(r
);
186 r
= sd_bus_message_close_container(m
);
188 return bus_log_create_error(r
);
190 r
= sd_bus_message_close_container(m
);
192 return bus_log_create_error(r
);
197 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
200 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
202 return bus_log_create_error(r
);
204 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
206 return bus_log_create_error(r
);
208 r
= sd_bus_message_open_container(m
, 'v', "ay");
210 return bus_log_create_error(r
);
212 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
214 return bus_log_create_error(r
);
216 r
= sd_bus_message_close_container(m
);
218 return bus_log_create_error(r
);
220 r
= sd_bus_message_close_container(m
);
222 return bus_log_create_error(r
);
227 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
233 r
= parse_sec(eq
, &t
);
235 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
238 n
= newa(char, l
+ 2);
239 /* Change suffix Sec → USec */
240 strcpy(mempcpy(n
, field
, l
- 3), "USec");
242 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
244 return bus_log_create_error(r
);
249 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
253 r
= parse_size(eq
, base
, &v
);
255 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
257 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
259 return bus_log_create_error(r
);
264 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
265 bool explicit_path
= false, done
= false;
266 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
267 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
268 ExecCommandFlags flags
= 0;
269 bool is_ex_prop
= endswith(field
, "Ex");
276 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
279 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
288 explicit_path
= true;
294 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
297 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
303 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
306 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
312 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
314 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
315 flags
&= ~EXEC_COMMAND_NO_SETUID
;
316 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
319 flags
|= EXEC_COMMAND_NO_SETUID
;
330 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
331 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
333 upgraded_name
= strjoin(field
, "Ex");
339 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
341 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
345 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
347 return log_error_errno(r
, "Failed to parse path: %m");
350 r
= strv_split_full(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
352 return log_error_errno(r
, "Failed to parse command line: %m");
354 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
356 return bus_log_create_error(r
);
358 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
360 return bus_log_create_error(r
);
362 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
364 return bus_log_create_error(r
);
366 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
368 return bus_log_create_error(r
);
370 if (!strv_isempty(l
)) {
372 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
374 return bus_log_create_error(r
);
376 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
378 return bus_log_create_error(r
);
380 r
= sd_bus_message_append_strv(m
, l
);
382 return bus_log_create_error(r
);
384 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
));
386 return bus_log_create_error(r
);
388 r
= sd_bus_message_close_container(m
);
390 return bus_log_create_error(r
);
393 r
= sd_bus_message_close_container(m
);
395 return bus_log_create_error(r
);
397 r
= sd_bus_message_close_container(m
);
399 return bus_log_create_error(r
);
401 r
= sd_bus_message_close_container(m
);
403 return bus_log_create_error(r
);
408 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
414 r
= sd_bus_message_open_container(m
, 'r', "iayu");
418 r
= sd_bus_message_append(m
, "i", family
);
422 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
426 r
= sd_bus_message_append(m
, "u", prefixlen
);
430 return sd_bus_message_close_container(m
);
433 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
436 if (STR_IN_SET(field
, "DevicePolicy",
439 "ManagedOOMMemoryPressure",
440 "ManagedOOMPreference"))
441 return bus_append_string(m
, field
, eq
);
443 if (STR_IN_SET(field
, "ManagedOOMMemoryPressureLimit")) {
444 r
= parse_permyriad(eq
);
446 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
448 /* Pass around scaled to 2^32-1 == 100% */
449 r
= sd_bus_message_append(m
, "(sv)", field
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
451 return bus_log_create_error(r
);
456 if (STR_IN_SET(field
, "CPUAccounting",
462 return bus_append_parse_boolean(m
, field
, eq
);
464 if (STR_IN_SET(field
, "CPUWeight",
468 return bus_append_cg_weight_parse(m
, field
, eq
);
470 if (STR_IN_SET(field
, "CPUShares",
472 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
474 if (STR_IN_SET(field
, "AllowedCPUs",
475 "AllowedMemoryNodes")) {
476 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
477 _cleanup_free_
uint8_t *array
= NULL
;
480 r
= parse_cpu_set(eq
, &cpuset
);
482 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
484 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
486 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
488 return bus_append_byte_array(m
, field
, array
, allocated
);
491 if (STR_IN_SET(field
, "BlockIOWeight",
492 "StartupBlockIOWeight"))
493 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
495 if (streq(field
, "DisableControllers"))
496 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
498 if (streq(field
, "Delegate")) {
499 r
= parse_boolean(eq
);
501 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
503 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
505 return bus_log_create_error(r
);
510 if (STR_IN_SET(field
, "MemoryMin",
520 if (streq(eq
, "infinity")) {
521 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
523 return bus_log_create_error(r
);
525 } else if (isempty(eq
)) {
526 uint64_t empty_value
= STR_IN_SET(field
,
534 r
= sd_bus_message_append(m
, "(sv)", field
, "t", empty_value
);
536 return bus_log_create_error(r
);
540 r
= parse_permyriad(eq
);
544 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
545 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
546 * size can be determined server-side. */
548 n
= strjoina(field
, "Scale");
549 r
= sd_bus_message_append(m
, "(sv)", n
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
551 return bus_log_create_error(r
);
556 if (streq(field
, "TasksMax"))
557 return bus_append_safe_atou64(m
, field
, eq
);
559 return bus_append_parse_size(m
, field
, eq
, 1024);
562 if (streq(field
, "CPUQuota")) {
564 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
566 r
= parse_permyriad_unbounded(eq
);
568 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
569 "CPU quota too small.");
571 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
573 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 10000U));
577 return bus_log_create_error(r
);
582 if (streq(field
, "CPUQuotaPeriodSec")) {
583 usec_t u
= USEC_INFINITY
;
585 r
= parse_sec_def_infinity(eq
, &u
);
587 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
589 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
591 return bus_log_create_error(r
);
596 if (streq(field
, "DeviceAllow")) {
598 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
600 const char *path
= eq
, *rwm
= NULL
, *e
;
604 path
= strndupa(eq
, e
- eq
);
608 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
612 return bus_log_create_error(r
);
617 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
619 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
621 const char *path
, *bandwidth
, *e
;
626 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
627 "Failed to parse %s value %s.",
630 path
= strndupa(eq
, e
- eq
);
633 if (streq(bandwidth
, "infinity"))
634 bytes
= CGROUP_LIMIT_MAX
;
636 r
= parse_size(bandwidth
, 1000, &bytes
);
638 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
641 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
645 return bus_log_create_error(r
);
650 if (STR_IN_SET(field
, "IODeviceWeight",
651 "BlockIODeviceWeight")) {
653 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
655 const char *path
, *weight
, *e
;
660 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
661 "Failed to parse %s value %s.",
664 path
= strndupa(eq
, e
- eq
);
667 r
= safe_atou64(weight
, &u
);
669 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
671 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
675 return bus_log_create_error(r
);
680 if (streq(field
, "IODeviceLatencyTargetSec")) {
681 const char *field_usec
= "IODeviceLatencyTargetUSec";
684 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
686 const char *path
, *target
, *e
;
691 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
692 "Failed to parse %s value %s.",
695 path
= strndupa(eq
, e
- eq
);
698 r
= parse_sec(target
, &usec
);
700 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
702 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
706 return bus_log_create_error(r
);
711 if (STR_IN_SET(field
, "IPAddressAllow",
713 unsigned char prefixlen
;
714 union in_addr_union prefix
= {};
718 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
720 return bus_log_create_error(r
);
725 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
727 return bus_log_create_error(r
);
729 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
731 return bus_log_create_error(r
);
733 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
735 return bus_log_create_error(r
);
737 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
739 return bus_log_create_error(r
);
741 if (streq(eq
, "any")) {
742 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
744 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
746 return bus_log_create_error(r
);
748 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
750 return bus_log_create_error(r
);
752 } else if (is_localhost(eq
)) {
753 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
755 prefix
.in
.s_addr
= htobe32(0x7f000000);
756 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
758 return bus_log_create_error(r
);
760 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
761 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
765 } else if (streq(eq
, "link-local")) {
766 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
768 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
769 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
771 return bus_log_create_error(r
);
773 prefix
.in6
= (struct in6_addr
) {
774 .s6_addr32
[0] = htobe32(0xfe800000)
776 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
778 return bus_log_create_error(r
);
780 } else if (streq(eq
, "multicast")) {
781 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
783 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
784 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
786 return bus_log_create_error(r
);
788 prefix
.in6
= (struct in6_addr
) {
789 .s6_addr32
[0] = htobe32(0xff000000)
791 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
793 return bus_log_create_error(r
);
797 _cleanup_free_
char *word
= NULL
;
799 r
= extract_first_word(&eq
, &word
, NULL
, 0);
805 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
807 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
809 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
811 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
813 return bus_log_create_error(r
);
817 r
= sd_bus_message_close_container(m
);
819 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
);
832 if (STR_IN_SET(field
, "IPIngressFilterPath",
833 "IPEgressFilterPath")) {
835 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
837 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
840 return bus_log_create_error(r
);
848 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
849 if (streq(field
, "Where"))
850 return bus_append_string(m
, field
, eq
);
852 if (streq(field
, "DirectoryMode"))
853 return bus_append_parse_mode(m
, field
, eq
);
855 if (streq(field
, "TimeoutIdleSec"))
856 return bus_append_parse_sec_rename(m
, field
, eq
);
861 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
865 if (STR_IN_SET(field
, "User",
879 "RuntimeDirectoryPreserve",
884 "NetworkNamespacePath",
887 return bus_append_string(m
, field
, eq
);
889 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
901 "MemoryDenyWriteExecute",
905 "ProtectKernelTunables",
906 "ProtectKernelModules",
909 "ProtectControlGroups",
911 "CPUSchedulingResetOnFork",
915 return bus_append_parse_boolean(m
, field
, eq
);
917 if (STR_IN_SET(field
, "ReadWriteDirectories",
918 "ReadOnlyDirectories",
919 "InaccessibleDirectories",
929 "ConfigurationDirectory",
930 "SupplementaryGroups",
931 "SystemCallArchitectures"))
932 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
934 if (STR_IN_SET(field
, "SyslogLevel",
936 return bus_append_log_level_from_string(m
, field
, eq
);
938 if (streq(field
, "SyslogFacility"))
939 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
941 if (streq(field
, "SecureBits"))
942 return bus_append_secure_bits_from_string(m
, field
, eq
);
944 if (streq(field
, "CPUSchedulingPolicy"))
945 return bus_append_sched_policy_from_string(m
, field
, eq
);
947 if (STR_IN_SET(field
, "CPUSchedulingPriority",
949 return bus_append_safe_atoi(m
, field
, eq
);
951 if (streq(field
, "CoredumpFilter"))
952 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
954 if (streq(field
, "Nice"))
955 return bus_append_parse_nice(m
, field
, eq
);
957 if (streq(field
, "SystemCallErrorNumber"))
958 return bus_append_seccomp_parse_errno_or_action(m
, field
, eq
);
960 if (streq(field
, "IOSchedulingClass"))
961 return bus_append_ioprio_class_from_string(m
, field
, eq
);
963 if (streq(field
, "IOSchedulingPriority"))
964 return bus_append_ioprio_parse_priority(m
, field
, eq
);
966 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
967 "StateDirectoryMode",
968 "CacheDirectoryMode",
970 "ConfigurationDirectoryMode",
972 return bus_append_parse_mode(m
, field
, eq
);
974 if (streq(field
, "TimerSlackNSec"))
975 return bus_append_parse_nsec(m
, field
, eq
);
977 if (streq(field
, "LogRateLimitIntervalSec"))
978 return bus_append_parse_sec_rename(m
, field
, eq
);
980 if (streq(field
, "LogRateLimitBurst"))
981 return bus_append_safe_atou(m
, field
, eq
);
983 if (streq(field
, "MountFlags"))
984 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
986 if (STR_IN_SET(field
, "Environment",
989 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
991 if (streq(field
, "EnvironmentFile")) {
993 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
995 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
996 eq
[0] == '-' ? eq
+ 1 : eq
,
999 return bus_log_create_error(r
);
1004 if (streq(field
, "SetCredential")) {
1005 r
= sd_bus_message_open_container(m
, 'r', "sv");
1007 return bus_log_create_error(r
);
1009 r
= sd_bus_message_append_basic(m
, 's', "SetCredential");
1011 return bus_log_create_error(r
);
1013 r
= sd_bus_message_open_container(m
, 'v', "a(say)");
1015 return bus_log_create_error(r
);
1018 r
= sd_bus_message_append(m
, "a(say)", 0);
1020 _cleanup_free_
char *word
= NULL
, *unescaped
= NULL
;
1024 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1028 return log_error_errno(r
, "Failed to parse SetCredential= parameter: %s", eq
);
1030 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to SetCredential=.");
1032 l
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &unescaped
);
1034 return log_error_errno(l
, "Failed to unescape SetCredential= value: %s", p
);
1036 r
= sd_bus_message_open_container(m
, 'a', "(say)");
1038 return bus_log_create_error(r
);
1040 r
= sd_bus_message_open_container(m
, 'r', "say");
1042 return bus_log_create_error(r
);
1044 r
= sd_bus_message_append(m
, "s", word
);
1046 return bus_log_create_error(r
);
1048 r
= sd_bus_message_append_array(m
, 'y', unescaped
, l
);
1050 return bus_log_create_error(r
);
1052 r
= sd_bus_message_close_container(m
);
1054 return bus_log_create_error(r
);
1056 r
= sd_bus_message_close_container(m
);
1059 return bus_log_create_error(r
);
1061 r
= sd_bus_message_close_container(m
);
1063 return bus_log_create_error(r
);
1065 r
= sd_bus_message_close_container(m
);
1067 return bus_log_create_error(r
);
1072 if (streq(field
, "LoadCredential")) {
1073 r
= sd_bus_message_open_container(m
, 'r', "sv");
1075 return bus_log_create_error(r
);
1077 r
= sd_bus_message_append_basic(m
, 's', "LoadCredential");
1079 return bus_log_create_error(r
);
1081 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1083 return bus_log_create_error(r
);
1086 r
= sd_bus_message_append(m
, "a(ss)", 0);
1088 _cleanup_free_
char *word
= NULL
;
1091 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1095 return log_error_errno(r
, "Failed to parse LoadCredential= parameter: %s", eq
);
1097 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to LoadCredential=.");
1099 r
= sd_bus_message_append(m
, "a(ss)", 1, word
, p
);
1102 return bus_log_create_error(r
);
1104 r
= sd_bus_message_close_container(m
);
1106 return bus_log_create_error(r
);
1108 r
= sd_bus_message_close_container(m
);
1110 return bus_log_create_error(r
);
1115 if (streq(field
, "LogExtraFields")) {
1116 r
= sd_bus_message_open_container(m
, 'r', "sv");
1118 return bus_log_create_error(r
);
1120 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
1122 return bus_log_create_error(r
);
1124 r
= sd_bus_message_open_container(m
, 'v', "aay");
1126 return bus_log_create_error(r
);
1128 r
= sd_bus_message_open_container(m
, 'a', "ay");
1130 return bus_log_create_error(r
);
1132 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
1134 return bus_log_create_error(r
);
1136 r
= sd_bus_message_close_container(m
);
1138 return bus_log_create_error(r
);
1140 r
= sd_bus_message_close_container(m
);
1142 return bus_log_create_error(r
);
1144 r
= sd_bus_message_close_container(m
);
1146 return bus_log_create_error(r
);
1151 if (STR_IN_SET(field
, "StandardInput",
1154 const char *n
, *appended
;
1156 if ((n
= startswith(eq
, "fd:"))) {
1157 appended
= strjoina(field
, "FileDescriptorName");
1158 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1159 } else if ((n
= startswith(eq
, "file:"))) {
1160 appended
= strjoina(field
, "File");
1161 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1162 } else if ((n
= startswith(eq
, "append:"))) {
1163 appended
= strjoina(field
, "FileToAppend");
1164 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1165 } else if ((n
= startswith(eq
, "truncate:"))) {
1166 appended
= strjoina(field
, "FileToTruncate");
1167 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1169 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1171 return bus_log_create_error(r
);
1176 if (streq(field
, "StandardInputText")) {
1177 _cleanup_free_
char *unescaped
= NULL
;
1179 r
= cunescape(eq
, 0, &unescaped
);
1181 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
1183 if (!strextend(&unescaped
, "\n"))
1186 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
1187 * interface anyway */
1189 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
1192 if (streq(field
, "StandardInputData")) {
1193 _cleanup_free_
void *decoded
= NULL
;
1196 r
= unbase64mem(eq
, SIZE_MAX
, &decoded
, &sz
);
1198 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1200 return bus_append_byte_array(m
, field
, decoded
, sz
);
1203 if ((suffix
= startswith(field
, "Limit"))) {
1206 rl
= rlimit_from_string(suffix
);
1211 r
= rlimit_parse(rl
, eq
, &l
);
1213 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1215 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
1217 return bus_log_create_error(r
);
1219 sn
= strjoina(field
, "Soft");
1220 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1222 return bus_log_create_error(r
);
1228 if (STR_IN_SET(field
, "AppArmorProfile",
1229 "SmackProcessLabel")) {
1238 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1240 return bus_log_create_error(r
);
1245 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1246 "AmbientCapabilities")) {
1248 bool invert
= false;
1256 r
= capability_set_from_string(p
, &sum
);
1258 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1260 sum
= invert
? ~sum
: sum
;
1262 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1264 return bus_log_create_error(r
);
1269 if (streq(field
, "CPUAffinity")) {
1270 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1271 _cleanup_free_
uint8_t *array
= NULL
;
1274 if (eq
&& streq(eq
, "numa")) {
1275 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1277 return bus_log_create_error(r
);
1281 r
= parse_cpu_set(eq
, &cpuset
);
1283 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1285 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1287 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1289 return bus_append_byte_array(m
, field
, array
, allocated
);
1292 if (streq(field
, "NUMAPolicy")) {
1293 r
= mpol_from_string(eq
);
1295 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1297 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1299 return bus_log_create_error(r
);
1304 if (streq(field
, "NUMAMask")) {
1305 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1306 _cleanup_free_
uint8_t *array
= NULL
;
1309 if (eq
&& streq(eq
, "all")) {
1310 r
= numa_mask_add_all(&nodes
);
1312 return log_error_errno(r
, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1314 r
= parse_cpu_set(eq
, &nodes
);
1316 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1319 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1321 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1323 return bus_append_byte_array(m
, field
, array
, allocated
);
1326 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1337 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1339 return bus_log_create_error(r
);
1341 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1343 return bus_log_create_error(r
);
1345 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1347 return bus_log_create_error(r
);
1349 r
= sd_bus_message_open_container(m
, 'r', "bas");
1351 return bus_log_create_error(r
);
1353 r
= sd_bus_message_append_basic(m
, 'b', &allow_list
);
1355 return bus_log_create_error(r
);
1357 r
= sd_bus_message_open_container(m
, 'a', "s");
1359 return bus_log_create_error(r
);
1362 _cleanup_free_
char *word
= NULL
;
1364 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1370 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1372 r
= sd_bus_message_append_basic(m
, 's', word
);
1374 return bus_log_create_error(r
);
1377 r
= sd_bus_message_close_container(m
);
1379 return bus_log_create_error(r
);
1381 r
= sd_bus_message_close_container(m
);
1383 return bus_log_create_error(r
);
1385 r
= sd_bus_message_close_container(m
);
1387 return bus_log_create_error(r
);
1389 r
= sd_bus_message_close_container(m
);
1391 return bus_log_create_error(r
);
1396 if (streq(field
, "RestrictNamespaces")) {
1397 bool invert
= false;
1398 unsigned long flags
;
1400 r
= parse_boolean(eq
);
1404 flags
= NAMESPACE_FLAGS_ALL
;
1411 r
= namespace_flags_from_string(eq
, &flags
);
1413 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1417 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1419 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1421 return bus_log_create_error(r
);
1426 if (STR_IN_SET(field
, "BindPaths",
1427 "BindReadOnlyPaths")) {
1430 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1432 return bus_log_create_error(r
);
1434 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1436 return bus_log_create_error(r
);
1438 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1440 return bus_log_create_error(r
);
1442 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1444 return bus_log_create_error(r
);
1447 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1448 char *s
= NULL
, *d
= NULL
;
1449 bool ignore_enoent
= false;
1450 uint64_t flags
= MS_REC
;
1452 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1454 return log_error_errno(r
, "Failed to parse argument: %m");
1460 ignore_enoent
= true;
1464 if (p
&& p
[-1] == ':') {
1465 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1467 return log_error_errno(r
, "Failed to parse argument: %m");
1469 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1470 "Missing argument after ':': %s",
1475 if (p
&& p
[-1] == ':') {
1476 _cleanup_free_
char *options
= NULL
;
1478 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1480 return log_error_errno(r
, "Failed to parse argument: %m");
1482 if (isempty(options
) || streq(options
, "rbind"))
1484 else if (streq(options
, "norbind"))
1487 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1488 "Unknown options: %s",
1494 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1496 return bus_log_create_error(r
);
1499 r
= sd_bus_message_close_container(m
);
1501 return bus_log_create_error(r
);
1503 r
= sd_bus_message_close_container(m
);
1505 return bus_log_create_error(r
);
1507 r
= sd_bus_message_close_container(m
);
1509 return bus_log_create_error(r
);
1514 if (streq(field
, "TemporaryFileSystem")) {
1517 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1519 return bus_log_create_error(r
);
1521 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1523 return bus_log_create_error(r
);
1525 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1527 return bus_log_create_error(r
);
1529 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1531 return bus_log_create_error(r
);
1534 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1537 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1539 return log_error_errno(r
, "Failed to parse argument: %m");
1544 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1546 return log_error_errno(r
, "Failed to parse argument: %m");
1548 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1549 "Failed to parse argument: %s",
1552 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1554 return bus_log_create_error(r
);
1557 r
= sd_bus_message_close_container(m
);
1559 return bus_log_create_error(r
);
1561 r
= sd_bus_message_close_container(m
);
1563 return bus_log_create_error(r
);
1565 r
= sd_bus_message_close_container(m
);
1567 return bus_log_create_error(r
);
1572 if (streq(field
, "RootHash")) {
1573 _cleanup_free_
void *roothash_decoded
= NULL
;
1574 size_t roothash_decoded_size
= 0;
1576 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1577 if (path_is_absolute(eq
))
1578 return bus_append_string(m
, "RootHashPath", eq
);
1580 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1581 r
= unhexmem(eq
, strlen(eq
), &roothash_decoded
, &roothash_decoded_size
);
1583 return log_error_errno(r
, "Failed to decode RootHash= '%s': %m", eq
);
1584 if (roothash_decoded_size
< sizeof(sd_id128_t
))
1585 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "RootHash= '%s' is too short: %m", eq
);
1587 return bus_append_byte_array(m
, field
, roothash_decoded
, roothash_decoded_size
);
1590 if (streq(field
, "RootHashSignature")) {
1591 _cleanup_free_
void *roothash_sig_decoded
= NULL
;
1593 size_t roothash_sig_decoded_size
= 0;
1595 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1596 if (path_is_absolute(eq
))
1597 return bus_append_string(m
, "RootHashSignaturePath", eq
);
1599 if (!(value
= startswith(eq
, "base64:")))
1600 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq
);
1602 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1603 r
= unbase64mem(value
, strlen(value
), &roothash_sig_decoded
, &roothash_sig_decoded_size
);
1605 return log_error_errno(r
, "Failed to decode RootHashSignature= '%s': %m", eq
);
1607 return bus_append_byte_array(m
, field
, roothash_sig_decoded
, roothash_sig_decoded_size
);
1610 if (streq(field
, "RootImageOptions")) {
1611 _cleanup_strv_free_
char **l
= NULL
;
1612 char **first
= NULL
, **second
= NULL
;
1615 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1617 return bus_log_create_error(r
);
1619 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1621 return bus_log_create_error(r
);
1623 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1625 return bus_log_create_error(r
);
1627 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1629 return bus_log_create_error(r
);
1631 r
= strv_split_colon_pairs(&l
, p
);
1633 return log_error_errno(r
, "Failed to parse argument: %m");
1635 STRV_FOREACH_PAIR(first
, second
, l
) {
1636 r
= sd_bus_message_append(m
, "(ss)",
1637 !isempty(*second
) ? *first
: "root",
1638 !isempty(*second
) ? *second
: *first
);
1640 return bus_log_create_error(r
);
1643 r
= sd_bus_message_close_container(m
);
1645 return bus_log_create_error(r
);
1647 r
= sd_bus_message_close_container(m
);
1649 return bus_log_create_error(r
);
1651 r
= sd_bus_message_close_container(m
);
1653 return bus_log_create_error(r
);
1658 if (streq(field
, "MountImages")) {
1661 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1663 return bus_log_create_error(r
);
1665 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1667 return bus_log_create_error(r
);
1669 r
= sd_bus_message_open_container(m
, 'v', "a(ssba(ss))");
1671 return bus_log_create_error(r
);
1673 r
= sd_bus_message_open_container(m
, 'a', "(ssba(ss))");
1675 return bus_log_create_error(r
);
1678 _cleanup_free_
char *first
= NULL
, *second
= NULL
, *tuple
= NULL
;
1679 const char *q
= NULL
, *source
= NULL
;
1680 bool permissive
= false;
1682 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1684 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1689 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &first
, &second
, NULL
);
1691 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1696 if (source
[0] == '-') {
1701 if (isempty(second
))
1702 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1703 "Missing argument after ':': %s",
1706 r
= sd_bus_message_open_container(m
, 'r', "ssba(ss)");
1708 return bus_log_create_error(r
);
1710 r
= sd_bus_message_append(m
, "ssb", source
, second
, permissive
);
1712 return bus_log_create_error(r
);
1714 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1716 return bus_log_create_error(r
);
1719 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1721 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
1723 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1726 /* Single set of options, applying to the root partition/single filesystem */
1728 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1730 return bus_log_create_error(r
);
1735 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
1737 return bus_log_create_error(r
);
1740 r
= sd_bus_message_close_container(m
);
1742 return bus_log_create_error(r
);
1744 r
= sd_bus_message_close_container(m
);
1746 return bus_log_create_error(r
);
1749 r
= sd_bus_message_close_container(m
);
1751 return bus_log_create_error(r
);
1753 r
= sd_bus_message_close_container(m
);
1755 return bus_log_create_error(r
);
1757 r
= sd_bus_message_close_container(m
);
1759 return bus_log_create_error(r
);
1764 if (streq(field
, "ExtensionImages")) {
1767 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1769 return bus_log_create_error(r
);
1771 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1773 return bus_log_create_error(r
);
1775 r
= sd_bus_message_open_container(m
, 'v', "a(sba(ss))");
1777 return bus_log_create_error(r
);
1779 r
= sd_bus_message_open_container(m
, 'a', "(sba(ss))");
1781 return bus_log_create_error(r
);
1784 _cleanup_free_
char *source
= NULL
, *tuple
= NULL
;
1785 const char *q
= NULL
, *s
= NULL
;
1786 bool permissive
= false;
1788 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1790 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1795 r
= extract_first_word(&q
, &source
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
);
1797 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1807 r
= sd_bus_message_open_container(m
, 'r', "sba(ss)");
1809 return bus_log_create_error(r
);
1811 r
= sd_bus_message_append(m
, "sb", s
, permissive
);
1813 return bus_log_create_error(r
);
1815 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1817 return bus_log_create_error(r
);
1820 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1822 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
1824 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
1827 /* Single set of options, applying to the root partition/single filesystem */
1829 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1831 return bus_log_create_error(r
);
1836 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
1838 return bus_log_create_error(r
);
1841 r
= sd_bus_message_close_container(m
);
1843 return bus_log_create_error(r
);
1845 r
= sd_bus_message_close_container(m
);
1847 return bus_log_create_error(r
);
1850 r
= sd_bus_message_close_container(m
);
1852 return bus_log_create_error(r
);
1854 r
= sd_bus_message_close_container(m
);
1856 return bus_log_create_error(r
);
1858 r
= sd_bus_message_close_container(m
);
1860 return bus_log_create_error(r
);
1868 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1869 if (streq(field
, "KillMode"))
1870 return bus_append_string(m
, field
, eq
);
1872 if (STR_IN_SET(field
, "SendSIGHUP",
1874 return bus_append_parse_boolean(m
, field
, eq
);
1876 if (STR_IN_SET(field
, "KillSignal",
1877 "RestartKillSignal",
1880 return bus_append_signal_from_string(m
, field
, eq
);
1885 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1887 if (STR_IN_SET(field
, "What",
1891 return bus_append_string(m
, field
, eq
);
1893 if (streq(field
, "TimeoutSec"))
1894 return bus_append_parse_sec_rename(m
, field
, eq
);
1896 if (streq(field
, "DirectoryMode"))
1897 return bus_append_parse_mode(m
, field
, eq
);
1899 if (STR_IN_SET(field
, "SloppyOptions",
1903 return bus_append_parse_boolean(m
, field
, eq
);
1908 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1911 if (streq(field
, "MakeDirectory"))
1912 return bus_append_parse_boolean(m
, field
, eq
);
1914 if (streq(field
, "DirectoryMode"))
1915 return bus_append_parse_mode(m
, field
, eq
);
1917 if (STR_IN_SET(field
, "PathExists",
1921 "DirectoryNotEmpty")) {
1923 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1925 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1927 return bus_log_create_error(r
);
1935 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1936 if (streq(field
, "RuntimeMaxSec"))
1937 return bus_append_parse_sec_rename(m
, field
, eq
);
1939 if (streq(field
, "TimeoutStopSec"))
1940 return bus_append_parse_sec_rename(m
, field
, eq
);
1945 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1948 if (STR_IN_SET(field
, "PIDFile",
1953 "USBFunctionDescriptors",
1954 "USBFunctionStrings",
1956 "TimeoutStartFailureMode",
1957 "TimeoutStopFailureMode"))
1958 return bus_append_string(m
, field
, eq
);
1960 if (STR_IN_SET(field
, "PermissionsStartOnly",
1961 "RootDirectoryStartOnly",
1964 return bus_append_parse_boolean(m
, field
, eq
);
1966 if (STR_IN_SET(field
, "RestartSec",
1972 return bus_append_parse_sec_rename(m
, field
, eq
);
1974 if (streq(field
, "TimeoutSec")) {
1975 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1979 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1982 if (streq(field
, "FileDescriptorStoreMax"))
1983 return bus_append_safe_atou(m
, field
, eq
);
1985 if (STR_IN_SET(field
, "ExecCondition",
1999 return bus_append_exec_command(m
, field
, eq
);
2001 if (STR_IN_SET(field
, "RestartPreventExitStatus",
2002 "RestartForceExitStatus",
2003 "SuccessExitStatus")) {
2004 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
2005 size_t n_status
= 0, n_signal
= 0;
2009 _cleanup_free_
char *word
= NULL
;
2011 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
2017 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
2019 /* We need to call exit_status_from_string() first, because we want
2020 * to parse numbers as exit statuses, not signals. */
2022 r
= exit_status_from_string(word
);
2024 assert(r
>= 0 && r
< 256);
2026 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
2030 status
[n_status
++] = r
;
2032 } else if ((r
= signal_from_string(word
)) >= 0) {
2033 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
2037 signal
[n_signal
++] = r
;
2040 /* original r from exit_status_to_string() */
2041 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
2045 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2047 return bus_log_create_error(r
);
2049 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2051 return bus_log_create_error(r
);
2053 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
2055 return bus_log_create_error(r
);
2057 r
= sd_bus_message_open_container(m
, 'r', "aiai");
2059 return bus_log_create_error(r
);
2061 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
2063 return bus_log_create_error(r
);
2065 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
2067 return bus_log_create_error(r
);
2069 r
= sd_bus_message_close_container(m
);
2071 return bus_log_create_error(r
);
2073 r
= sd_bus_message_close_container(m
);
2075 return bus_log_create_error(r
);
2077 r
= sd_bus_message_close_container(m
);
2079 return bus_log_create_error(r
);
2087 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2090 if (STR_IN_SET(field
, "Accept",
2103 "SELinuxContextFromNet"))
2104 return bus_append_parse_boolean(m
, field
, eq
);
2106 if (STR_IN_SET(field
, "Priority",
2109 return bus_append_safe_atoi(m
, field
, eq
);
2111 if (streq(field
, "IPTOS"))
2112 return bus_append_ip_tos_from_string(m
, field
, eq
);
2114 if (STR_IN_SET(field
, "Backlog",
2116 "MaxConnectionsPerSource",
2118 "TriggerLimitBurst"))
2119 return bus_append_safe_atou(m
, field
, eq
);
2121 if (STR_IN_SET(field
, "SocketMode",
2123 return bus_append_parse_mode(m
, field
, eq
);
2125 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
2126 "MessageQueueMessageSize"))
2127 return bus_append_safe_atoi64(m
, field
, eq
);
2129 if (STR_IN_SET(field
, "TimeoutSec",
2131 "KeepAliveIntervalSec",
2133 "TriggerLimitIntervalSec"))
2134 return bus_append_parse_sec_rename(m
, field
, eq
);
2136 if (STR_IN_SET(field
, "ReceiveBuffer",
2139 return bus_append_parse_size(m
, field
, eq
, 1024);
2141 if (STR_IN_SET(field
, "ExecStartPre",
2145 return bus_append_exec_command(m
, field
, eq
);
2147 if (STR_IN_SET(field
, "SmackLabel",
2153 "FileDescriptorName",
2157 return bus_append_string(m
, field
, eq
);
2159 if (streq(field
, "Symlinks"))
2160 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2162 if (streq(field
, "SocketProtocol"))
2163 return bus_append_parse_ip_protocol(m
, field
, eq
);
2165 if (STR_IN_SET(field
, "ListenStream",
2167 "ListenSequentialPacket",
2170 "ListenMessageQueue",
2172 "ListenUSBFunction")) {
2174 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
2176 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
2178 return bus_log_create_error(r
);
2185 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2188 if (STR_IN_SET(field
, "WakeSystem",
2189 "RemainAfterElapse",
2193 "FixedRandomDelay"))
2194 return bus_append_parse_boolean(m
, field
, eq
);
2196 if (STR_IN_SET(field
, "AccuracySec",
2197 "RandomizedDelaySec"))
2198 return bus_append_parse_sec_rename(m
, field
, eq
);
2200 if (STR_IN_SET(field
, "OnActiveSec",
2204 "OnUnitInactiveSec")) {
2206 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
2209 r
= parse_sec(eq
, &t
);
2211 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
2213 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
2216 return bus_log_create_error(r
);
2221 if (streq(field
, "OnCalendar")) {
2223 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
2225 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
2227 return bus_log_create_error(r
);
2235 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2236 ConditionType t
= _CONDITION_TYPE_INVALID
;
2237 bool is_condition
= false;
2240 if (STR_IN_SET(field
, "Description",
2244 "JobTimeoutRebootArgument",
2250 return bus_append_string(m
, field
, eq
);
2252 if (STR_IN_SET(field
, "StopWhenUnneeded",
2253 "RefuseManualStart",
2257 "DefaultDependencies"))
2258 return bus_append_parse_boolean(m
, field
, eq
);
2260 if (STR_IN_SET(field
, "JobTimeoutSec",
2261 "JobRunningTimeoutSec",
2262 "StartLimitIntervalSec"))
2263 return bus_append_parse_sec_rename(m
, field
, eq
);
2265 if (streq(field
, "StartLimitBurst"))
2266 return bus_append_safe_atou(m
, field
, eq
);
2268 if (STR_IN_SET(field
, "SuccessActionExitStatus",
2269 "FailureActionExitStatus")) {
2271 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
2275 r
= safe_atou8(eq
, &u
);
2277 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
2279 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
2282 return bus_log_create_error(r
);
2287 if (unit_dependency_from_string(field
) >= 0 ||
2288 STR_IN_SET(field
, "Documentation",
2289 "RequiresMountsFor",
2291 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2293 t
= condition_type_from_string(field
);
2295 is_condition
= true;
2297 t
= assert_type_from_string(field
);
2300 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
2303 int trigger
, negate
;
2305 trigger
= *p
== '|';
2313 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
2314 field
, trigger
, negate
, p
);
2317 return bus_log_create_error(r
);
2325 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
2326 const char *eq
, *field
;
2332 eq
= strchr(assignment
, '=');
2334 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2335 "Not an assignment: %s", assignment
);
2337 field
= strndupa(assignment
, eq
- assignment
);
2342 r
= bus_append_cgroup_property(m
, field
, eq
);
2346 r
= bus_append_execute_property(m
, field
, eq
);
2350 r
= bus_append_kill_property(m
, field
, eq
);
2354 r
= bus_append_service_property(m
, field
, eq
);
2360 r
= bus_append_cgroup_property(m
, field
, eq
);
2364 r
= bus_append_execute_property(m
, field
, eq
);
2368 r
= bus_append_kill_property(m
, field
, eq
);
2372 r
= bus_append_socket_property(m
, field
, eq
);
2378 r
= bus_append_timer_property(m
, field
, eq
);
2384 r
= bus_append_path_property(m
, field
, eq
);
2390 r
= bus_append_cgroup_property(m
, field
, eq
);
2396 r
= bus_append_cgroup_property(m
, field
, eq
);
2400 r
= bus_append_kill_property(m
, field
, eq
);
2404 r
= bus_append_scope_property(m
, field
, eq
);
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_mount_property(m
, field
, eq
);
2428 case UNIT_AUTOMOUNT
:
2429 r
= bus_append_automount_property(m
, field
, eq
);
2438 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2439 "Not supported unit type");
2442 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2443 "Invalid unit type");
2446 r
= bus_append_unit_property(m
, field
, eq
);
2450 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2451 "Unknown assignment: %s", assignment
);
2454 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
2460 STRV_FOREACH(i
, l
) {
2461 r
= bus_append_unit_property_assignment(m
, t
, *i
);
2469 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
2470 const char *type
, *path
, *source
;
2473 /* changes is dereferenced when calling unit_file_dump_changes() later,
2474 * so we have to make sure this is not NULL. */
2478 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2480 return bus_log_parse_error(r
);
2482 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2483 /* We expect only "success" changes to be sent over the bus.
2484 Hence, reject anything negative. */
2485 int ch
= unit_file_change_type_from_string(type
);
2487 log_notice_errno(ch
, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2492 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2497 return bus_log_parse_error(r
);
2499 r
= sd_bus_message_exit_container(m
);
2501 return bus_log_parse_error(r
);
2503 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2507 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2508 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2509 _cleanup_free_
char *path
= NULL
;
2512 path
= unit_dbus_path_from_name(name
);
2516 /* This function warns on it's own, because otherwise it'd be awkward to pass
2517 * the dbus error message around. */
2519 r
= sd_bus_get_property_string(
2521 "org.freedesktop.systemd1",
2523 "org.freedesktop.systemd1.Unit",
2528 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));
2533 int unit_info_compare(const UnitInfo
*a
, const UnitInfo
*b
) {
2536 /* First, order by machine */
2537 r
= strcasecmp_ptr(a
->machine
, b
->machine
);
2541 /* Second, order by unit type */
2542 r
= strcasecmp_ptr(strrchr(a
->id
, '.'), strrchr(b
->id
, '.'));
2546 /* Third, order by name */
2547 return strcasecmp(a
->id
, b
->id
);