1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "alloc-util.h"
6 #include "bus-locator.h"
7 #include "bus-unit-util.h"
10 #include "cgroup-setup.h"
11 #include "cgroup-util.h"
12 #include "condition.h"
13 #include "coredump-util.h"
14 #include "cpu-set-util.h"
15 #include "dissect-image.h"
17 #include "exec-util.h"
18 #include "exit-status.h"
20 #include "firewall-util.h"
21 #include "hexdecoct.h"
22 #include "hostname-util.h"
23 #include "in-addr-util.h"
24 #include "ioprio-util.h"
25 #include "ip-protocol-list.h"
26 #include "libmount-util.h"
27 #include "locale-util.h"
30 #include "missing_fs.h"
31 #include "mountpoint-util.h"
33 #include "numa-util.h"
34 #include "open-file.h"
35 #include "parse-helpers.h"
36 #include "parse-util.h"
37 #include "path-util.h"
38 #include "percent-util.h"
39 #include "process-util.h"
40 #include "rlimit-util.h"
41 #include "seccomp-util.h"
42 #include "securebits-util.h"
43 #include "signal-util.h"
44 #include "socket-util.h"
45 #include "sort-util.h"
46 #include "stdio-util.h"
47 #include "string-util.h"
48 #include "syslog-util.h"
49 #include "terminal-util.h"
51 #include "user-util.h"
54 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
60 return sd_bus_message_read(
75 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
76 static int bus_append_##parse_func( \
83 r = parse_func(eq, &val); \
85 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
87 r = sd_bus_message_append(m, "(sv)", field, \
88 bus_type, (cast_type) val); \
90 return bus_log_create_error(r); \
95 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
96 static int bus_append_##parse_func( \
102 r = parse_func(eq); \
104 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
106 r = sd_bus_message_append(m, "(sv)", field, \
107 bus_type, (int32_t) r); \
109 return bus_log_create_error(r); \
114 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
115 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
116 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
117 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
118 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
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, uint64_t, cg_cpu_weight_parse
);
132 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flag_from_string
);
133 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
134 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
135 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
136 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
137 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
139 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
142 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
144 return bus_log_create_error(r
);
149 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
153 r
= sd_bus_message_open_container(m
, 'r', "sv");
155 return bus_log_create_error(r
);
157 r
= sd_bus_message_append_basic(m
, 's', field
);
159 return bus_log_create_error(r
);
161 r
= sd_bus_message_open_container(m
, 'v', "as");
163 return bus_log_create_error(r
);
165 r
= sd_bus_message_open_container(m
, 'a', "s");
167 return bus_log_create_error(r
);
170 _cleanup_free_
char *word
= NULL
;
172 r
= extract_first_word(&p
, &word
, NULL
, flags
);
178 return log_error_errno(r
, "Invalid syntax: %s", eq
);
180 r
= sd_bus_message_append_basic(m
, 's', word
);
182 return bus_log_create_error(r
);
185 r
= sd_bus_message_close_container(m
);
187 return bus_log_create_error(r
);
189 r
= sd_bus_message_close_container(m
);
191 return bus_log_create_error(r
);
193 r
= sd_bus_message_close_container(m
);
195 return bus_log_create_error(r
);
200 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
203 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
205 return bus_log_create_error(r
);
207 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
209 return bus_log_create_error(r
);
211 r
= sd_bus_message_open_container(m
, 'v', "ay");
213 return bus_log_create_error(r
);
215 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
217 return bus_log_create_error(r
);
219 r
= sd_bus_message_close_container(m
);
221 return bus_log_create_error(r
);
223 r
= sd_bus_message_close_container(m
);
225 return bus_log_create_error(r
);
230 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
236 r
= parse_sec(eq
, &t
);
238 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
241 n
= newa(char, l
+ 2);
242 /* Change suffix Sec → USec */
243 strcpy(mempcpy(n
, field
, l
- 3), "USec");
245 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
247 return bus_log_create_error(r
);
252 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
256 r
= parse_size(eq
, base
, &v
);
258 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
260 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
262 return bus_log_create_error(r
);
267 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
268 bool explicit_path
= false, done
= false;
269 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
270 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
271 ExecCommandFlags flags
= 0;
272 bool is_ex_prop
= endswith(field
, "Ex");
279 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
282 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
291 explicit_path
= true;
297 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
300 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
306 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
309 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
315 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
317 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
318 flags
&= ~EXEC_COMMAND_NO_SETUID
;
319 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
322 flags
|= EXEC_COMMAND_NO_SETUID
;
333 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
334 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
336 upgraded_name
= strjoin(field
, "Ex");
342 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
344 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
348 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
350 return log_error_errno(r
, "Failed to parse path: %m");
353 r
= strv_split_full(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
355 return log_error_errno(r
, "Failed to parse command line: %m");
357 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
359 return bus_log_create_error(r
);
361 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
363 return bus_log_create_error(r
);
365 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
367 return bus_log_create_error(r
);
369 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
371 return bus_log_create_error(r
);
373 if (!strv_isempty(l
)) {
375 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
377 return bus_log_create_error(r
);
379 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
381 return bus_log_create_error(r
);
383 r
= sd_bus_message_append_strv(m
, l
);
385 return bus_log_create_error(r
);
387 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
));
389 return bus_log_create_error(r
);
391 r
= sd_bus_message_close_container(m
);
393 return bus_log_create_error(r
);
396 r
= sd_bus_message_close_container(m
);
398 return bus_log_create_error(r
);
400 r
= sd_bus_message_close_container(m
);
402 return bus_log_create_error(r
);
404 r
= sd_bus_message_close_container(m
);
406 return bus_log_create_error(r
);
411 static int bus_append_open_file(sd_bus_message
*m
, const char *field
, const char *eq
) {
412 _cleanup_(open_file_freep
) OpenFile
*of
= NULL
;
417 r
= open_file_parse(eq
, &of
);
419 return log_error_errno(r
, "Failed to parse OpenFile= setting: %m");
421 r
= sd_bus_message_append(m
, "(sv)", field
, "a(sst)", (size_t) 1, of
->path
, of
->fdname
, of
->flags
);
423 return bus_log_create_error(r
);
428 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
434 r
= sd_bus_message_open_container(m
, 'r', "iayu");
438 r
= sd_bus_message_append(m
, "i", family
);
442 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
446 r
= sd_bus_message_append(m
, "u", prefixlen
);
450 return sd_bus_message_close_container(m
);
453 static int bus_append_nft_set(sd_bus_message
*m
, const char *field
, const char *eq
) {
461 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iiss)", 0);
463 return bus_log_create_error(r
);
468 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
470 return bus_log_create_error(r
);
472 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
474 return bus_log_create_error(r
);
476 r
= sd_bus_message_open_container(m
, 'v', "a(iiss)");
478 return bus_log_create_error(r
);
480 r
= sd_bus_message_open_container(m
, 'a', "(iiss)");
482 return bus_log_create_error(r
);
484 for (const char *p
= eq
;;) {
485 _cleanup_free_
char *tuple
= NULL
, *source_str
= NULL
, *nfproto_str
= NULL
, *table
= NULL
, *set
= NULL
;
486 const char *q
= NULL
;
489 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
493 return log_error_errno(r
, "Failed to parse %s: %m", field
);
497 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse %s", field
);
500 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
, &source_str
, &nfproto_str
, &table
, &set
);
503 if (r
!= 4 || !isempty(q
))
504 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse %s", field
);
511 source
= nft_set_source_from_string(source_str
);
512 if (!IN_SET(source
, NFT_SET_SOURCE_CGROUP
, NFT_SET_SOURCE_USER
, NFT_SET_SOURCE_GROUP
))
513 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse %s", field
);
515 nfproto
= nfproto_from_string(nfproto_str
);
516 if (nfproto
< 0 || !nft_identifier_valid(table
) || !nft_identifier_valid(set
))
517 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse %s", field
);
519 r
= sd_bus_message_append(m
, "(iiss)", source
, nfproto
, table
, set
);
521 return bus_log_create_error(r
);
523 r
= sd_bus_message_close_container(m
);
525 return bus_log_create_error(r
);
527 r
= sd_bus_message_close_container(m
);
529 return bus_log_create_error(r
);
531 r
= sd_bus_message_close_container(m
);
533 return bus_log_create_error(r
);
538 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
541 if (STR_IN_SET(field
, "DevicePolicy",
544 "ManagedOOMMemoryPressure",
545 "ManagedOOMPreference",
546 "MemoryPressureWatch",
548 return bus_append_string(m
, field
, eq
);
550 if (STR_IN_SET(field
, "ManagedOOMMemoryPressureLimit")) {
551 r
= parse_permyriad(eq
);
553 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
555 /* Pass around scaled to 2^32-1 == 100% */
556 r
= sd_bus_message_append(m
, "(sv)", field
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
558 return bus_log_create_error(r
);
563 if (STR_IN_SET(field
, "CPUAccounting",
565 "MemoryZSwapWriteback",
571 return bus_append_parse_boolean(m
, field
, eq
);
573 if (STR_IN_SET(field
, "CPUWeight",
575 return bus_append_cg_cpu_weight_parse(m
, field
, eq
);
577 if (STR_IN_SET(field
, "IOWeight",
579 return bus_append_cg_weight_parse(m
, field
, eq
);
581 if (STR_IN_SET(field
, "CPUShares",
583 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
585 if (STR_IN_SET(field
, "AllowedCPUs",
586 "StartupAllowedCPUs",
587 "AllowedMemoryNodes",
588 "StartupAllowedMemoryNodes")) {
589 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
590 _cleanup_free_
uint8_t *array
= NULL
;
593 r
= parse_cpu_set(eq
, &cpuset
);
595 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
597 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
599 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
601 return bus_append_byte_array(m
, field
, array
, allocated
);
604 if (STR_IN_SET(field
, "BlockIOWeight",
605 "StartupBlockIOWeight"))
606 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
608 if (streq(field
, "DisableControllers"))
609 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
611 if (streq(field
, "Delegate")) {
612 r
= parse_boolean(eq
);
614 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
616 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
618 return bus_log_create_error(r
);
623 if (STR_IN_SET(field
, "MemoryMin",
634 if (streq(eq
, "infinity")) {
635 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
637 return bus_log_create_error(r
);
639 } else if (isempty(eq
)) {
640 uint64_t empty_value
= STR_IN_SET(field
,
648 r
= sd_bus_message_append(m
, "(sv)", field
, "t", empty_value
);
650 return bus_log_create_error(r
);
654 r
= parse_permyriad(eq
);
658 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
659 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
660 * size can be determined server-side. */
662 n
= strjoina(field
, "Scale");
663 r
= sd_bus_message_append(m
, "(sv)", n
, "u", UINT32_SCALE_FROM_PERMYRIAD(r
));
665 return bus_log_create_error(r
);
670 if (streq(field
, "TasksMax"))
671 return bus_append_safe_atou64(m
, field
, eq
);
673 return bus_append_parse_size(m
, field
, eq
, 1024);
676 if (streq(field
, "CPUQuota")) {
678 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
680 r
= parse_permyriad_unbounded(eq
);
682 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
683 "CPU quota too small.");
685 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
687 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 10000U));
691 return bus_log_create_error(r
);
696 if (streq(field
, "CPUQuotaPeriodSec")) {
697 usec_t u
= USEC_INFINITY
;
699 r
= parse_sec_def_infinity(eq
, &u
);
701 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
703 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
705 return bus_log_create_error(r
);
710 if (streq(field
, "DeviceAllow")) {
712 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
714 const char *path
= eq
, *rwm
= NULL
, *e
;
718 path
= strndupa_safe(eq
, e
- eq
);
722 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
726 return bus_log_create_error(r
);
731 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
733 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
735 const char *path
, *bandwidth
, *e
;
740 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
741 "Failed to parse %s value %s.",
744 path
= strndupa_safe(eq
, e
- eq
);
747 if (streq(bandwidth
, "infinity"))
748 bytes
= CGROUP_LIMIT_MAX
;
750 r
= parse_size(bandwidth
, 1000, &bytes
);
752 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
755 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
759 return bus_log_create_error(r
);
764 if (STR_IN_SET(field
, "IODeviceWeight",
765 "BlockIODeviceWeight")) {
767 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
769 const char *path
, *weight
, *e
;
774 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
775 "Failed to parse %s value %s.",
778 path
= strndupa_safe(eq
, e
- eq
);
781 r
= safe_atou64(weight
, &u
);
783 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
785 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
789 return bus_log_create_error(r
);
794 if (streq(field
, "IODeviceLatencyTargetSec")) {
795 const char *field_usec
= "IODeviceLatencyTargetUSec";
798 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
800 const char *path
, *target
, *e
;
805 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
806 "Failed to parse %s value %s.",
809 path
= strndupa_safe(eq
, e
- eq
);
812 r
= parse_sec(target
, &usec
);
814 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
816 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
820 return bus_log_create_error(r
);
825 if (STR_IN_SET(field
, "IPAddressAllow",
827 unsigned char prefixlen
;
828 union in_addr_union prefix
= {};
832 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
834 return bus_log_create_error(r
);
839 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
841 return bus_log_create_error(r
);
843 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
845 return bus_log_create_error(r
);
847 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
849 return bus_log_create_error(r
);
851 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
853 return bus_log_create_error(r
);
855 if (streq(eq
, "any")) {
856 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
858 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
860 return bus_log_create_error(r
);
862 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
864 return bus_log_create_error(r
);
866 } else if (is_localhost(eq
)) {
867 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
869 prefix
.in
.s_addr
= htobe32(0x7f000000);
870 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
872 return bus_log_create_error(r
);
874 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
875 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
879 } else if (streq(eq
, "link-local")) {
880 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
882 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
883 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
885 return bus_log_create_error(r
);
887 prefix
.in6
= (struct in6_addr
) {
888 .s6_addr32
[0] = htobe32(0xfe800000)
890 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
892 return bus_log_create_error(r
);
894 } else if (streq(eq
, "multicast")) {
895 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
897 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
898 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
900 return bus_log_create_error(r
);
902 prefix
.in6
= (struct in6_addr
) {
903 .s6_addr32
[0] = htobe32(0xff000000)
905 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
907 return bus_log_create_error(r
);
911 _cleanup_free_
char *word
= NULL
;
913 r
= extract_first_word(&eq
, &word
, NULL
, 0);
919 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
921 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
923 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
925 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
927 return bus_log_create_error(r
);
931 r
= sd_bus_message_close_container(m
);
933 return bus_log_create_error(r
);
935 r
= sd_bus_message_close_container(m
);
937 return bus_log_create_error(r
);
939 r
= sd_bus_message_close_container(m
);
941 return bus_log_create_error(r
);
946 if (STR_IN_SET(field
, "IPIngressFilterPath",
947 "IPEgressFilterPath")) {
949 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
951 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
954 return bus_log_create_error(r
);
959 if (streq(field
, "BPFProgram")) {
961 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
963 _cleanup_free_
char *word
= NULL
;
965 r
= extract_first_word(&eq
, &word
, ":", 0);
969 return log_error_errno(r
, "Failed to parse %s: %m", field
);
971 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, word
, eq
);
974 return bus_log_create_error(r
);
979 if (STR_IN_SET(field
, "SocketBindAllow",
982 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iiqq)", 0);
984 int32_t family
, ip_protocol
;
985 uint16_t nr_ports
, port_min
;
987 r
= parse_socket_bind_item(eq
, &family
, &ip_protocol
, &nr_ports
, &port_min
);
991 return log_error_errno(r
, "Failed to parse %s", field
);
993 r
= sd_bus_message_append(
994 m
, "(sv)", field
, "a(iiqq)", 1, family
, ip_protocol
, nr_ports
, port_min
);
997 return bus_log_create_error(r
);
1002 if (streq(field
, "MemoryPressureThresholdSec"))
1003 return bus_append_parse_sec_rename(m
, field
, eq
);
1005 if (streq(field
, "NFTSet"))
1006 return bus_append_nft_set(m
, field
, eq
);
1011 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1012 if (STR_IN_SET(field
, "Where",
1014 return bus_append_string(m
, field
, eq
);
1016 if (streq(field
, "DirectoryMode"))
1017 return bus_append_parse_mode(m
, field
, eq
);
1019 if (streq(field
, "TimeoutIdleSec"))
1020 return bus_append_parse_sec_rename(m
, field
, eq
);
1025 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1029 if (STR_IN_SET(field
, "User",
1043 "RuntimeDirectoryPreserve",
1048 "NetworkNamespacePath",
1053 "ExtensionImagePolicy"))
1054 return bus_append_string(m
, field
, eq
);
1056 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
1067 "SyslogLevelPrefix",
1068 "MemoryDenyWriteExecute",
1072 "ProtectKernelTunables",
1073 "ProtectKernelModules",
1074 "ProtectKernelLogs",
1076 "ProtectControlGroups",
1078 "CPUSchedulingResetOnFork",
1084 "SetLoginEnvironment"))
1085 return bus_append_parse_boolean(m
, field
, eq
);
1087 if (STR_IN_SET(field
, "ReadWriteDirectories",
1088 "ReadOnlyDirectories",
1089 "InaccessibleDirectories",
1092 "InaccessiblePaths",
1096 "ExtensionDirectories",
1097 "ConfigurationDirectory",
1098 "SupplementaryGroups",
1099 "SystemCallArchitectures"))
1100 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
1102 if (STR_IN_SET(field
, "SyslogLevel",
1104 return bus_append_log_level_from_string(m
, field
, eq
);
1106 if (streq(field
, "SyslogFacility"))
1107 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
1109 if (streq(field
, "SecureBits"))
1110 return bus_append_secure_bits_from_string(m
, field
, eq
);
1112 if (streq(field
, "CPUSchedulingPolicy"))
1113 return bus_append_sched_policy_from_string(m
, field
, eq
);
1115 if (STR_IN_SET(field
, "CPUSchedulingPriority",
1117 return bus_append_safe_atoi(m
, field
, eq
);
1119 if (streq(field
, "CoredumpFilter"))
1120 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
1122 if (streq(field
, "Nice"))
1123 return bus_append_parse_nice(m
, field
, eq
);
1125 if (streq(field
, "SystemCallErrorNumber"))
1126 return bus_append_seccomp_parse_errno_or_action(m
, field
, eq
);
1128 if (streq(field
, "IOSchedulingClass"))
1129 return bus_append_ioprio_class_from_string(m
, field
, eq
);
1131 if (streq(field
, "IOSchedulingPriority"))
1132 return bus_append_ioprio_parse_priority(m
, field
, eq
);
1134 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
1135 "StateDirectoryMode",
1136 "CacheDirectoryMode",
1137 "LogsDirectoryMode",
1138 "ConfigurationDirectoryMode",
1140 return bus_append_parse_mode(m
, field
, eq
);
1142 if (streq(field
, "TimerSlackNSec"))
1143 return bus_append_parse_nsec(m
, field
, eq
);
1145 if (streq(field
, "LogRateLimitIntervalSec"))
1146 return bus_append_parse_sec_rename(m
, field
, eq
);
1148 if (STR_IN_SET(field
, "LogRateLimitBurst",
1151 return bus_append_safe_atou(m
, field
, eq
);
1153 if (streq(field
, "MountFlags"))
1154 return bus_append_mount_propagation_flag_from_string(m
, field
, eq
);
1156 if (STR_IN_SET(field
, "Environment",
1159 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
1161 if (streq(field
, "EnvironmentFile")) {
1163 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1165 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1166 eq
[0] == '-' ? eq
+ 1 : eq
,
1169 return bus_log_create_error(r
);
1174 if (STR_IN_SET(field
, "SetCredential", "SetCredentialEncrypted")) {
1175 r
= sd_bus_message_open_container(m
, 'r', "sv");
1177 return bus_log_create_error(r
);
1179 r
= sd_bus_message_append_basic(m
, 's', field
);
1181 return bus_log_create_error(r
);
1183 r
= sd_bus_message_open_container(m
, 'v', "a(say)");
1185 return bus_log_create_error(r
);
1188 r
= sd_bus_message_append(m
, "a(say)", 0);
1190 _cleanup_free_
char *word
= NULL
;
1193 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1197 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1199 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1201 r
= sd_bus_message_open_container(m
, 'a', "(say)");
1203 return bus_log_create_error(r
);
1205 r
= sd_bus_message_open_container(m
, 'r', "say");
1207 return bus_log_create_error(r
);
1209 r
= sd_bus_message_append(m
, "s", word
);
1211 return bus_log_create_error(r
);
1213 if (streq(field
, "SetCredentialEncrypted")) {
1214 _cleanup_free_
void *decoded
= NULL
;
1215 size_t decoded_size
;
1217 r
= unbase64mem(p
, &decoded
, &decoded_size
);
1219 return log_error_errno(r
, "Failed to base64 decode encrypted credential: %m");
1221 r
= sd_bus_message_append_array(m
, 'y', decoded
, decoded_size
);
1223 _cleanup_free_
char *unescaped
= NULL
;
1226 l
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &unescaped
);
1228 return log_error_errno(l
, "Failed to unescape %s= value: %s", field
, p
);
1230 r
= sd_bus_message_append_array(m
, 'y', unescaped
, l
);
1233 return bus_log_create_error(r
);
1235 r
= sd_bus_message_close_container(m
);
1237 return bus_log_create_error(r
);
1239 r
= sd_bus_message_close_container(m
);
1242 return bus_log_create_error(r
);
1244 r
= sd_bus_message_close_container(m
);
1246 return bus_log_create_error(r
);
1248 r
= sd_bus_message_close_container(m
);
1250 return bus_log_create_error(r
);
1255 if (STR_IN_SET(field
, "LoadCredential", "LoadCredentialEncrypted")) {
1256 r
= sd_bus_message_open_container(m
, 'r', "sv");
1258 return bus_log_create_error(r
);
1260 r
= sd_bus_message_append_basic(m
, 's', field
);
1262 return bus_log_create_error(r
);
1264 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1266 return bus_log_create_error(r
);
1269 r
= sd_bus_message_append(m
, "a(ss)", 0);
1271 _cleanup_free_
char *word
= NULL
;
1274 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1278 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
1280 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to %s=.", field
);
1282 if (isempty(p
)) /* If only one field is specified, then this means "inherit from above" */
1285 r
= sd_bus_message_append(m
, "a(ss)", 1, word
, p
);
1288 return bus_log_create_error(r
);
1290 r
= sd_bus_message_close_container(m
);
1292 return bus_log_create_error(r
);
1294 r
= sd_bus_message_close_container(m
);
1296 return bus_log_create_error(r
);
1301 if (streq(field
, "ImportCredential")) {
1303 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
1305 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
1307 return bus_log_create_error(r
);
1312 if (streq(field
, "LogExtraFields")) {
1313 r
= sd_bus_message_open_container(m
, 'r', "sv");
1315 return bus_log_create_error(r
);
1317 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
1319 return bus_log_create_error(r
);
1321 r
= sd_bus_message_open_container(m
, 'v', "aay");
1323 return bus_log_create_error(r
);
1325 r
= sd_bus_message_open_container(m
, 'a', "ay");
1327 return bus_log_create_error(r
);
1329 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
1331 return bus_log_create_error(r
);
1333 r
= sd_bus_message_close_container(m
);
1335 return bus_log_create_error(r
);
1337 r
= sd_bus_message_close_container(m
);
1339 return bus_log_create_error(r
);
1341 r
= sd_bus_message_close_container(m
);
1343 return bus_log_create_error(r
);
1348 if (streq(field
, "LogFilterPatterns")) {
1349 r
= sd_bus_message_append(m
, "(sv)", "LogFilterPatterns", "a(bs)", 1,
1351 eq
[0] != '~' ? eq
: eq
+ 1);
1353 return bus_log_create_error(r
);
1358 if (STR_IN_SET(field
, "StandardInput",
1361 const char *n
, *appended
;
1363 if ((n
= startswith(eq
, "fd:"))) {
1364 appended
= strjoina(field
, "FileDescriptorName");
1365 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1366 } else if ((n
= startswith(eq
, "file:"))) {
1367 appended
= strjoina(field
, "File");
1368 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1369 } else if ((n
= startswith(eq
, "append:"))) {
1370 appended
= strjoina(field
, "FileToAppend");
1371 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1372 } else if ((n
= startswith(eq
, "truncate:"))) {
1373 appended
= strjoina(field
, "FileToTruncate");
1374 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1376 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1378 return bus_log_create_error(r
);
1383 if (streq(field
, "StandardInputText")) {
1384 _cleanup_free_
char *unescaped
= NULL
;
1387 l
= cunescape(eq
, 0, &unescaped
);
1389 return log_error_errno(l
, "Failed to unescape text '%s': %m", eq
);
1391 if (!strextend(&unescaped
, "\n"))
1394 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1395 * programmatic interface anyway */
1397 return bus_append_byte_array(m
, field
, unescaped
, l
+ 1);
1400 if (streq(field
, "StandardInputData")) {
1401 _cleanup_free_
void *decoded
= NULL
;
1404 r
= unbase64mem(eq
, &decoded
, &sz
);
1406 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1408 return bus_append_byte_array(m
, field
, decoded
, sz
);
1411 if ((suffix
= startswith(field
, "Limit"))) {
1414 rl
= rlimit_from_string(suffix
);
1419 r
= rlimit_parse(rl
, eq
, &l
);
1421 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1423 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) l
.rlim_max
);
1425 return bus_log_create_error(r
);
1427 sn
= strjoina(field
, "Soft");
1428 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", (uint64_t) l
.rlim_cur
);
1430 return bus_log_create_error(r
);
1436 if (STR_IN_SET(field
, "AppArmorProfile",
1437 "SmackProcessLabel")) {
1446 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1448 return bus_log_create_error(r
);
1453 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1454 "AmbientCapabilities")) {
1456 bool invert
= false;
1464 r
= capability_set_from_string(p
, &sum
);
1466 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1468 sum
= invert
? ~sum
: sum
;
1470 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1472 return bus_log_create_error(r
);
1477 if (streq(field
, "CPUAffinity")) {
1478 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1479 _cleanup_free_
uint8_t *array
= NULL
;
1482 if (eq
&& streq(eq
, "numa")) {
1483 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1485 return bus_log_create_error(r
);
1489 r
= parse_cpu_set(eq
, &cpuset
);
1491 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1493 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1495 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1497 return bus_append_byte_array(m
, field
, array
, allocated
);
1500 if (streq(field
, "NUMAPolicy")) {
1501 r
= mpol_from_string(eq
);
1503 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1505 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1507 return bus_log_create_error(r
);
1512 if (streq(field
, "NUMAMask")) {
1513 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1514 _cleanup_free_
uint8_t *array
= NULL
;
1517 if (eq
&& streq(eq
, "all")) {
1518 r
= numa_mask_add_all(&nodes
);
1520 return log_error_errno(r
, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1522 r
= parse_cpu_set(eq
, &nodes
);
1524 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1527 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1529 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1531 return bus_append_byte_array(m
, field
, array
, allocated
);
1534 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1535 "RestrictFileSystems",
1538 "RestrictNetworkInterfaces")) {
1547 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1549 return bus_log_create_error(r
);
1551 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1553 return bus_log_create_error(r
);
1555 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1557 return bus_log_create_error(r
);
1559 r
= sd_bus_message_open_container(m
, 'r', "bas");
1561 return bus_log_create_error(r
);
1563 r
= sd_bus_message_append_basic(m
, 'b', &allow_list
);
1565 return bus_log_create_error(r
);
1567 r
= sd_bus_message_open_container(m
, 'a', "s");
1569 return bus_log_create_error(r
);
1572 _cleanup_free_
char *word
= NULL
;
1574 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1580 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1582 r
= sd_bus_message_append_basic(m
, 's', word
);
1584 return bus_log_create_error(r
);
1587 r
= sd_bus_message_close_container(m
);
1589 return bus_log_create_error(r
);
1591 r
= sd_bus_message_close_container(m
);
1593 return bus_log_create_error(r
);
1595 r
= sd_bus_message_close_container(m
);
1597 return bus_log_create_error(r
);
1599 r
= sd_bus_message_close_container(m
);
1601 return bus_log_create_error(r
);
1606 if (streq(field
, "RestrictNamespaces")) {
1607 bool invert
= false;
1608 unsigned long flags
;
1610 r
= parse_boolean(eq
);
1614 flags
= NAMESPACE_FLAGS_ALL
;
1621 r
= namespace_flags_from_string(eq
, &flags
);
1623 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1627 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1629 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1631 return bus_log_create_error(r
);
1636 if (STR_IN_SET(field
, "BindPaths",
1637 "BindReadOnlyPaths")) {
1640 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1642 return bus_log_create_error(r
);
1644 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1646 return bus_log_create_error(r
);
1648 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1650 return bus_log_create_error(r
);
1652 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1654 return bus_log_create_error(r
);
1657 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1658 char *s
= NULL
, *d
= NULL
;
1659 bool ignore_enoent
= false;
1660 uint64_t flags
= MS_REC
;
1662 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1664 return log_error_errno(r
, "Failed to parse argument: %m");
1670 ignore_enoent
= true;
1674 if (p
&& p
[-1] == ':') {
1675 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1677 return log_error_errno(r
, "Failed to parse argument: %m");
1679 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1680 "Missing argument after ':': %s",
1685 if (p
&& p
[-1] == ':') {
1686 _cleanup_free_
char *options
= NULL
;
1688 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1690 return log_error_errno(r
, "Failed to parse argument: %m");
1692 if (isempty(options
) || streq(options
, "rbind"))
1694 else if (streq(options
, "norbind"))
1697 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1698 "Unknown options: %s",
1704 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1706 return bus_log_create_error(r
);
1709 r
= sd_bus_message_close_container(m
);
1711 return bus_log_create_error(r
);
1713 r
= sd_bus_message_close_container(m
);
1715 return bus_log_create_error(r
);
1717 r
= sd_bus_message_close_container(m
);
1719 return bus_log_create_error(r
);
1724 if (streq(field
, "TemporaryFileSystem")) {
1727 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1729 return bus_log_create_error(r
);
1731 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1733 return bus_log_create_error(r
);
1735 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1737 return bus_log_create_error(r
);
1739 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1741 return bus_log_create_error(r
);
1744 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1747 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1749 return log_error_errno(r
, "Failed to parse argument: %m");
1754 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1756 return log_error_errno(r
, "Failed to parse argument: %m");
1758 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1759 "Failed to parse argument: %s",
1762 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1764 return bus_log_create_error(r
);
1767 r
= sd_bus_message_close_container(m
);
1769 return bus_log_create_error(r
);
1771 r
= sd_bus_message_close_container(m
);
1773 return bus_log_create_error(r
);
1775 r
= sd_bus_message_close_container(m
);
1777 return bus_log_create_error(r
);
1782 if (streq(field
, "RootHash")) {
1783 _cleanup_free_
void *roothash_decoded
= NULL
;
1784 size_t roothash_decoded_size
= 0;
1786 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1787 if (path_is_absolute(eq
))
1788 return bus_append_string(m
, "RootHashPath", eq
);
1790 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1791 r
= unhexmem(eq
, &roothash_decoded
, &roothash_decoded_size
);
1793 return log_error_errno(r
, "Failed to decode RootHash= '%s': %m", eq
);
1794 if (roothash_decoded_size
< sizeof(sd_id128_t
))
1795 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "RootHash= '%s' is too short: %m", eq
);
1797 return bus_append_byte_array(m
, field
, roothash_decoded
, roothash_decoded_size
);
1800 if (streq(field
, "RootHashSignature")) {
1801 _cleanup_free_
void *roothash_sig_decoded
= NULL
;
1803 size_t roothash_sig_decoded_size
= 0;
1805 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1806 if (path_is_absolute(eq
))
1807 return bus_append_string(m
, "RootHashSignaturePath", eq
);
1809 if (!(value
= startswith(eq
, "base64:")))
1810 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq
);
1812 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1813 r
= unbase64mem(value
, &roothash_sig_decoded
, &roothash_sig_decoded_size
);
1815 return log_error_errno(r
, "Failed to decode RootHashSignature= '%s': %m", eq
);
1817 return bus_append_byte_array(m
, field
, roothash_sig_decoded
, roothash_sig_decoded_size
);
1820 if (streq(field
, "RootImageOptions")) {
1821 _cleanup_strv_free_
char **l
= NULL
;
1824 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1826 return bus_log_create_error(r
);
1828 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1830 return bus_log_create_error(r
);
1832 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1834 return bus_log_create_error(r
);
1836 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1838 return bus_log_create_error(r
);
1840 r
= strv_split_colon_pairs(&l
, p
);
1842 return log_error_errno(r
, "Failed to parse argument: %m");
1844 STRV_FOREACH_PAIR(first
, second
, l
) {
1845 r
= sd_bus_message_append(m
, "(ss)",
1846 !isempty(*second
) ? *first
: "root",
1847 !isempty(*second
) ? *second
: *first
);
1849 return bus_log_create_error(r
);
1852 r
= sd_bus_message_close_container(m
);
1854 return bus_log_create_error(r
);
1856 r
= sd_bus_message_close_container(m
);
1858 return bus_log_create_error(r
);
1860 r
= sd_bus_message_close_container(m
);
1862 return bus_log_create_error(r
);
1867 if (streq(field
, "MountImages")) {
1870 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1872 return bus_log_create_error(r
);
1874 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1876 return bus_log_create_error(r
);
1878 r
= sd_bus_message_open_container(m
, 'v', "a(ssba(ss))");
1880 return bus_log_create_error(r
);
1882 r
= sd_bus_message_open_container(m
, 'a', "(ssba(ss))");
1884 return bus_log_create_error(r
);
1887 _cleanup_free_
char *first
= NULL
, *second
= NULL
, *tuple
= NULL
;
1888 const char *q
= NULL
, *source
= NULL
;
1889 bool permissive
= false;
1891 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1893 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1898 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &first
, &second
);
1900 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1905 if (source
[0] == '-') {
1910 if (isempty(second
))
1911 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1912 "Missing argument after ':': %s",
1915 r
= sd_bus_message_open_container(m
, 'r', "ssba(ss)");
1917 return bus_log_create_error(r
);
1919 r
= sd_bus_message_append(m
, "ssb", source
, second
, permissive
);
1921 return bus_log_create_error(r
);
1923 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1925 return bus_log_create_error(r
);
1928 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1930 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
);
1932 return log_error_errno(r
, "Failed to parse MountImages= property: %s", eq
);
1935 /* Single set of options, applying to the root partition/single filesystem */
1937 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1939 return bus_log_create_error(r
);
1944 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
1946 return bus_log_create_error(r
);
1949 r
= sd_bus_message_close_container(m
);
1951 return bus_log_create_error(r
);
1953 r
= sd_bus_message_close_container(m
);
1955 return bus_log_create_error(r
);
1958 r
= sd_bus_message_close_container(m
);
1960 return bus_log_create_error(r
);
1962 r
= sd_bus_message_close_container(m
);
1964 return bus_log_create_error(r
);
1966 r
= sd_bus_message_close_container(m
);
1968 return bus_log_create_error(r
);
1973 if (streq(field
, "ExtensionImages")) {
1976 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1978 return bus_log_create_error(r
);
1980 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1982 return bus_log_create_error(r
);
1984 r
= sd_bus_message_open_container(m
, 'v', "a(sba(ss))");
1986 return bus_log_create_error(r
);
1988 r
= sd_bus_message_open_container(m
, 'a', "(sba(ss))");
1990 return bus_log_create_error(r
);
1993 _cleanup_free_
char *source
= NULL
, *tuple
= NULL
;
1994 const char *q
= NULL
, *s
= NULL
;
1995 bool permissive
= false;
1997 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1999 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
2004 r
= extract_first_word(&q
, &source
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
);
2006 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
2016 r
= sd_bus_message_open_container(m
, 'r', "sba(ss)");
2018 return bus_log_create_error(r
);
2020 r
= sd_bus_message_append(m
, "sb", s
, permissive
);
2022 return bus_log_create_error(r
);
2024 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
2026 return bus_log_create_error(r
);
2029 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
2031 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
);
2033 return log_error_errno(r
, "Failed to parse ExtensionImages= property: %s", eq
);
2036 /* Single set of options, applying to the root partition/single filesystem */
2038 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
2040 return bus_log_create_error(r
);
2045 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
2047 return bus_log_create_error(r
);
2050 r
= sd_bus_message_close_container(m
);
2052 return bus_log_create_error(r
);
2054 r
= sd_bus_message_close_container(m
);
2056 return bus_log_create_error(r
);
2059 r
= sd_bus_message_close_container(m
);
2061 return bus_log_create_error(r
);
2063 r
= sd_bus_message_close_container(m
);
2065 return bus_log_create_error(r
);
2067 r
= sd_bus_message_close_container(m
);
2069 return bus_log_create_error(r
);
2074 if (STR_IN_SET(field
, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
2075 _cleanup_strv_free_
char **symlinks
= NULL
, **sources
= NULL
;
2078 /* Adding new directories is supported from both *DirectorySymlink methods and the
2079 * older ones, so first parse the input, and if we are given a new-style src:dst
2080 * tuple use the new method, else use the old one. */
2083 _cleanup_free_
char *tuple
= NULL
, *source
= NULL
, *destination
= NULL
;
2085 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
);
2087 return log_error_errno(r
, "Failed to parse argument: %m");
2091 const char *t
= tuple
;
2092 r
= extract_many_words(&t
, ":", EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
, &source
, &destination
);
2094 return log_error_errno(r
?: SYNTHETIC_ERRNO(EINVAL
), "Failed to parse argument: %m");
2096 path_simplify(source
);
2098 if (isempty(destination
)) {
2099 r
= strv_consume(&sources
, TAKE_PTR(source
));
2101 return bus_log_create_error(r
);
2103 path_simplify(destination
);
2105 r
= strv_consume_pair(&symlinks
, TAKE_PTR(source
), TAKE_PTR(destination
));
2111 if (!strv_isempty(sources
)) {
2112 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2114 return bus_log_create_error(r
);
2116 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2118 return bus_log_create_error(r
);
2120 r
= sd_bus_message_open_container(m
, 'v', "as");
2122 return bus_log_create_error(r
);
2124 r
= sd_bus_message_append_strv(m
, sources
);
2126 return bus_log_create_error(r
);
2128 r
= sd_bus_message_close_container(m
);
2130 return bus_log_create_error(r
);
2132 r
= sd_bus_message_close_container(m
);
2134 return bus_log_create_error(r
);
2137 /* For State and Runtime directories we support an optional destination parameter, which
2138 * will be used to create a symlink to the source. But it is new so we cannot change the
2139 * old DBUS signatures, so append a new message type. */
2140 if (!strv_isempty(symlinks
)) {
2141 const char *symlink_field
;
2143 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2145 return bus_log_create_error(r
);
2147 if (streq(field
, "StateDirectory"))
2148 symlink_field
= "StateDirectorySymlink";
2149 else if (streq(field
, "RuntimeDirectory"))
2150 symlink_field
= "RuntimeDirectorySymlink";
2151 else if (streq(field
, "CacheDirectory"))
2152 symlink_field
= "CacheDirectorySymlink";
2153 else if (streq(field
, "LogsDirectory"))
2154 symlink_field
= "LogsDirectorySymlink";
2156 assert_not_reached();
2158 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, symlink_field
);
2160 return bus_log_create_error(r
);
2162 r
= sd_bus_message_open_container(m
, 'v', "a(sst)");
2164 return bus_log_create_error(r
);
2166 r
= sd_bus_message_open_container(m
, 'a', "(sst)");
2168 return bus_log_create_error(r
);
2170 STRV_FOREACH_PAIR(source
, destination
, symlinks
) {
2171 r
= sd_bus_message_append(m
, "(sst)", *source
, *destination
, UINT64_C(0));
2173 return bus_log_create_error(r
);
2176 r
= sd_bus_message_close_container(m
);
2178 return bus_log_create_error(r
);
2180 r
= sd_bus_message_close_container(m
);
2182 return bus_log_create_error(r
);
2184 r
= sd_bus_message_close_container(m
);
2186 return bus_log_create_error(r
);
2195 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2196 if (streq(field
, "KillMode"))
2197 return bus_append_string(m
, field
, eq
);
2199 if (STR_IN_SET(field
, "SendSIGHUP",
2201 return bus_append_parse_boolean(m
, field
, eq
);
2203 if (STR_IN_SET(field
, "KillSignal",
2204 "RestartKillSignal",
2208 return bus_append_signal_from_string(m
, field
, eq
);
2213 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2215 if (STR_IN_SET(field
, "What",
2219 return bus_append_string(m
, field
, eq
);
2221 if (streq(field
, "TimeoutSec"))
2222 return bus_append_parse_sec_rename(m
, field
, eq
);
2224 if (streq(field
, "DirectoryMode"))
2225 return bus_append_parse_mode(m
, field
, eq
);
2227 if (STR_IN_SET(field
, "SloppyOptions",
2231 return bus_append_parse_boolean(m
, field
, eq
);
2236 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2239 if (streq(field
, "MakeDirectory"))
2240 return bus_append_parse_boolean(m
, field
, eq
);
2242 if (streq(field
, "DirectoryMode"))
2243 return bus_append_parse_mode(m
, field
, eq
);
2245 if (STR_IN_SET(field
, "PathExists",
2249 "DirectoryNotEmpty")) {
2251 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
2253 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
2255 return bus_log_create_error(r
);
2260 if (STR_IN_SET(field
, "TriggerLimitBurst", "PollLimitBurst"))
2261 return bus_append_safe_atou(m
, field
, eq
);
2263 if (STR_IN_SET(field
, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
2264 return bus_append_parse_sec_rename(m
, field
, eq
);
2269 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2270 if (streq(field
, "RuntimeMaxSec"))
2271 return bus_append_parse_sec_rename(m
, field
, eq
);
2273 if (streq(field
, "RuntimeRandomizedExtraSec"))
2274 return bus_append_parse_sec_rename(m
, field
, eq
);
2276 if (streq(field
, "TimeoutStopSec"))
2277 return bus_append_parse_sec_rename(m
, field
, eq
);
2279 /* Scope units don't have execution context but we still want to allow setting these two,
2280 * so let's handle them separately. */
2281 if (STR_IN_SET(field
, "User", "Group"))
2282 return bus_append_string(m
, field
, eq
);
2284 if (streq(field
, "OOMPolicy"))
2285 return bus_append_string(m
, field
, eq
);
2290 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2293 if (STR_IN_SET(field
, "PIDFile",
2300 "USBFunctionDescriptors",
2301 "USBFunctionStrings",
2303 "TimeoutStartFailureMode",
2304 "TimeoutStopFailureMode",
2305 "FileDescriptorStorePreserve"))
2306 return bus_append_string(m
, field
, eq
);
2308 if (STR_IN_SET(field
, "PermissionsStartOnly",
2309 "RootDirectoryStartOnly",
2312 return bus_append_parse_boolean(m
, field
, eq
);
2314 if (STR_IN_SET(field
, "RestartSec",
2315 "RestartMaxDelaySec",
2320 "RuntimeRandomizedExtraSec",
2322 return bus_append_parse_sec_rename(m
, field
, eq
);
2324 if (streq(field
, "TimeoutSec")) {
2325 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
2329 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
2332 if (STR_IN_SET(field
, "FileDescriptorStoreMax",
2334 return bus_append_safe_atou(m
, field
, eq
);
2336 if (STR_IN_SET(field
, "ExecCondition",
2350 return bus_append_exec_command(m
, field
, eq
);
2352 if (STR_IN_SET(field
, "RestartPreventExitStatus",
2353 "RestartForceExitStatus",
2354 "SuccessExitStatus")) {
2355 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
2356 size_t n_status
= 0, n_signal
= 0;
2360 _cleanup_free_
char *word
= NULL
;
2362 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
2368 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
2370 /* We need to call exit_status_from_string() first, because we want
2371 * to parse numbers as exit statuses, not signals. */
2373 r
= exit_status_from_string(word
);
2375 assert(r
>= 0 && r
< 256);
2377 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
2381 status
[n_status
++] = r
;
2383 } else if ((r
= signal_from_string(word
)) >= 0) {
2384 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
2388 signal
[n_signal
++] = r
;
2391 /* original r from exit_status_to_string() */
2392 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
2396 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
2398 return bus_log_create_error(r
);
2400 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
2402 return bus_log_create_error(r
);
2404 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
2406 return bus_log_create_error(r
);
2408 r
= sd_bus_message_open_container(m
, 'r', "aiai");
2410 return bus_log_create_error(r
);
2412 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
2414 return bus_log_create_error(r
);
2416 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
2418 return bus_log_create_error(r
);
2420 r
= sd_bus_message_close_container(m
);
2422 return bus_log_create_error(r
);
2424 r
= sd_bus_message_close_container(m
);
2426 return bus_log_create_error(r
);
2428 r
= sd_bus_message_close_container(m
);
2430 return bus_log_create_error(r
);
2435 if (streq(field
, "OpenFile"))
2436 return bus_append_open_file(m
, field
, eq
);
2441 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2444 if (STR_IN_SET(field
, "Accept",
2457 "SELinuxContextFromNet"))
2458 return bus_append_parse_boolean(m
, field
, eq
);
2460 if (STR_IN_SET(field
, "Priority",
2463 return bus_append_safe_atoi(m
, field
, eq
);
2465 if (streq(field
, "IPTOS"))
2466 return bus_append_ip_tos_from_string(m
, field
, eq
);
2468 if (STR_IN_SET(field
, "Backlog",
2470 "MaxConnectionsPerSource",
2472 "TriggerLimitBurst",
2474 return bus_append_safe_atou(m
, field
, eq
);
2476 if (STR_IN_SET(field
, "SocketMode",
2478 return bus_append_parse_mode(m
, field
, eq
);
2480 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
2481 "MessageQueueMessageSize"))
2482 return bus_append_safe_atoi64(m
, field
, eq
);
2484 if (STR_IN_SET(field
, "TimeoutSec",
2486 "KeepAliveIntervalSec",
2488 "TriggerLimitIntervalSec",
2489 "PollLimitIntervalSec"))
2490 return bus_append_parse_sec_rename(m
, field
, eq
);
2492 if (STR_IN_SET(field
, "ReceiveBuffer",
2495 return bus_append_parse_size(m
, field
, eq
, 1024);
2497 if (STR_IN_SET(field
, "ExecStartPre",
2501 return bus_append_exec_command(m
, field
, eq
);
2503 if (STR_IN_SET(field
, "SmackLabel",
2509 "FileDescriptorName",
2513 return bus_append_string(m
, field
, eq
);
2515 if (streq(field
, "Symlinks"))
2516 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2518 if (streq(field
, "SocketProtocol"))
2519 return bus_append_parse_ip_protocol(m
, field
, eq
);
2521 if (STR_IN_SET(field
, "ListenStream",
2523 "ListenSequentialPacket",
2526 "ListenMessageQueue",
2528 "ListenUSBFunction")) {
2530 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
2532 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
2534 return bus_log_create_error(r
);
2541 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2544 if (STR_IN_SET(field
, "WakeSystem",
2545 "RemainAfterElapse",
2549 "FixedRandomDelay"))
2550 return bus_append_parse_boolean(m
, field
, eq
);
2552 if (STR_IN_SET(field
, "AccuracySec",
2553 "RandomizedDelaySec"))
2554 return bus_append_parse_sec_rename(m
, field
, eq
);
2556 if (STR_IN_SET(field
, "OnActiveSec",
2560 "OnUnitInactiveSec")) {
2562 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
2565 r
= parse_sec(eq
, &t
);
2567 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
2569 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
2572 return bus_log_create_error(r
);
2577 if (streq(field
, "OnCalendar")) {
2579 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
2581 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
2583 return bus_log_create_error(r
);
2591 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2592 ConditionType t
= _CONDITION_TYPE_INVALID
;
2593 bool is_condition
= false;
2596 if (STR_IN_SET(field
, "Description",
2600 "JobTimeoutRebootArgument",
2606 return bus_append_string(m
, field
, eq
);
2608 if (STR_IN_SET(field
, "StopWhenUnneeded",
2609 "RefuseManualStart",
2613 "SurviveFinalKillSignal",
2614 "DefaultDependencies"))
2615 return bus_append_parse_boolean(m
, field
, eq
);
2617 if (STR_IN_SET(field
, "JobTimeoutSec",
2618 "JobRunningTimeoutSec",
2619 "StartLimitIntervalSec"))
2620 return bus_append_parse_sec_rename(m
, field
, eq
);
2622 if (streq(field
, "StartLimitBurst"))
2623 return bus_append_safe_atou(m
, field
, eq
);
2625 if (STR_IN_SET(field
, "SuccessActionExitStatus",
2626 "FailureActionExitStatus")) {
2628 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
2632 r
= safe_atou8(eq
, &u
);
2634 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
2636 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
2639 return bus_log_create_error(r
);
2644 if (unit_dependency_from_string(field
) >= 0 ||
2645 STR_IN_SET(field
, "Documentation",
2646 "RequiresMountsFor",
2649 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2651 t
= condition_type_from_string(field
);
2653 is_condition
= true;
2655 t
= assert_type_from_string(field
);
2658 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
2661 int trigger
, negate
;
2663 trigger
= *p
== '|';
2671 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
2672 field
, trigger
, negate
, p
);
2675 return bus_log_create_error(r
);
2683 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
2684 const char *eq
, *field
;
2690 eq
= strchr(assignment
, '=');
2692 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2693 "Not an assignment: %s", assignment
);
2695 field
= strndupa_safe(assignment
, eq
- assignment
);
2700 r
= bus_append_cgroup_property(m
, field
, eq
);
2704 r
= bus_append_execute_property(m
, field
, eq
);
2708 r
= bus_append_kill_property(m
, field
, eq
);
2712 r
= bus_append_service_property(m
, field
, eq
);
2718 r
= bus_append_cgroup_property(m
, field
, eq
);
2722 r
= bus_append_execute_property(m
, field
, eq
);
2726 r
= bus_append_kill_property(m
, field
, eq
);
2730 r
= bus_append_socket_property(m
, field
, eq
);
2736 r
= bus_append_timer_property(m
, field
, eq
);
2742 r
= bus_append_path_property(m
, field
, eq
);
2748 r
= bus_append_cgroup_property(m
, field
, eq
);
2754 r
= bus_append_cgroup_property(m
, field
, eq
);
2758 r
= bus_append_kill_property(m
, field
, eq
);
2762 r
= bus_append_scope_property(m
, field
, eq
);
2768 r
= bus_append_cgroup_property(m
, field
, eq
);
2772 r
= bus_append_execute_property(m
, field
, eq
);
2776 r
= bus_append_kill_property(m
, field
, eq
);
2780 r
= bus_append_mount_property(m
, field
, eq
);
2786 case UNIT_AUTOMOUNT
:
2787 r
= bus_append_automount_property(m
, field
, eq
);
2799 assert_not_reached();
2802 r
= bus_append_unit_property(m
, field
, eq
);
2806 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2807 "Unknown assignment: %s", assignment
);
2810 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
2815 STRV_FOREACH(i
, l
) {
2816 r
= bus_append_unit_property_assignment(m
, t
, *i
);
2824 int bus_append_scope_pidref(sd_bus_message
*m
, const PidRef
*pidref
) {
2827 if (!pidref_is_set(pidref
))
2830 if (pidref
->fd
>= 0)
2831 return sd_bus_message_append(
2833 "PIDFDs", "ah", 1, pidref
->fd
);
2835 return sd_bus_message_append(
2837 "PIDs", "au", 1, pidref
->pid
);
2840 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
) {
2841 const char *type
, *path
, *source
;
2842 InstallChange
*changes
= NULL
;
2843 size_t n_changes
= 0;
2846 CLEANUP_ARRAY(changes
, n_changes
, install_changes_free
);
2848 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2850 return bus_log_parse_error(r
);
2852 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2853 InstallChangeType t
;
2855 /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2857 t
= install_change_type_from_string(type
);
2859 log_notice_errno(t
, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2864 r
= install_changes_add(&changes
, &n_changes
, t
, path
, source
);
2869 return bus_log_parse_error(r
);
2871 r
= sd_bus_message_exit_container(m
);
2873 return bus_log_parse_error(r
);
2875 install_changes_dump(0, NULL
, changes
, n_changes
, quiet
);
2880 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2881 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2882 _cleanup_free_
char *path
= NULL
;
2885 path
= unit_dbus_path_from_name(name
);
2889 /* This function warns on its own, because otherwise it'd be awkward to pass
2890 * the dbus error message around. */
2892 r
= sd_bus_get_property_string(
2894 "org.freedesktop.systemd1",
2896 "org.freedesktop.systemd1.Unit",
2901 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));
2906 int unit_info_compare(const UnitInfo
*a
, const UnitInfo
*b
) {
2909 /* First, order by machine */
2910 r
= strcasecmp_ptr(a
->machine
, b
->machine
);
2914 /* Second, order by unit type */
2915 r
= strcasecmp_ptr(strrchr(a
->id
, '.'), strrchr(b
->id
, '.'));
2919 /* Third, order by name */
2920 return strcasecmp(a
->id
, b
->id
);
2923 int bus_service_manager_reload(sd_bus
*bus
) {
2924 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2925 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2930 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "Reload");
2932 return bus_log_create_error(r
);
2934 /* Reloading the daemon may take long, hence set a longer timeout here */
2935 r
= sd_bus_call(bus
, m
, DAEMON_RELOAD_TIMEOUT_SEC
, &error
, NULL
);
2937 return log_error_errno(r
, "Failed to reload service manager: %s", bus_error_message(&error
, r
));
2942 /* Wait for 1.5 seconds at maximum for freeze operation */
2943 #define FREEZE_BUS_CALL_TIMEOUT (1500 * USEC_PER_MSEC)
2945 int unit_freezer_new(const char *name
, UnitFreezer
*ret
) {
2946 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2947 _cleanup_free_
char *namedup
= NULL
;
2953 namedup
= strdup(name
);
2955 return log_oom_debug();
2957 r
= bus_connect_system_systemd(&bus
);
2959 return log_debug_errno(r
, "Failed to open connection to systemd: %m");
2961 (void) sd_bus_set_method_call_timeout(bus
, FREEZE_BUS_CALL_TIMEOUT
);
2963 *ret
= (UnitFreezer
) {
2964 .name
= TAKE_PTR(namedup
),
2965 .bus
= TAKE_PTR(bus
),
2970 void unit_freezer_done(UnitFreezer
*f
) {
2973 f
->name
= mfree(f
->name
);
2974 f
->bus
= sd_bus_flush_close_unref(f
->bus
);
2977 static int unit_freezer_action(UnitFreezer
*f
, bool freeze
) {
2978 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2985 r
= bus_call_method(f
->bus
, bus_systemd_mgr
,
2986 freeze
? "FreezeUnit" : "ThawUnit",
2992 return log_debug_errno(r
, "Failed to %s unit %s: %s",
2993 freeze
? "freeze" : "thaw", f
->name
, bus_error_message(&error
, r
));
2998 int unit_freezer_freeze(UnitFreezer
*f
) {
2999 return unit_freezer_action(f
, true);
3002 int unit_freezer_thaw(UnitFreezer
*f
) {
3003 return unit_freezer_action(f
, false);
3006 int unit_freezer_new_freeze(const char *name
, UnitFreezer
*ret
) {
3007 _cleanup_(unit_freezer_done
) UnitFreezer f
= {};
3013 r
= unit_freezer_new(name
, &f
);
3017 r
= unit_freezer_freeze(&f
);
3021 *ret
= TAKE_STRUCT(f
);
3025 void unit_freezer_done_thaw(UnitFreezer
*f
) {
3031 (void) unit_freezer_thaw(f
);
3032 unit_freezer_done(f
);