1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
5 #include "bus-unit-util.h"
8 #include "cgroup-setup.h"
9 #include "cgroup-util.h"
10 #include "condition.h"
11 #include "coredump-util.h"
12 #include "cpu-set-util.h"
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 "process-util.h"
32 #include "rlimit-util.h"
34 #include "seccomp-util.h"
36 #include "securebits-util.h"
37 #include "signal-util.h"
38 #include "socket-util.h"
39 #include "sort-util.h"
40 #include "stdio-util.h"
41 #include "string-util.h"
42 #include "syslog-util.h"
43 #include "terminal-util.h"
45 #include "user-util.h"
48 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
54 return sd_bus_message_read(
69 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
70 static int bus_append_##parse_func( \
77 r = parse_func(eq, &val); \
79 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
81 r = sd_bus_message_append(m, "(sv)", field, \
82 bus_type, (cast_type) val); \
84 return bus_log_create_error(r); \
89 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
90 static int bus_append_##parse_func( \
98 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
100 r = sd_bus_message_append(m, "(sv)", field, \
101 bus_type, (int32_t) r); \
103 return bus_log_create_error(r); \
108 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
109 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
110 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
111 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
112 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
114 static inline int seccomp_parse_errno_or_action(const char *eq
) { return -EINVAL
; }
116 DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action
);
117 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
118 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
119 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
120 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
121 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
122 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
123 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
124 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
125 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
126 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
127 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
128 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
129 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
130 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
131 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
132 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
133 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string
);
135 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
138 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
140 return bus_log_create_error(r
);
145 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
149 r
= sd_bus_message_open_container(m
, 'r', "sv");
151 return bus_log_create_error(r
);
153 r
= sd_bus_message_append_basic(m
, 's', field
);
155 return bus_log_create_error(r
);
157 r
= sd_bus_message_open_container(m
, 'v', "as");
159 return bus_log_create_error(r
);
161 r
= sd_bus_message_open_container(m
, 'a', "s");
163 return bus_log_create_error(r
);
166 _cleanup_free_
char *word
= NULL
;
168 r
= extract_first_word(&p
, &word
, NULL
, flags
);
174 return log_error_errno(r
, "Invalid syntax: %s", eq
);
176 r
= sd_bus_message_append_basic(m
, 's', word
);
178 return bus_log_create_error(r
);
181 r
= sd_bus_message_close_container(m
);
183 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
);
196 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
199 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
201 return bus_log_create_error(r
);
203 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
205 return bus_log_create_error(r
);
207 r
= sd_bus_message_open_container(m
, 'v', "ay");
209 return bus_log_create_error(r
);
211 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
213 return bus_log_create_error(r
);
215 r
= sd_bus_message_close_container(m
);
217 return bus_log_create_error(r
);
219 r
= sd_bus_message_close_container(m
);
221 return bus_log_create_error(r
);
226 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
232 r
= parse_sec(eq
, &t
);
234 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
237 n
= newa(char, l
+ 2);
238 /* Change suffix Sec → USec */
239 strcpy(mempcpy(n
, field
, l
- 3), "USec");
241 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
243 return bus_log_create_error(r
);
248 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
252 r
= parse_size(eq
, base
, &v
);
254 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
256 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
258 return bus_log_create_error(r
);
263 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
264 bool explicit_path
= false, done
= false;
265 _cleanup_strv_free_
char **l
= NULL
, **ex_opts
= NULL
;
266 _cleanup_free_
char *path
= NULL
, *upgraded_name
= NULL
;
267 ExecCommandFlags flags
= 0;
268 bool is_ex_prop
= endswith(field
, "Ex");
275 if (FLAGS_SET(flags
, EXEC_COMMAND_IGNORE_FAILURE
))
278 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
287 explicit_path
= true;
293 if (FLAGS_SET(flags
, EXEC_COMMAND_NO_ENV_EXPAND
))
296 flags
|= EXEC_COMMAND_NO_ENV_EXPAND
;
302 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))
305 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
311 if (flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))
313 else if (FLAGS_SET(flags
, EXEC_COMMAND_NO_SETUID
)) {
314 flags
&= ~EXEC_COMMAND_NO_SETUID
;
315 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
318 flags
|= EXEC_COMMAND_NO_SETUID
;
329 if (!is_ex_prop
&& (flags
& (EXEC_COMMAND_NO_ENV_EXPAND
|EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
330 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
332 upgraded_name
= strjoin(field
, "Ex");
338 r
= exec_command_flags_to_strv(flags
, &ex_opts
);
340 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
344 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
346 return log_error_errno(r
, "Failed to parse path: %m");
349 r
= strv_split_full(&l
, eq
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
351 return log_error_errno(r
, "Failed to parse command line: %m");
353 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
355 return bus_log_create_error(r
);
357 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, upgraded_name
?: field
);
359 return bus_log_create_error(r
);
361 r
= sd_bus_message_open_container(m
, 'v', is_ex_prop
? "a(sasas)" : "a(sasb)");
363 return bus_log_create_error(r
);
365 r
= sd_bus_message_open_container(m
, 'a', is_ex_prop
? "(sasas)" : "(sasb)");
367 return bus_log_create_error(r
);
369 if (!strv_isempty(l
)) {
371 r
= sd_bus_message_open_container(m
, 'r', is_ex_prop
? "sasas" : "sasb");
373 return bus_log_create_error(r
);
375 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
377 return bus_log_create_error(r
);
379 r
= sd_bus_message_append_strv(m
, l
);
381 return bus_log_create_error(r
);
383 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
));
385 return bus_log_create_error(r
);
387 r
= sd_bus_message_close_container(m
);
389 return bus_log_create_error(r
);
392 r
= sd_bus_message_close_container(m
);
394 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
);
407 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
413 r
= sd_bus_message_open_container(m
, 'r', "iayu");
417 r
= sd_bus_message_append(m
, "i", family
);
421 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
425 r
= sd_bus_message_append(m
, "u", prefixlen
);
429 return sd_bus_message_close_container(m
);
432 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
435 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
436 return bus_append_string(m
, field
, eq
);
438 if (STR_IN_SET(field
, "CPUAccounting",
444 return bus_append_parse_boolean(m
, field
, eq
);
446 if (STR_IN_SET(field
, "CPUWeight",
450 return bus_append_cg_weight_parse(m
, field
, eq
);
452 if (STR_IN_SET(field
, "CPUShares",
454 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
456 if (STR_IN_SET(field
, "AllowedCPUs",
457 "AllowedMemoryNodes")) {
458 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
459 _cleanup_free_
uint8_t *array
= NULL
;
462 r
= parse_cpu_set(eq
, &cpuset
);
464 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
466 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
468 return log_error_errno(r
, "Failed to serialize CPUSet: %m");
470 return bus_append_byte_array(m
, field
, array
, allocated
);
473 if (STR_IN_SET(field
, "BlockIOWeight",
474 "StartupBlockIOWeight"))
475 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
477 if (streq(field
, "DisableControllers"))
478 return bus_append_strv(m
, "DisableControllers", eq
, EXTRACT_UNQUOTE
);
480 if (streq(field
, "Delegate")) {
481 r
= parse_boolean(eq
);
483 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_UNQUOTE
);
485 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
487 return bus_log_create_error(r
);
492 if (STR_IN_SET(field
, "MemoryMin",
502 if (streq(eq
, "infinity")) {
503 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
505 return bus_log_create_error(r
);
507 } else if (isempty(eq
)) {
508 uint64_t empty_value
= STR_IN_SET(field
,
516 r
= sd_bus_message_append(m
, "(sv)", field
, "t", empty_value
);
518 return bus_log_create_error(r
);
522 r
= parse_permille(eq
);
526 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
527 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
528 * size can be determined server-side. */
530 n
= strjoina(field
, "Scale");
531 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
533 return bus_log_create_error(r
);
538 if (streq(field
, "TasksMax"))
539 return bus_append_safe_atou64(m
, field
, eq
);
541 return bus_append_parse_size(m
, field
, eq
, 1024);
544 if (streq(field
, "CPUQuota")) {
546 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
548 r
= parse_permille_unbounded(eq
);
550 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
551 "CPU quota too small.");
553 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
555 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
559 return bus_log_create_error(r
);
564 if (streq(field
, "CPUQuotaPeriodSec")) {
565 usec_t u
= USEC_INFINITY
;
567 r
= parse_sec_def_infinity(eq
, &u
);
569 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
571 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
573 return bus_log_create_error(r
);
578 if (streq(field
, "DeviceAllow")) {
580 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
582 const char *path
= eq
, *rwm
= NULL
, *e
;
586 path
= strndupa(eq
, e
- eq
);
590 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
594 return bus_log_create_error(r
);
599 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
601 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
603 const char *path
, *bandwidth
, *e
;
608 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
609 "Failed to parse %s value %s.",
612 path
= strndupa(eq
, e
- eq
);
615 if (streq(bandwidth
, "infinity"))
616 bytes
= CGROUP_LIMIT_MAX
;
618 r
= parse_size(bandwidth
, 1000, &bytes
);
620 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
623 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
627 return bus_log_create_error(r
);
632 if (STR_IN_SET(field
, "IODeviceWeight",
633 "BlockIODeviceWeight")) {
635 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
637 const char *path
, *weight
, *e
;
642 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
643 "Failed to parse %s value %s.",
646 path
= strndupa(eq
, e
- eq
);
649 r
= safe_atou64(weight
, &u
);
651 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
653 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
657 return bus_log_create_error(r
);
662 if (streq(field
, "IODeviceLatencyTargetSec")) {
663 const char *field_usec
= "IODeviceLatencyTargetUSec";
666 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
668 const char *path
, *target
, *e
;
673 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
674 "Failed to parse %s value %s.",
677 path
= strndupa(eq
, e
- eq
);
680 r
= parse_sec(target
, &usec
);
682 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
684 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
688 return bus_log_create_error(r
);
693 if (STR_IN_SET(field
, "IPAddressAllow",
695 unsigned char prefixlen
;
696 union in_addr_union prefix
= {};
700 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
702 return bus_log_create_error(r
);
707 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
709 return bus_log_create_error(r
);
711 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
713 return bus_log_create_error(r
);
715 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
717 return bus_log_create_error(r
);
719 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
721 return bus_log_create_error(r
);
723 if (streq(eq
, "any")) {
724 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
726 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
728 return bus_log_create_error(r
);
730 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
732 return bus_log_create_error(r
);
734 } else if (is_localhost(eq
)) {
735 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
737 prefix
.in
.s_addr
= htobe32(0x7f000000);
738 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
740 return bus_log_create_error(r
);
742 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
743 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
747 } else if (streq(eq
, "link-local")) {
748 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
750 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
751 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
753 return bus_log_create_error(r
);
755 prefix
.in6
= (struct in6_addr
) {
756 .s6_addr32
[0] = htobe32(0xfe800000)
758 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
760 return bus_log_create_error(r
);
762 } else if (streq(eq
, "multicast")) {
763 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
765 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
766 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
768 return bus_log_create_error(r
);
770 prefix
.in6
= (struct in6_addr
) {
771 .s6_addr32
[0] = htobe32(0xff000000)
773 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
775 return bus_log_create_error(r
);
779 _cleanup_free_
char *word
= NULL
;
781 r
= extract_first_word(&eq
, &word
, NULL
, 0);
787 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
789 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
791 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
793 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
795 return bus_log_create_error(r
);
799 r
= sd_bus_message_close_container(m
);
801 return bus_log_create_error(r
);
803 r
= sd_bus_message_close_container(m
);
805 return bus_log_create_error(r
);
807 r
= sd_bus_message_close_container(m
);
809 return bus_log_create_error(r
);
814 if (STR_IN_SET(field
, "IPIngressFilterPath",
815 "IPEgressFilterPath")) {
817 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 0);
819 r
= sd_bus_message_append(m
, "(sv)", field
, "as", 1, eq
);
822 return bus_log_create_error(r
);
830 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
831 if (streq(field
, "Where"))
832 return bus_append_string(m
, field
, eq
);
834 if (streq(field
, "DirectoryMode"))
835 return bus_append_parse_mode(m
, field
, eq
);
837 if (streq(field
, "TimeoutIdleSec"))
838 return bus_append_parse_sec_rename(m
, field
, eq
);
843 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
847 if (STR_IN_SET(field
, "User",
861 "RuntimeDirectoryPreserve",
866 "NetworkNamespacePath",
868 return bus_append_string(m
, field
, eq
);
870 if (STR_IN_SET(field
, "IgnoreSIGPIPE",
881 "MemoryDenyWriteExecute",
885 "ProtectKernelTunables",
886 "ProtectKernelModules",
889 "ProtectControlGroups",
891 "CPUSchedulingResetOnFork",
895 return bus_append_parse_boolean(m
, field
, eq
);
897 if (STR_IN_SET(field
, "ReadWriteDirectories",
898 "ReadOnlyDirectories",
899 "InaccessibleDirectories",
907 "ConfigurationDirectory",
908 "SupplementaryGroups",
909 "SystemCallArchitectures"))
910 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
912 if (STR_IN_SET(field
, "SyslogLevel",
914 return bus_append_log_level_from_string(m
, field
, eq
);
916 if (streq(field
, "SyslogFacility"))
917 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
919 if (streq(field
, "SecureBits"))
920 return bus_append_secure_bits_from_string(m
, field
, eq
);
922 if (streq(field
, "CPUSchedulingPolicy"))
923 return bus_append_sched_policy_from_string(m
, field
, eq
);
925 if (STR_IN_SET(field
, "CPUSchedulingPriority",
927 return bus_append_safe_atoi(m
, field
, eq
);
929 if (streq(field
, "CoredumpFilter"))
930 return bus_append_coredump_filter_mask_from_string(m
, field
, eq
);
932 if (streq(field
, "Nice"))
933 return bus_append_parse_nice(m
, field
, eq
);
935 if (streq(field
, "SystemCallErrorNumber"))
936 return bus_append_seccomp_parse_errno_or_action(m
, field
, eq
);
938 if (streq(field
, "IOSchedulingClass"))
939 return bus_append_ioprio_class_from_string(m
, field
, eq
);
941 if (streq(field
, "IOSchedulingPriority"))
942 return bus_append_ioprio_parse_priority(m
, field
, eq
);
944 if (STR_IN_SET(field
, "RuntimeDirectoryMode",
945 "StateDirectoryMode",
946 "CacheDirectoryMode",
948 "ConfigurationDirectoryMode",
950 return bus_append_parse_mode(m
, field
, eq
);
952 if (streq(field
, "TimerSlackNSec"))
953 return bus_append_parse_nsec(m
, field
, eq
);
955 if (streq(field
, "LogRateLimitIntervalSec"))
956 return bus_append_parse_sec_rename(m
, field
, eq
);
958 if (streq(field
, "LogRateLimitBurst"))
959 return bus_append_safe_atou(m
, field
, eq
);
961 if (streq(field
, "MountFlags"))
962 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
964 if (STR_IN_SET(field
, "Environment",
967 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
);
969 if (streq(field
, "EnvironmentFile")) {
971 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
973 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
974 eq
[0] == '-' ? eq
+ 1 : eq
,
977 return bus_log_create_error(r
);
982 if (streq(field
, "SetCredential")) {
983 r
= sd_bus_message_open_container(m
, 'r', "sv");
985 return bus_log_create_error(r
);
987 r
= sd_bus_message_append_basic(m
, 's', "SetCredential");
989 return bus_log_create_error(r
);
991 r
= sd_bus_message_open_container(m
, 'v', "a(say)");
993 return bus_log_create_error(r
);
996 r
= sd_bus_message_append(m
, "a(say)", 0);
998 _cleanup_free_
char *word
= NULL
, *unescaped
= NULL
;
1002 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1006 return log_error_errno(r
, "Failed to parse SetCredential= parameter: %s", eq
);
1008 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to SetCredential=.");
1010 l
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &unescaped
);
1012 return log_error_errno(l
, "Failed to unescape SetCredential= value: %s", p
);
1014 r
= sd_bus_message_open_container(m
, 'a', "(say)");
1016 return bus_log_create_error(r
);
1018 r
= sd_bus_message_open_container(m
, 'r', "say");
1020 return bus_log_create_error(r
);
1022 r
= sd_bus_message_append(m
, "s", word
);
1024 return bus_log_create_error(r
);
1026 r
= sd_bus_message_append_array(m
, 'y', unescaped
, l
);
1028 return bus_log_create_error(r
);
1030 r
= sd_bus_message_close_container(m
);
1032 return bus_log_create_error(r
);
1034 r
= sd_bus_message_close_container(m
);
1037 return bus_log_create_error(r
);
1039 r
= sd_bus_message_close_container(m
);
1041 return bus_log_create_error(r
);
1043 r
= sd_bus_message_close_container(m
);
1045 return bus_log_create_error(r
);
1050 if (streq(field
, "LoadCredential")) {
1051 r
= sd_bus_message_open_container(m
, 'r', "sv");
1053 return bus_log_create_error(r
);
1055 r
= sd_bus_message_append_basic(m
, 's', "LoadCredential");
1057 return bus_log_create_error(r
);
1059 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1061 return bus_log_create_error(r
);
1064 r
= sd_bus_message_append(m
, "a(ss)", 0);
1066 _cleanup_free_
char *word
= NULL
;
1069 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1073 return log_error_errno(r
, "Failed to parse LoadCredential= parameter: %s", eq
);
1075 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Missing argument to LoadCredential=.");
1077 r
= sd_bus_message_append(m
, "a(ss)", 1, word
, p
);
1080 return bus_log_create_error(r
);
1082 r
= sd_bus_message_close_container(m
);
1084 return bus_log_create_error(r
);
1086 r
= sd_bus_message_close_container(m
);
1088 return bus_log_create_error(r
);
1093 if (streq(field
, "LogExtraFields")) {
1094 r
= sd_bus_message_open_container(m
, 'r', "sv");
1096 return bus_log_create_error(r
);
1098 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
1100 return bus_log_create_error(r
);
1102 r
= sd_bus_message_open_container(m
, 'v', "aay");
1104 return bus_log_create_error(r
);
1106 r
= sd_bus_message_open_container(m
, 'a', "ay");
1108 return bus_log_create_error(r
);
1110 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
1112 return bus_log_create_error(r
);
1114 r
= sd_bus_message_close_container(m
);
1116 return bus_log_create_error(r
);
1118 r
= sd_bus_message_close_container(m
);
1120 return bus_log_create_error(r
);
1122 r
= sd_bus_message_close_container(m
);
1124 return bus_log_create_error(r
);
1129 if (STR_IN_SET(field
, "StandardInput",
1132 const char *n
, *appended
;
1134 if ((n
= startswith(eq
, "fd:"))) {
1135 appended
= strjoina(field
, "FileDescriptorName");
1136 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1137 } else if ((n
= startswith(eq
, "file:"))) {
1138 appended
= strjoina(field
, "File");
1139 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1140 } else if ((n
= startswith(eq
, "append:"))) {
1141 appended
= strjoina(field
, "FileToAppend");
1142 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
1144 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
1146 return bus_log_create_error(r
);
1151 if (streq(field
, "StandardInputText")) {
1152 _cleanup_free_
char *unescaped
= NULL
;
1154 r
= cunescape(eq
, 0, &unescaped
);
1156 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
1158 if (!strextend(&unescaped
, "\n", NULL
))
1161 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
1162 * interface anyway */
1164 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
1167 if (streq(field
, "StandardInputData")) {
1168 _cleanup_free_
void *decoded
= NULL
;
1171 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
1173 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
1175 return bus_append_byte_array(m
, field
, decoded
, sz
);
1178 if ((suffix
= startswith(field
, "Limit"))) {
1181 rl
= rlimit_from_string(suffix
);
1186 r
= rlimit_parse(rl
, eq
, &l
);
1188 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
1190 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
1192 return bus_log_create_error(r
);
1194 sn
= strjoina(field
, "Soft");
1195 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
1197 return bus_log_create_error(r
);
1203 if (STR_IN_SET(field
, "AppArmorProfile",
1204 "SmackProcessLabel")) {
1213 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
1215 return bus_log_create_error(r
);
1220 if (STR_IN_SET(field
, "CapabilityBoundingSet",
1221 "AmbientCapabilities")) {
1223 bool invert
= false;
1231 r
= capability_set_from_string(p
, &sum
);
1233 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
1235 sum
= invert
? ~sum
: sum
;
1237 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
1239 return bus_log_create_error(r
);
1244 if (streq(field
, "CPUAffinity")) {
1245 _cleanup_(cpu_set_reset
) CPUSet cpuset
= {};
1246 _cleanup_free_
uint8_t *array
= NULL
;
1249 if (eq
&& streq(eq
, "numa")) {
1250 r
= sd_bus_message_append(m
, "(sv)", "CPUAffinityFromNUMA", "b", true);
1252 return bus_log_create_error(r
);
1256 r
= parse_cpu_set(eq
, &cpuset
);
1258 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1260 r
= cpu_set_to_dbus(&cpuset
, &array
, &allocated
);
1262 return log_error_errno(r
, "Failed to serialize CPUAffinity: %m");
1264 return bus_append_byte_array(m
, field
, array
, allocated
);
1267 if (streq(field
, "NUMAPolicy")) {
1268 r
= mpol_from_string(eq
);
1270 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1272 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int32_t) r
);
1274 return bus_log_create_error(r
);
1279 if (streq(field
, "NUMAMask")) {
1280 _cleanup_(cpu_set_reset
) CPUSet nodes
= {};
1281 _cleanup_free_
uint8_t *array
= NULL
;
1284 if (eq
&& streq(eq
, "all")) {
1285 r
= numa_mask_add_all(&nodes
);
1287 return log_error_errno(r
, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1289 r
= parse_cpu_set(eq
, &nodes
);
1291 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1294 r
= cpu_set_to_dbus(&nodes
, &array
, &allocated
);
1296 return log_error_errno(r
, "Failed to serialize NUMAMask: %m");
1298 return bus_append_byte_array(m
, field
, array
, allocated
);
1301 if (STR_IN_SET(field
, "RestrictAddressFamilies",
1312 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1314 return bus_log_create_error(r
);
1316 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1318 return bus_log_create_error(r
);
1320 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1322 return bus_log_create_error(r
);
1324 r
= sd_bus_message_open_container(m
, 'r', "bas");
1326 return bus_log_create_error(r
);
1328 r
= sd_bus_message_append_basic(m
, 'b', &allow_list
);
1330 return bus_log_create_error(r
);
1332 r
= sd_bus_message_open_container(m
, 'a', "s");
1334 return bus_log_create_error(r
);
1337 _cleanup_free_
char *word
= NULL
;
1339 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1345 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1347 r
= sd_bus_message_append_basic(m
, 's', word
);
1349 return bus_log_create_error(r
);
1352 r
= sd_bus_message_close_container(m
);
1354 return bus_log_create_error(r
);
1356 r
= sd_bus_message_close_container(m
);
1358 return bus_log_create_error(r
);
1360 r
= sd_bus_message_close_container(m
);
1362 return bus_log_create_error(r
);
1364 r
= sd_bus_message_close_container(m
);
1366 return bus_log_create_error(r
);
1371 if (streq(field
, "RestrictNamespaces")) {
1372 bool invert
= false;
1373 unsigned long flags
;
1375 r
= parse_boolean(eq
);
1379 flags
= NAMESPACE_FLAGS_ALL
;
1386 r
= namespace_flags_from_string(eq
, &flags
);
1388 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1392 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1394 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1396 return bus_log_create_error(r
);
1401 if (STR_IN_SET(field
, "BindPaths",
1402 "BindReadOnlyPaths")) {
1405 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1407 return bus_log_create_error(r
);
1409 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1411 return bus_log_create_error(r
);
1413 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1415 return bus_log_create_error(r
);
1417 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1419 return bus_log_create_error(r
);
1422 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1423 char *s
= NULL
, *d
= NULL
;
1424 bool ignore_enoent
= false;
1425 uint64_t flags
= MS_REC
;
1427 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1429 return log_error_errno(r
, "Failed to parse argument: %m");
1435 ignore_enoent
= true;
1439 if (p
&& p
[-1] == ':') {
1440 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1442 return log_error_errno(r
, "Failed to parse argument: %m");
1444 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1445 "Missing argument after ':': %s",
1450 if (p
&& p
[-1] == ':') {
1451 _cleanup_free_
char *options
= NULL
;
1453 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_UNQUOTE
);
1455 return log_error_errno(r
, "Failed to parse argument: %m");
1457 if (isempty(options
) || streq(options
, "rbind"))
1459 else if (streq(options
, "norbind"))
1462 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1463 "Unknown options: %s",
1469 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1471 return bus_log_create_error(r
);
1474 r
= sd_bus_message_close_container(m
);
1476 return bus_log_create_error(r
);
1478 r
= sd_bus_message_close_container(m
);
1480 return bus_log_create_error(r
);
1482 r
= sd_bus_message_close_container(m
);
1484 return bus_log_create_error(r
);
1489 if (streq(field
, "TemporaryFileSystem")) {
1492 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1494 return bus_log_create_error(r
);
1496 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1498 return bus_log_create_error(r
);
1500 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1502 return bus_log_create_error(r
);
1504 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1506 return bus_log_create_error(r
);
1509 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1512 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1514 return log_error_errno(r
, "Failed to parse argument: %m");
1519 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1521 return log_error_errno(r
, "Failed to parse argument: %m");
1523 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1524 "Failed to parse argument: %s",
1527 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1529 return bus_log_create_error(r
);
1532 r
= sd_bus_message_close_container(m
);
1534 return bus_log_create_error(r
);
1536 r
= sd_bus_message_close_container(m
);
1538 return bus_log_create_error(r
);
1540 r
= sd_bus_message_close_container(m
);
1542 return bus_log_create_error(r
);
1547 if (streq(field
, "RootHash")) {
1548 _cleanup_free_
void *roothash_decoded
= NULL
;
1549 size_t roothash_decoded_size
= 0;
1551 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1552 if (path_is_absolute(eq
))
1553 return bus_append_string(m
, "RootHashPath", eq
);
1555 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1556 r
= unhexmem(eq
, strlen(eq
), &roothash_decoded
, &roothash_decoded_size
);
1558 return log_error_errno(r
, "Failed to decode RootHash= '%s': %m", eq
);
1559 if (roothash_decoded_size
< sizeof(sd_id128_t
))
1560 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "RootHash= '%s' is too short: %m", eq
);
1562 return bus_append_byte_array(m
, field
, roothash_decoded
, roothash_decoded_size
);
1565 if (streq(field
, "RootHashSignature")) {
1566 _cleanup_free_
void *roothash_sig_decoded
= NULL
;
1568 size_t roothash_sig_decoded_size
= 0;
1570 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1571 if (path_is_absolute(eq
))
1572 return bus_append_string(m
, "RootHashSignaturePath", eq
);
1574 if (!(value
= startswith(eq
, "base64:")))
1575 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq
);
1577 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1578 r
= unbase64mem(value
, strlen(value
), &roothash_sig_decoded
, &roothash_sig_decoded_size
);
1580 return log_error_errno(r
, "Failed to decode RootHashSignature= '%s': %m", eq
);
1582 return bus_append_byte_array(m
, field
, roothash_sig_decoded
, roothash_sig_decoded_size
);
1585 if (streq(field
, "RootImageOptions")) {
1586 _cleanup_strv_free_
char **l
= NULL
;
1587 char **first
= NULL
, **second
= NULL
;
1590 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1592 return bus_log_create_error(r
);
1594 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1596 return bus_log_create_error(r
);
1598 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1600 return bus_log_create_error(r
);
1602 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1604 return bus_log_create_error(r
);
1606 r
= strv_split_colon_pairs(&l
, p
);
1608 return log_error_errno(r
, "Failed to parse argument: %m");
1610 STRV_FOREACH_PAIR(first
, second
, l
) {
1611 /* Format is either 'root:foo' or 'foo' (root is implied) */
1612 if (!isempty(*second
) && partition_designator_from_string(*first
) < 0)
1613 return bus_log_create_error(-EINVAL
);
1615 r
= sd_bus_message_append(m
, "(ss)",
1616 !isempty(*second
) ? *first
: "root",
1617 !isempty(*second
) ? *second
: *first
);
1619 return bus_log_create_error(r
);
1622 r
= sd_bus_message_close_container(m
);
1624 return bus_log_create_error(r
);
1626 r
= sd_bus_message_close_container(m
);
1628 return bus_log_create_error(r
);
1630 r
= sd_bus_message_close_container(m
);
1632 return bus_log_create_error(r
);
1637 if (streq(field
, "MountImages")) {
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(ssba(ss))");
1650 return bus_log_create_error(r
);
1652 r
= sd_bus_message_open_container(m
, 'a', "(ssba(ss))");
1654 return bus_log_create_error(r
);
1657 _cleanup_free_
char *first
= NULL
, *second
= NULL
, *tuple
= NULL
;
1658 const char *q
= NULL
, *source
= NULL
;
1659 bool permissive
= false;
1661 r
= extract_first_word(&p
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1668 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &first
, &second
, NULL
);
1675 if (source
[0] == '-') {
1680 if (isempty(second
))
1681 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1682 "Missing argument after ':': %s",
1685 r
= sd_bus_message_open_container(m
, 'r', "ssba(ss)");
1687 return bus_log_create_error(r
);
1689 r
= sd_bus_message_append(m
, "ssb", source
, second
, permissive
);
1691 return bus_log_create_error(r
);
1693 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1695 return bus_log_create_error(r
);
1698 _cleanup_free_
char *partition
= NULL
, *mount_options
= NULL
;
1700 r
= extract_many_words(&q
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
1705 /* Single set of options, applying to the root partition/single filesystem */
1707 r
= sd_bus_message_append(m
, "(ss)", "root", partition
);
1709 return bus_log_create_error(r
);
1714 if (partition_designator_from_string(partition
) < 0)
1715 return bus_log_create_error(-EINVAL
);
1717 r
= sd_bus_message_append(m
, "(ss)", partition
, mount_options
);
1719 return bus_log_create_error(r
);
1722 r
= sd_bus_message_close_container(m
);
1724 return bus_log_create_error(r
);
1726 r
= sd_bus_message_close_container(m
);
1728 return bus_log_create_error(r
);
1731 r
= sd_bus_message_close_container(m
);
1733 return bus_log_create_error(r
);
1735 r
= sd_bus_message_close_container(m
);
1737 return bus_log_create_error(r
);
1739 r
= sd_bus_message_close_container(m
);
1741 return bus_log_create_error(r
);
1749 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1750 if (streq(field
, "KillMode"))
1751 return bus_append_string(m
, field
, eq
);
1753 if (STR_IN_SET(field
, "SendSIGHUP",
1755 return bus_append_parse_boolean(m
, field
, eq
);
1757 if (STR_IN_SET(field
, "KillSignal",
1758 "RestartKillSignal",
1761 return bus_append_signal_from_string(m
, field
, eq
);
1766 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1768 if (STR_IN_SET(field
, "What",
1772 return bus_append_string(m
, field
, eq
);
1774 if (streq(field
, "TimeoutSec"))
1775 return bus_append_parse_sec_rename(m
, field
, eq
);
1777 if (streq(field
, "DirectoryMode"))
1778 return bus_append_parse_mode(m
, field
, eq
);
1780 if (STR_IN_SET(field
, "SloppyOptions",
1784 return bus_append_parse_boolean(m
, field
, eq
);
1789 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1792 if (streq(field
, "MakeDirectory"))
1793 return bus_append_parse_boolean(m
, field
, eq
);
1795 if (streq(field
, "DirectoryMode"))
1796 return bus_append_parse_mode(m
, field
, eq
);
1798 if (STR_IN_SET(field
, "PathExists",
1802 "DirectoryNotEmpty")) {
1804 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1806 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1808 return bus_log_create_error(r
);
1816 static int bus_append_scope_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1817 if (streq(field
, "RuntimeMaxSec"))
1818 return bus_append_parse_sec_rename(m
, field
, eq
);
1820 if (streq(field
, "TimeoutStopSec"))
1821 return bus_append_parse_sec_rename(m
, field
, eq
);
1826 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1829 if (STR_IN_SET(field
, "PIDFile",
1834 "USBFunctionDescriptors",
1835 "USBFunctionStrings",
1837 "TimeoutStartFailureMode",
1838 "TimeoutStopFailureMode"))
1839 return bus_append_string(m
, field
, eq
);
1841 if (STR_IN_SET(field
, "PermissionsStartOnly",
1842 "RootDirectoryStartOnly",
1845 return bus_append_parse_boolean(m
, field
, eq
);
1847 if (STR_IN_SET(field
, "RestartSec",
1853 return bus_append_parse_sec_rename(m
, field
, eq
);
1855 if (streq(field
, "TimeoutSec")) {
1856 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1860 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1863 if (streq(field
, "FileDescriptorStoreMax"))
1864 return bus_append_safe_atou(m
, field
, eq
);
1866 if (STR_IN_SET(field
, "ExecCondition",
1880 return bus_append_exec_command(m
, field
, eq
);
1882 if (STR_IN_SET(field
, "RestartPreventExitStatus",
1883 "RestartForceExitStatus",
1884 "SuccessExitStatus")) {
1885 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1886 size_t n_status
= 0, n_signal
= 0;
1890 _cleanup_free_
char *word
= NULL
;
1892 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
);
1898 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1900 /* We need to call exit_status_from_string() first, because we want
1901 * to parse numbers as exit statuses, not signals. */
1903 r
= exit_status_from_string(word
);
1905 assert(r
>= 0 && r
< 256);
1907 status
= reallocarray(status
, n_status
+ 1, sizeof(int));
1911 status
[n_status
++] = r
;
1913 } else if ((r
= signal_from_string(word
)) >= 0) {
1914 signal
= reallocarray(signal
, n_signal
+ 1, sizeof(int));
1918 signal
[n_signal
++] = r
;
1921 /* original r from exit_status_to_string() */
1922 return log_error_errno(r
, "Invalid status or signal %s in %s: %m",
1926 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1928 return bus_log_create_error(r
);
1930 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1932 return bus_log_create_error(r
);
1934 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1936 return bus_log_create_error(r
);
1938 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1940 return bus_log_create_error(r
);
1942 r
= sd_bus_message_append_array(m
, 'i', status
, n_status
* sizeof(int));
1944 return bus_log_create_error(r
);
1946 r
= sd_bus_message_append_array(m
, 'i', signal
, n_signal
* sizeof(int));
1948 return bus_log_create_error(r
);
1950 r
= sd_bus_message_close_container(m
);
1952 return bus_log_create_error(r
);
1954 r
= sd_bus_message_close_container(m
);
1956 return bus_log_create_error(r
);
1958 r
= sd_bus_message_close_container(m
);
1960 return bus_log_create_error(r
);
1968 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1971 if (STR_IN_SET(field
, "Accept",
1984 "SELinuxContextFromNet"))
1985 return bus_append_parse_boolean(m
, field
, eq
);
1987 if (STR_IN_SET(field
, "Priority",
1990 return bus_append_safe_atoi(m
, field
, eq
);
1992 if (streq(field
, "IPTOS"))
1993 return bus_append_ip_tos_from_string(m
, field
, eq
);
1995 if (STR_IN_SET(field
, "Backlog",
1997 "MaxConnectionsPerSource",
1999 "TriggerLimitBurst"))
2000 return bus_append_safe_atou(m
, field
, eq
);
2002 if (STR_IN_SET(field
, "SocketMode",
2004 return bus_append_parse_mode(m
, field
, eq
);
2006 if (STR_IN_SET(field
, "MessageQueueMaxMessages",
2007 "MessageQueueMessageSize"))
2008 return bus_append_safe_atoi64(m
, field
, eq
);
2010 if (STR_IN_SET(field
, "TimeoutSec",
2012 "KeepAliveIntervalSec",
2014 "TriggerLimitIntervalSec"))
2015 return bus_append_parse_sec_rename(m
, field
, eq
);
2017 if (STR_IN_SET(field
, "ReceiveBuffer",
2020 return bus_append_parse_size(m
, field
, eq
, 1024);
2022 if (STR_IN_SET(field
, "ExecStartPre",
2026 return bus_append_exec_command(m
, field
, eq
);
2028 if (STR_IN_SET(field
, "SmackLabel",
2034 "FileDescriptorName",
2037 return bus_append_string(m
, field
, eq
);
2039 if (streq(field
, "Symlinks"))
2040 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2042 if (streq(field
, "SocketProtocol"))
2043 return bus_append_parse_ip_protocol(m
, field
, eq
);
2045 if (STR_IN_SET(field
, "ListenStream",
2047 "ListenSequentialPacket",
2050 "ListenMessageQueue",
2052 "ListenUSBFunction")) {
2054 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
2056 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
2058 return bus_log_create_error(r
);
2065 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2068 if (STR_IN_SET(field
, "WakeSystem",
2069 "RemainAfterElapse",
2073 return bus_append_parse_boolean(m
, field
, eq
);
2075 if (STR_IN_SET(field
, "AccuracySec",
2076 "RandomizedDelaySec"))
2077 return bus_append_parse_sec_rename(m
, field
, eq
);
2079 if (STR_IN_SET(field
, "OnActiveSec",
2083 "OnUnitInactiveSec")) {
2085 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
2088 r
= parse_sec(eq
, &t
);
2090 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
2092 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
2095 return bus_log_create_error(r
);
2100 if (streq(field
, "OnCalendar")) {
2102 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
2104 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
2106 return bus_log_create_error(r
);
2114 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
2115 ConditionType t
= _CONDITION_TYPE_INVALID
;
2116 bool is_condition
= false;
2119 if (STR_IN_SET(field
, "Description",
2123 "JobTimeoutRebootArgument",
2129 return bus_append_string(m
, field
, eq
);
2131 if (STR_IN_SET(field
, "StopWhenUnneeded",
2132 "RefuseManualStart",
2136 "DefaultDependencies"))
2137 return bus_append_parse_boolean(m
, field
, eq
);
2139 if (STR_IN_SET(field
, "JobTimeoutSec",
2140 "JobRunningTimeoutSec",
2141 "StartLimitIntervalSec"))
2142 return bus_append_parse_sec_rename(m
, field
, eq
);
2144 if (streq(field
, "StartLimitBurst"))
2145 return bus_append_safe_atou(m
, field
, eq
);
2147 if (STR_IN_SET(field
, "SuccessActionExitStatus",
2148 "FailureActionExitStatus")) {
2150 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
2154 r
= safe_atou8(eq
, &u
);
2156 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
2158 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
2161 return bus_log_create_error(r
);
2166 if (unit_dependency_from_string(field
) >= 0 ||
2167 STR_IN_SET(field
, "Documentation",
2168 "RequiresMountsFor"))
2169 return bus_append_strv(m
, field
, eq
, EXTRACT_UNQUOTE
);
2171 t
= condition_type_from_string(field
);
2173 is_condition
= true;
2175 t
= assert_type_from_string(field
);
2178 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
2181 int trigger
, negate
;
2183 trigger
= *p
== '|';
2191 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
2192 field
, trigger
, negate
, p
);
2195 return bus_log_create_error(r
);
2203 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
2204 const char *eq
, *field
;
2210 eq
= strchr(assignment
, '=');
2212 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2213 "Not an assignment: %s", assignment
);
2215 field
= strndupa(assignment
, eq
- assignment
);
2220 r
= bus_append_cgroup_property(m
, field
, eq
);
2224 r
= bus_append_execute_property(m
, field
, eq
);
2228 r
= bus_append_kill_property(m
, field
, eq
);
2232 r
= bus_append_service_property(m
, field
, eq
);
2238 r
= bus_append_cgroup_property(m
, field
, eq
);
2242 r
= bus_append_execute_property(m
, field
, eq
);
2246 r
= bus_append_kill_property(m
, field
, eq
);
2250 r
= bus_append_socket_property(m
, field
, eq
);
2256 r
= bus_append_timer_property(m
, field
, eq
);
2262 r
= bus_append_path_property(m
, field
, eq
);
2268 r
= bus_append_cgroup_property(m
, field
, eq
);
2274 r
= bus_append_cgroup_property(m
, field
, eq
);
2278 r
= bus_append_kill_property(m
, field
, eq
);
2282 r
= bus_append_scope_property(m
, field
, eq
);
2288 r
= bus_append_cgroup_property(m
, field
, eq
);
2292 r
= bus_append_execute_property(m
, field
, eq
);
2296 r
= bus_append_kill_property(m
, field
, eq
);
2300 r
= bus_append_mount_property(m
, field
, eq
);
2306 case UNIT_AUTOMOUNT
:
2307 r
= bus_append_automount_property(m
, field
, eq
);
2316 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2317 "Not supported unit type");
2320 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2321 "Invalid unit type");
2324 r
= bus_append_unit_property(m
, field
, eq
);
2328 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2329 "Unknown assignment: %s", assignment
);
2332 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
2338 STRV_FOREACH(i
, l
) {
2339 r
= bus_append_unit_property_assignment(m
, t
, *i
);
2347 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
2348 const char *type
, *path
, *source
;
2351 /* changes is dereferenced when calling unit_file_dump_changes() later,
2352 * so we have to make sure this is not NULL. */
2356 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2358 return bus_log_parse_error(r
);
2360 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2361 /* We expect only "success" changes to be sent over the bus.
2362 Hence, reject anything negative. */
2363 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
2366 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
2370 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2375 return bus_log_parse_error(r
);
2377 r
= sd_bus_message_exit_container(m
);
2379 return bus_log_parse_error(r
);
2381 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2385 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2386 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2387 _cleanup_free_
char *path
= NULL
;
2390 path
= unit_dbus_path_from_name(name
);
2394 /* This function warns on it's own, because otherwise it'd be awkward to pass
2395 * the dbus error message around. */
2397 r
= sd_bus_get_property_string(
2399 "org.freedesktop.systemd1",
2401 "org.freedesktop.systemd1.Unit",
2406 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));