1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
4 #include "bus-internal.h"
5 #include "bus-unit-util.h"
8 #include "cgroup-util.h"
10 #include "cpu-set-util.h"
12 #include "errno-list.h"
15 #include "hexdecoct.h"
16 #include "hostname-util.h"
17 #include "in-addr-util.h"
18 #include "ip-protocol-list.h"
20 #include "locale-util.h"
21 #include "missing_fs.h"
22 #include "mountpoint-util.h"
24 #include "parse-util.h"
25 #include "path-util.h"
26 #include "process-util.h"
27 #include "rlimit-util.h"
28 #include "securebits-util.h"
29 #include "signal-util.h"
30 #include "string-util.h"
31 #include "syslog-util.h"
32 #include "terminal-util.h"
34 #include "user-util.h"
38 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
44 return sd_bus_message_read(
59 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
60 static int bus_append_##parse_func( \
67 r = parse_func(eq, &val); \
69 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
71 r = sd_bus_message_append(m, "(sv)", field, \
72 bus_type, (cast_type) val); \
74 return bus_log_create_error(r); \
79 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
80 static int bus_append_##parse_func( \
88 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
90 r = sd_bus_message_append(m, "(sv)", field, \
91 bus_type, (int32_t) r); \
93 return bus_log_create_error(r); \
98 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
99 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
100 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
101 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
102 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
103 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
104 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
105 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
106 DEFINE_BUS_APPEND_PARSE("i", signal_from_string
);
107 DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol
);
108 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
109 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
110 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
111 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
112 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
113 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
114 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
115 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
116 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
117 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
118 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
119 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
121 static int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
124 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
126 return bus_log_create_error(r
);
131 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
135 r
= sd_bus_message_open_container(m
, 'r', "sv");
137 return bus_log_create_error(r
);
139 r
= sd_bus_message_append_basic(m
, 's', field
);
141 return bus_log_create_error(r
);
143 r
= sd_bus_message_open_container(m
, 'v', "as");
145 return bus_log_create_error(r
);
147 r
= sd_bus_message_open_container(m
, 'a', "s");
149 return bus_log_create_error(r
);
152 _cleanup_free_
char *word
= NULL
;
154 r
= extract_first_word(&p
, &word
, NULL
, flags
);
160 return log_error_errno(r
, "Invalid syntax: %s", eq
);
162 r
= sd_bus_message_append_basic(m
, 's', word
);
164 return bus_log_create_error(r
);
167 r
= sd_bus_message_close_container(m
);
169 return bus_log_create_error(r
);
171 r
= sd_bus_message_close_container(m
);
173 return bus_log_create_error(r
);
175 r
= sd_bus_message_close_container(m
);
177 return bus_log_create_error(r
);
182 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
185 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
187 return bus_log_create_error(r
);
189 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
191 return bus_log_create_error(r
);
193 r
= sd_bus_message_open_container(m
, 'v', "ay");
195 return bus_log_create_error(r
);
197 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
199 return bus_log_create_error(r
);
201 r
= sd_bus_message_close_container(m
);
203 return bus_log_create_error(r
);
205 r
= sd_bus_message_close_container(m
);
207 return bus_log_create_error(r
);
212 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
218 r
= parse_sec(eq
, &t
);
220 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
223 n
= newa(char, l
+ 2);
224 /* Change suffix Sec → USec */
225 strcpy(mempcpy(n
, field
, l
- 3), "USec");
227 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
229 return bus_log_create_error(r
);
234 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
238 r
= parse_size(eq
, base
, &v
);
240 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
242 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
244 return bus_log_create_error(r
);
249 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
250 bool ignore_failure
= false, explicit_path
= false, done
= false;
251 _cleanup_strv_free_
char **l
= NULL
;
252 _cleanup_free_
char *path
= NULL
;
262 ignore_failure
= true;
271 explicit_path
= true;
278 /* The bus API doesn't support +, ! and !! currently, unfortunately. :-( */
279 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
280 "Sorry, but +, ! and !! are currently not supported for transient services.");
289 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
291 return log_error_errno(r
, "Failed to parse path: %m");
294 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
296 return log_error_errno(r
, "Failed to parse command line: %m");
298 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
300 return bus_log_create_error(r
);
302 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
304 return bus_log_create_error(r
);
306 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
308 return bus_log_create_error(r
);
310 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
312 return bus_log_create_error(r
);
314 if (!strv_isempty(l
)) {
316 r
= sd_bus_message_open_container(m
, 'r', "sasb");
318 return bus_log_create_error(r
);
320 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
322 return bus_log_create_error(r
);
324 r
= sd_bus_message_append_strv(m
, l
);
326 return bus_log_create_error(r
);
328 r
= sd_bus_message_append(m
, "b", ignore_failure
);
330 return bus_log_create_error(r
);
332 r
= sd_bus_message_close_container(m
);
334 return bus_log_create_error(r
);
337 r
= sd_bus_message_close_container(m
);
339 return bus_log_create_error(r
);
341 r
= sd_bus_message_close_container(m
);
343 return bus_log_create_error(r
);
345 r
= sd_bus_message_close_container(m
);
347 return bus_log_create_error(r
);
352 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
358 r
= sd_bus_message_open_container(m
, 'r', "iayu");
362 r
= sd_bus_message_append(m
, "i", family
);
366 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
370 r
= sd_bus_message_append(m
, "u", prefixlen
);
374 return sd_bus_message_close_container(m
);
377 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
380 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
382 return bus_append_string(m
, field
, eq
);
384 if (STR_IN_SET(field
,
385 "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
386 "TasksAccounting", "IPAccounting"))
388 return bus_append_parse_boolean(m
, field
, eq
);
390 if (STR_IN_SET(field
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
392 return bus_append_cg_weight_parse(m
, field
, eq
);
394 if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares"))
396 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
398 if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight"))
400 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
402 if (streq(field
, "Delegate")) {
404 r
= parse_boolean(eq
);
406 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_QUOTES
);
408 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
410 return bus_log_create_error(r
);
415 if (STR_IN_SET(field
, "MemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
417 if (isempty(eq
) || streq(eq
, "infinity")) {
418 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
420 return bus_log_create_error(r
);
424 r
= parse_permille(eq
);
428 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
429 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
430 * size can be determined server-side. */
432 n
= strjoina(field
, "Scale");
433 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) r
* UINT32_MAX
) / 1000U));
435 return bus_log_create_error(r
);
440 if (streq(field
, "TasksMax"))
441 return bus_append_safe_atou64(m
, field
, eq
);
443 return bus_append_parse_size(m
, field
, eq
, 1024);
446 if (streq(field
, "CPUQuota")) {
449 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
451 r
= parse_permille_unbounded(eq
);
453 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
454 "CPU quota too small.");
456 return log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
458 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r
* USEC_PER_SEC
) / 1000U));
462 return bus_log_create_error(r
);
467 if (streq(field
, "CPUQuotaPeriodSec")) {
468 usec_t u
= USEC_INFINITY
;
470 r
= parse_sec_def_infinity(eq
, &u
);
472 return log_error_errno(r
, "CPU quota period '%s' invalid.", eq
);
474 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPeriodUSec", "t", u
);
476 return bus_log_create_error(r
);
481 if (streq(field
, "DeviceAllow")) {
484 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
486 const char *path
= eq
, *rwm
= NULL
, *e
;
490 path
= strndupa(eq
, e
- eq
);
494 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
498 return bus_log_create_error(r
);
503 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
506 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
508 const char *path
, *bandwidth
, *e
;
513 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
514 "Failed to parse %s value %s.",
517 path
= strndupa(eq
, e
- eq
);
520 if (streq(bandwidth
, "infinity"))
521 bytes
= CGROUP_LIMIT_MAX
;
523 r
= parse_size(bandwidth
, 1000, &bytes
);
525 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
528 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
532 return bus_log_create_error(r
);
537 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
540 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
542 const char *path
, *weight
, *e
;
547 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
548 "Failed to parse %s value %s.",
551 path
= strndupa(eq
, e
- eq
);
554 r
= safe_atou64(weight
, &u
);
556 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
558 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
562 return bus_log_create_error(r
);
567 if (streq(field
, "IODeviceLatencyTargetSec")) {
568 const char *field_usec
= "IODeviceLatencyTargetUSec";
571 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", USEC_INFINITY
);
573 const char *path
, *target
, *e
;
578 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
579 "Failed to parse %s value %s.",
582 path
= strndupa(eq
, e
- eq
);
585 r
= parse_sec(target
, &usec
);
587 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, target
);
589 r
= sd_bus_message_append(m
, "(sv)", field_usec
, "a(st)", 1, path
, usec
);
593 return bus_log_create_error(r
);
598 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
599 unsigned char prefixlen
;
600 union in_addr_union prefix
= {};
604 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
606 return bus_log_create_error(r
);
611 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
613 return bus_log_create_error(r
);
615 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
617 return bus_log_create_error(r
);
619 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
621 return bus_log_create_error(r
);
623 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
625 return bus_log_create_error(r
);
627 if (streq(eq
, "any")) {
628 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
630 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
632 return bus_log_create_error(r
);
634 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
636 return bus_log_create_error(r
);
638 } else if (is_localhost(eq
)) {
639 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
641 prefix
.in
.s_addr
= htobe32(0x7f000000);
642 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
644 return bus_log_create_error(r
);
646 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
647 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
651 } else if (streq(eq
, "link-local")) {
652 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
654 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
655 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
657 return bus_log_create_error(r
);
659 prefix
.in6
= (struct in6_addr
) {
660 .s6_addr32
[0] = htobe32(0xfe800000)
662 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
664 return bus_log_create_error(r
);
666 } else if (streq(eq
, "multicast")) {
667 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
669 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
670 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
672 return bus_log_create_error(r
);
674 prefix
.in6
= (struct in6_addr
) {
675 .s6_addr32
[0] = htobe32(0xff000000)
677 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
679 return bus_log_create_error(r
);
683 _cleanup_free_
char *word
= NULL
;
685 r
= extract_first_word(&eq
, &word
, NULL
, 0);
691 return log_error_errno(r
, "Failed to parse %s: %s", field
, eq
);
693 r
= in_addr_prefix_from_string_auto(word
, &family
, &prefix
, &prefixlen
);
695 return log_error_errno(r
, "Failed to parse IP address prefix: %s", word
);
697 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
699 return bus_log_create_error(r
);
703 r
= sd_bus_message_close_container(m
);
705 return bus_log_create_error(r
);
707 r
= sd_bus_message_close_container(m
);
709 return bus_log_create_error(r
);
711 r
= sd_bus_message_close_container(m
);
713 return bus_log_create_error(r
);
721 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
723 if (streq(field
, "Where"))
725 return bus_append_string(m
, field
, eq
);
727 if (streq(field
, "DirectoryMode"))
729 return bus_append_parse_mode(m
, field
, eq
);
731 if (streq(field
, "TimeoutIdleSec"))
733 return bus_append_parse_sec_rename(m
, field
, eq
);
738 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
742 if (STR_IN_SET(field
,
744 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
745 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
746 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
747 "RuntimeDirectoryPreserve", "Personality", "KeyringMode"))
749 return bus_append_string(m
, field
, eq
);
751 if (STR_IN_SET(field
,
752 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
753 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
754 "PrivateMounts", "NoNewPrivileges", "SyslogLevelPrefix",
755 "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
756 "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups",
757 "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality", "ProtectHostname"))
759 return bus_append_parse_boolean(m
, field
, eq
);
761 if (STR_IN_SET(field
,
762 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
763 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
764 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
765 "SupplementaryGroups", "SystemCallArchitectures"))
767 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
769 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
771 return bus_append_log_level_from_string(m
, field
, eq
);
773 if (streq(field
, "SyslogFacility"))
775 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
777 if (streq(field
, "SecureBits"))
779 return bus_append_secure_bits_from_string(m
, field
, eq
);
781 if (streq(field
, "CPUSchedulingPolicy"))
783 return bus_append_sched_policy_from_string(m
, field
, eq
);
785 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
787 return bus_append_safe_atoi(m
, field
, eq
);
789 if (streq(field
, "Nice"))
791 return bus_append_parse_nice(m
, field
, eq
);
793 if (streq(field
, "SystemCallErrorNumber"))
795 return bus_append_parse_errno(m
, field
, eq
);
797 if (streq(field
, "IOSchedulingClass"))
799 return bus_append_ioprio_class_from_string(m
, field
, eq
);
801 if (streq(field
, "IOSchedulingPriority"))
803 return bus_append_ioprio_parse_priority(m
, field
, eq
);
805 if (STR_IN_SET(field
,
806 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
807 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
809 return bus_append_parse_mode(m
, field
, eq
);
811 if (streq(field
, "TimerSlackNSec"))
813 return bus_append_parse_nsec(m
, field
, eq
);
815 if (streq(field
, "LogRateLimitIntervalSec"))
817 return bus_append_parse_sec_rename(m
, field
, eq
);
819 if (streq(field
, "LogRateLimitBurst"))
821 return bus_append_safe_atou(m
, field
, eq
);
823 if (streq(field
, "MountFlags"))
825 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
827 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
829 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
831 if (streq(field
, "EnvironmentFile")) {
834 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
836 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
837 eq
[0] == '-' ? eq
+ 1 : eq
,
840 return bus_log_create_error(r
);
845 if (streq(field
, "LogExtraFields")) {
847 r
= sd_bus_message_open_container(m
, 'r', "sv");
849 return bus_log_create_error(r
);
851 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
853 return bus_log_create_error(r
);
855 r
= sd_bus_message_open_container(m
, 'v', "aay");
857 return bus_log_create_error(r
);
859 r
= sd_bus_message_open_container(m
, 'a', "ay");
861 return bus_log_create_error(r
);
863 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
865 return bus_log_create_error(r
);
867 r
= sd_bus_message_close_container(m
);
869 return bus_log_create_error(r
);
871 r
= sd_bus_message_close_container(m
);
873 return bus_log_create_error(r
);
875 r
= sd_bus_message_close_container(m
);
877 return bus_log_create_error(r
);
882 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
883 const char *n
, *appended
;
885 if ((n
= startswith(eq
, "fd:"))) {
886 appended
= strjoina(field
, "FileDescriptorName");
887 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
888 } else if ((n
= startswith(eq
, "file:"))) {
889 appended
= strjoina(field
, "File");
890 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
891 } else if ((n
= startswith(eq
, "append:"))) {
892 appended
= strjoina(field
, "FileToAppend");
893 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
895 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
897 return bus_log_create_error(r
);
902 if (streq(field
, "StandardInputText")) {
903 _cleanup_free_
char *unescaped
= NULL
;
905 r
= cunescape(eq
, 0, &unescaped
);
907 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
909 if (!strextend(&unescaped
, "\n", NULL
))
912 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
913 * interface anyway */
915 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
918 if (streq(field
, "StandardInputData")) {
919 _cleanup_free_
void *decoded
= NULL
;
922 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
924 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
926 return bus_append_byte_array(m
, field
, decoded
, sz
);
929 if ((suffix
= startswith(field
, "Limit"))) {
932 rl
= rlimit_from_string(suffix
);
937 r
= rlimit_parse(rl
, eq
, &l
);
939 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
941 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
943 return bus_log_create_error(r
);
945 sn
= strjoina(field
, "Soft");
946 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
948 return bus_log_create_error(r
);
954 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
963 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
965 return bus_log_create_error(r
);
970 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
980 r
= capability_set_from_string(p
, &sum
);
982 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
984 sum
= invert
? ~sum
: sum
;
986 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
988 return bus_log_create_error(r
);
993 if (streq(field
, "CPUAffinity")) {
994 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
996 r
= parse_cpu_set(eq
, &cpuset
);
998 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
1000 return bus_append_byte_array(m
, field
, cpuset
, CPU_ALLOC_SIZE(r
));
1003 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
1012 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1014 return bus_log_create_error(r
);
1016 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1018 return bus_log_create_error(r
);
1020 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
1022 return bus_log_create_error(r
);
1024 r
= sd_bus_message_open_container(m
, 'r', "bas");
1026 return bus_log_create_error(r
);
1028 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
1030 return bus_log_create_error(r
);
1032 r
= sd_bus_message_open_container(m
, 'a', "s");
1034 return bus_log_create_error(r
);
1037 _cleanup_free_
char *word
= NULL
;
1039 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1045 return log_error_errno(r
, "Invalid syntax: %s", eq
);
1047 r
= sd_bus_message_append_basic(m
, 's', word
);
1049 return bus_log_create_error(r
);
1052 r
= sd_bus_message_close_container(m
);
1054 return bus_log_create_error(r
);
1056 r
= sd_bus_message_close_container(m
);
1058 return bus_log_create_error(r
);
1060 r
= sd_bus_message_close_container(m
);
1062 return bus_log_create_error(r
);
1064 r
= sd_bus_message_close_container(m
);
1066 return bus_log_create_error(r
);
1071 if (streq(field
, "RestrictNamespaces")) {
1072 bool invert
= false;
1073 unsigned long flags
;
1075 r
= parse_boolean(eq
);
1079 flags
= NAMESPACE_FLAGS_ALL
;
1086 r
= namespace_flags_from_string(eq
, &flags
);
1088 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1092 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1094 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1096 return bus_log_create_error(r
);
1101 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1104 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1106 return bus_log_create_error(r
);
1108 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1110 return bus_log_create_error(r
);
1112 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1114 return bus_log_create_error(r
);
1116 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1118 return bus_log_create_error(r
);
1121 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1122 char *s
= NULL
, *d
= NULL
;
1123 bool ignore_enoent
= false;
1124 uint64_t flags
= MS_REC
;
1126 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1128 return log_error_errno(r
, "Failed to parse argument: %m");
1134 ignore_enoent
= true;
1138 if (p
&& p
[-1] == ':') {
1139 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1141 return log_error_errno(r
, "Failed to parse argument: %m");
1143 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1144 "Missing argument after ':': %s",
1149 if (p
&& p
[-1] == ':') {
1150 _cleanup_free_
char *options
= NULL
;
1152 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
1154 return log_error_errno(r
, "Failed to parse argument: %m");
1156 if (isempty(options
) || streq(options
, "rbind"))
1158 else if (streq(options
, "norbind"))
1161 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1162 "Unknown options: %s",
1168 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1170 return bus_log_create_error(r
);
1173 r
= sd_bus_message_close_container(m
);
1175 return bus_log_create_error(r
);
1177 r
= sd_bus_message_close_container(m
);
1179 return bus_log_create_error(r
);
1181 r
= sd_bus_message_close_container(m
);
1183 return bus_log_create_error(r
);
1188 if (streq(field
, "TemporaryFileSystem")) {
1191 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1193 return bus_log_create_error(r
);
1195 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1197 return bus_log_create_error(r
);
1199 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1201 return bus_log_create_error(r
);
1203 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1205 return bus_log_create_error(r
);
1208 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1211 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1213 return log_error_errno(r
, "Failed to parse argument: %m");
1218 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1220 return log_error_errno(r
, "Failed to parse argument: %m");
1222 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1223 "Failed to parse argument: %s",
1226 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1228 return bus_log_create_error(r
);
1231 r
= sd_bus_message_close_container(m
);
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
);
1241 return bus_log_create_error(r
);
1249 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1251 if (streq(field
, "KillMode"))
1253 return bus_append_string(m
, field
, eq
);
1255 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1257 return bus_append_parse_boolean(m
, field
, eq
);
1259 if (STR_IN_SET(field
, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
1261 return bus_append_signal_from_string(m
, field
, eq
);
1266 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1268 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1270 return bus_append_string(m
, field
, eq
);
1272 if (streq(field
, "TimeoutSec"))
1274 return bus_append_parse_sec_rename(m
, field
, eq
);
1276 if (streq(field
, "DirectoryMode"))
1278 return bus_append_parse_mode(m
, field
, eq
);
1280 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1282 return bus_append_parse_boolean(m
, field
, eq
);
1287 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1290 if (streq(field
, "MakeDirectory"))
1292 return bus_append_parse_boolean(m
, field
, eq
);
1294 if (streq(field
, "DirectoryMode"))
1296 return bus_append_parse_mode(m
, field
, eq
);
1298 if (STR_IN_SET(field
,
1299 "PathExists", "PathExistsGlob", "PathChanged",
1300 "PathModified", "DirectoryNotEmpty")) {
1303 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1305 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1307 return bus_log_create_error(r
);
1315 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1318 if (STR_IN_SET(field
,
1319 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1320 "USBFunctionDescriptors", "USBFunctionStrings"))
1322 return bus_append_string(m
, field
, eq
);
1324 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1326 return bus_append_parse_boolean(m
, field
, eq
);
1328 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1330 return bus_append_parse_sec_rename(m
, field
, eq
);
1332 if (streq(field
, "TimeoutSec")) {
1334 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1338 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1341 if (streq(field
, "FileDescriptorStoreMax"))
1343 return bus_append_safe_atou(m
, field
, eq
);
1345 if (STR_IN_SET(field
,
1346 "ExecStartPre", "ExecStart", "ExecStartPost",
1347 "ExecReload", "ExecStop", "ExecStopPost"))
1349 return bus_append_exec_command(m
, field
, eq
);
1351 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1352 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1353 size_t sz_status
= 0, sz_signal
= 0;
1357 _cleanup_free_
char *word
= NULL
;
1360 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1366 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1368 r
= safe_atoi(word
, &val
);
1370 val
= signal_from_string(word
);
1372 return log_error_errno(r
, "Invalid status or signal %s in %s: %m", word
, field
);
1374 signal
= reallocarray(signal
, sz_signal
+ 1, sizeof(int));
1378 signal
[sz_signal
++] = val
;
1380 status
= reallocarray(status
, sz_status
+ 1, sizeof(int));
1384 status
[sz_status
++] = val
;
1388 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1390 return bus_log_create_error(r
);
1392 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1394 return bus_log_create_error(r
);
1396 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1398 return bus_log_create_error(r
);
1400 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1402 return bus_log_create_error(r
);
1404 r
= sd_bus_message_append_array(m
, 'i', status
, sz_status
);
1406 return bus_log_create_error(r
);
1408 r
= sd_bus_message_append_array(m
, 'i', signal
, sz_signal
);
1410 return bus_log_create_error(r
);
1412 r
= sd_bus_message_close_container(m
);
1414 return bus_log_create_error(r
);
1416 r
= sd_bus_message_close_container(m
);
1418 return bus_log_create_error(r
);
1420 r
= sd_bus_message_close_container(m
);
1422 return bus_log_create_error(r
);
1430 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1433 if (STR_IN_SET(field
,
1434 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1435 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1437 return bus_append_parse_boolean(m
, field
, eq
);
1439 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1441 return bus_append_safe_atoi(m
, field
, eq
);
1443 if (streq(field
, "IPTOS"))
1445 return bus_append_ip_tos_from_string(m
, field
, eq
);
1447 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1449 return bus_append_safe_atou(m
, field
, eq
);
1451 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1453 return bus_append_parse_mode(m
, field
, eq
);
1455 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1457 return bus_append_safe_atoi64(m
, field
, eq
);
1459 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1461 return bus_append_parse_sec_rename(m
, field
, eq
);
1463 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1465 return bus_append_parse_size(m
, field
, eq
, 1024);
1467 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1469 return bus_append_exec_command(m
, field
, eq
);
1471 if (STR_IN_SET(field
,
1472 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1473 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1474 "SocketUser", "SocketGroup"))
1476 return bus_append_string(m
, field
, eq
);
1478 if (streq(field
, "Symlinks"))
1480 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1482 if (streq(field
, "SocketProtocol"))
1484 return bus_append_parse_ip_protocol(m
, field
, eq
);
1486 if (STR_IN_SET(field
,
1487 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1488 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1491 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1493 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1495 return bus_log_create_error(r
);
1502 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1505 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent"))
1507 return bus_append_parse_boolean(m
, field
, eq
);
1509 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1511 return bus_append_parse_sec_rename(m
, field
, eq
);
1513 if (STR_IN_SET(field
,
1514 "OnActiveSec", "OnBootSec", "OnStartupSec",
1515 "OnUnitActiveSec","OnUnitInactiveSec")) {
1518 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1521 r
= parse_sec(eq
, &t
);
1523 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1525 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1528 return bus_log_create_error(r
);
1533 if (streq(field
, "OnCalendar")) {
1536 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1538 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1540 return bus_log_create_error(r
);
1548 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1549 ConditionType t
= _CONDITION_TYPE_INVALID
;
1550 bool is_condition
= false;
1553 if (STR_IN_SET(field
,
1554 "Description", "SourcePath", "OnFailureJobMode",
1555 "JobTimeoutAction", "JobTimeoutRebootArgument",
1556 "StartLimitAction", "FailureAction", "SuccessAction",
1557 "RebootArgument", "CollectMode"))
1559 return bus_append_string(m
, field
, eq
);
1561 if (STR_IN_SET(field
,
1562 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1563 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1565 return bus_append_parse_boolean(m
, field
, eq
);
1567 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1569 return bus_append_parse_sec_rename(m
, field
, eq
);
1571 if (streq(field
, "StartLimitBurst"))
1573 return bus_append_safe_atou(m
, field
, eq
);
1575 if (STR_IN_SET(field
, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1578 r
= sd_bus_message_append(m
, "(sv)", field
, "i", -1);
1582 r
= safe_atou8(eq
, &u
);
1584 return log_error_errno(r
, "Failed to parse %s=%s", field
, eq
);
1586 r
= sd_bus_message_append(m
, "(sv)", field
, "i", (int) u
);
1589 return bus_log_create_error(r
);
1594 if (unit_dependency_from_string(field
) >= 0 ||
1595 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1597 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1599 t
= condition_type_from_string(field
);
1601 is_condition
= true;
1603 t
= assert_type_from_string(field
);
1606 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1609 int trigger
, negate
;
1611 trigger
= *p
== '|';
1619 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1620 field
, trigger
, negate
, p
);
1623 return bus_log_create_error(r
);
1631 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1632 const char *eq
, *field
;
1638 eq
= strchr(assignment
, '=');
1640 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1641 "Not an assignment: %s", assignment
);
1643 field
= strndupa(assignment
, eq
- assignment
);
1648 r
= bus_append_cgroup_property(m
, field
, eq
);
1652 r
= bus_append_execute_property(m
, field
, eq
);
1656 r
= bus_append_kill_property(m
, field
, eq
);
1660 r
= bus_append_service_property(m
, field
, eq
);
1666 r
= bus_append_cgroup_property(m
, field
, eq
);
1670 r
= bus_append_execute_property(m
, field
, eq
);
1674 r
= bus_append_kill_property(m
, field
, eq
);
1678 r
= bus_append_socket_property(m
, field
, eq
);
1684 r
= bus_append_timer_property(m
, field
, eq
);
1690 r
= bus_append_path_property(m
, field
, eq
);
1696 r
= bus_append_cgroup_property(m
, field
, eq
);
1703 if (streq(field
, "TimeoutStopSec"))
1704 return bus_append_parse_sec_rename(m
, field
, eq
);
1706 r
= bus_append_cgroup_property(m
, field
, eq
);
1710 r
= bus_append_kill_property(m
, field
, eq
);
1716 r
= bus_append_cgroup_property(m
, field
, eq
);
1720 r
= bus_append_execute_property(m
, field
, eq
);
1724 r
= bus_append_kill_property(m
, field
, eq
);
1728 r
= bus_append_mount_property(m
, field
, eq
);
1734 case UNIT_AUTOMOUNT
:
1735 r
= bus_append_automount_property(m
, field
, eq
);
1744 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1745 "Not supported unit type");
1748 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1749 "Invalid unit type");
1752 r
= bus_append_unit_property(m
, field
, eq
);
1756 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1757 "Unknown assignment: %s", assignment
);
1760 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1766 STRV_FOREACH(i
, l
) {
1767 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1775 typedef struct BusWaitForJobs
{
1782 sd_bus_slot
*slot_job_removed
;
1783 sd_bus_slot
*slot_disconnected
;
1786 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1789 log_error("Warning! D-Bus connection terminated.");
1790 sd_bus_close(sd_bus_message_get_bus(m
));
1795 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1796 const char *path
, *unit
, *result
;
1797 BusWaitForJobs
*d
= userdata
;
1805 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1807 bus_log_parse_error(r
);
1811 found
= set_remove(d
->jobs
, (char*) path
);
1817 if (!isempty(result
))
1818 d
->result
= strdup(result
);
1821 d
->name
= strdup(unit
);
1826 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1830 set_free_free(d
->jobs
);
1832 sd_bus_slot_unref(d
->slot_disconnected
);
1833 sd_bus_slot_unref(d
->slot_job_removed
);
1835 sd_bus_unref(d
->bus
);
1843 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1844 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1850 d
= new0(BusWaitForJobs
, 1);
1854 d
->bus
= sd_bus_ref(bus
);
1856 /* When we are a bus client we match by sender. Direct
1857 * connections OTOH have no initialized sender field, and
1858 * hence we ignore the sender then */
1859 r
= sd_bus_match_signal_async(
1861 &d
->slot_job_removed
,
1862 bus
->bus_client
? "org.freedesktop.systemd1" : NULL
,
1863 "/org/freedesktop/systemd1",
1864 "org.freedesktop.systemd1.Manager",
1866 match_job_removed
, NULL
, d
);
1870 r
= sd_bus_match_signal_async(
1872 &d
->slot_disconnected
,
1873 "org.freedesktop.DBus.Local",
1875 "org.freedesktop.DBus.Local",
1877 match_disconnected
, NULL
, d
);
1886 static int bus_process_wait(sd_bus
*bus
) {
1890 r
= sd_bus_process(bus
, NULL
);
1896 r
= sd_bus_wait(bus
, (uint64_t) -1);
1902 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1903 _cleanup_free_
char *dbus_path
= NULL
;
1909 if (!endswith(d
->name
, ".service"))
1912 dbus_path
= unit_dbus_path_from_name(d
->name
);
1916 return sd_bus_get_property_string(d
->bus
,
1917 "org.freedesktop.systemd1",
1919 "org.freedesktop.systemd1.Service",
1925 static const struct {
1926 const char *result
, *explanation
;
1927 } explanations
[] = {
1928 { "resources", "of unavailable resources or another system error" },
1929 { "protocol", "the service did not take the steps required by its unit configuration" },
1930 { "timeout", "a timeout was exceeded" },
1931 { "exit-code", "the control process exited with error code" },
1932 { "signal", "a fatal signal was delivered to the control process" },
1933 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1934 { "watchdog", "the service failed to send watchdog ping" },
1935 { "start-limit", "start of the service was attempted too often" }
1938 static void log_job_error_with_service_result(const char* service
, const char *result
, const char* const* extra_args
) {
1939 _cleanup_free_
char *service_shell_quoted
= NULL
;
1940 const char *systemctl
= "systemctl", *journalctl
= "journalctl";
1944 service_shell_quoted
= shell_maybe_quote(service
, ESCAPE_BACKSLASH
);
1946 if (!strv_isempty((char**) extra_args
)) {
1947 _cleanup_free_
char *t
;
1949 t
= strv_join((char**) extra_args
, " ");
1950 systemctl
= strjoina("systemctl ", t
? : "<args>");
1951 journalctl
= strjoina("journalctl ", t
? : "<args>");
1954 if (!isempty(result
)) {
1957 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1958 if (streq(result
, explanations
[i
].result
))
1961 if (i
< ELEMENTSOF(explanations
)) {
1962 log_error("Job for %s failed because %s.\n"
1963 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1965 explanations
[i
].explanation
,
1967 service_shell_quoted
?: "<service>",
1973 log_error("Job for %s failed.\n"
1974 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1977 service_shell_quoted
?: "<service>",
1981 /* For some results maybe additional explanation is required */
1982 if (streq_ptr(result
, "start-limit"))
1983 log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
1984 "followed by \"%1$s start %2$s\" again.",
1986 service_shell_quoted
?: "<service>");
1989 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1993 if (streq(d
->result
, "canceled"))
1994 log_error("Job for %s canceled.", strna(d
->name
));
1995 else if (streq(d
->result
, "timeout"))
1996 log_error("Job for %s timed out.", strna(d
->name
));
1997 else if (streq(d
->result
, "dependency"))
1998 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
1999 else if (streq(d
->result
, "invalid"))
2000 log_error("%s is not active, cannot reload.", strna(d
->name
));
2001 else if (streq(d
->result
, "assert"))
2002 log_error("Assertion failed on job for %s.", strna(d
->name
));
2003 else if (streq(d
->result
, "unsupported"))
2004 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
2005 else if (streq(d
->result
, "collected"))
2006 log_error("Queued job for %s was garbage collected.", strna(d
->name
));
2007 else if (streq(d
->result
, "once"))
2008 log_error("Unit %s was started already once and can't be started again.", strna(d
->name
));
2009 else if (!STR_IN_SET(d
->result
, "done", "skipped")) {
2011 _cleanup_free_
char *result
= NULL
;
2014 q
= bus_job_get_service_result(d
, &result
);
2016 log_debug_errno(q
, "Failed to get Result property of unit %s: %m", d
->name
);
2018 log_job_error_with_service_result(d
->name
, result
, extra_args
);
2020 log_error("Job failed. See \"journalctl -xe\" for details.");
2024 if (STR_IN_SET(d
->result
, "canceled", "collected"))
2026 else if (streq(d
->result
, "timeout"))
2028 else if (streq(d
->result
, "dependency"))
2030 else if (streq(d
->result
, "invalid"))
2032 else if (streq(d
->result
, "assert"))
2034 else if (streq(d
->result
, "unsupported"))
2036 else if (streq(d
->result
, "once"))
2038 else if (STR_IN_SET(d
->result
, "done", "skipped"))
2041 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
2042 "Unexpected job result, assuming server side newer than us: %s", d
->result
);
2045 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
2050 while (!set_isempty(d
->jobs
)) {
2053 q
= bus_process_wait(d
->bus
);
2055 return log_error_errno(q
, "Failed to wait for response: %m");
2058 q
= check_wait_response(d
, quiet
, extra_args
);
2059 /* Return the first error as it is most likely to be
2061 if (q
< 0 && r
== 0)
2064 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
2067 d
->name
= mfree(d
->name
);
2068 d
->result
= mfree(d
->result
);
2074 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2079 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2083 return set_put_strdup(d
->jobs
, path
);
2086 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2089 r
= bus_wait_for_jobs_add(d
, path
);
2093 return bus_wait_for_jobs(d
, quiet
, NULL
);
2096 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, size_t *n_changes
) {
2097 const char *type
, *path
, *source
;
2100 /* changes is dereferenced when calling unit_file_dump_changes() later,
2101 * so we have to make sure this is not NULL. */
2105 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2107 return bus_log_parse_error(r
);
2109 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2110 /* We expect only "success" changes to be sent over the bus.
2111 Hence, reject anything negative. */
2112 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
2115 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
2119 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2124 return bus_log_parse_error(r
);
2126 r
= sd_bus_message_exit_container(m
);
2128 return bus_log_parse_error(r
);
2130 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2136 bool is_const
; /* If false, cgroup_path should be free()'d */
2138 Hashmap
*pids
; /* PID → process name */
2141 struct CGroupInfo
*parent
;
2142 LIST_FIELDS(struct CGroupInfo
, siblings
);
2143 LIST_HEAD(struct CGroupInfo
, children
);
2147 static bool IS_ROOT(const char *p
) {
2148 return isempty(p
) || streq(p
, "/");
2151 static int add_cgroup(Hashmap
*cgroups
, const char *path
, bool is_const
, struct CGroupInfo
**ret
) {
2152 struct CGroupInfo
*parent
= NULL
, *cg
;
2161 cg
= hashmap_get(cgroups
, path
);
2167 if (!IS_ROOT(path
)) {
2170 e
= strrchr(path
, '/');
2174 pp
= strndupa(path
, e
- path
);
2178 r
= add_cgroup(cgroups
, pp
, false, &parent
);
2183 cg
= new0(struct CGroupInfo
, 1);
2188 cg
->cgroup_path
= (char*) path
;
2190 cg
->cgroup_path
= strdup(path
);
2191 if (!cg
->cgroup_path
) {
2197 cg
->is_const
= is_const
;
2198 cg
->parent
= parent
;
2200 r
= hashmap_put(cgroups
, cg
->cgroup_path
, cg
);
2203 free(cg
->cgroup_path
);
2209 LIST_PREPEND(siblings
, parent
->children
, cg
);
2210 parent
->n_children
++;
2217 static int add_process(
2223 struct CGroupInfo
*cg
;
2230 r
= add_cgroup(cgroups
, path
, true, &cg
);
2234 r
= hashmap_ensure_allocated(&cg
->pids
, &trivial_hash_ops
);
2238 return hashmap_put(cg
->pids
, PID_TO_PTR(pid
), (void*) name
);
2241 static void remove_cgroup(Hashmap
*cgroups
, struct CGroupInfo
*cg
) {
2245 while (cg
->children
)
2246 remove_cgroup(cgroups
, cg
->children
);
2248 hashmap_remove(cgroups
, cg
->cgroup_path
);
2251 free(cg
->cgroup_path
);
2253 hashmap_free(cg
->pids
);
2256 LIST_REMOVE(siblings
, cg
->parent
->children
, cg
);
2261 static int cgroup_info_compare_func(struct CGroupInfo
* const *a
, struct CGroupInfo
* const *b
) {
2262 return strcmp((*a
)->cgroup_path
, (*b
)->cgroup_path
);
2265 static int dump_processes(
2267 const char *cgroup_path
,
2270 OutputFlags flags
) {
2272 struct CGroupInfo
*cg
;
2277 if (IS_ROOT(cgroup_path
))
2280 cg
= hashmap_get(cgroups
, cgroup_path
);
2284 if (!hashmap_isempty(cg
->pids
)) {
2292 /* Order processes by their PID */
2293 pids
= newa(pid_t
, hashmap_size(cg
->pids
));
2295 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
)
2296 pids
[n
++] = PTR_TO_PID(pidp
);
2298 assert(n
== hashmap_size(cg
->pids
));
2299 typesafe_qsort(pids
, n
, pid_compare_func
);
2301 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2303 for (i
= 0; i
< n
; i
++) {
2304 _cleanup_free_
char *e
= NULL
;
2305 const char *special
;
2308 name
= hashmap_get(cg
->pids
, PID_TO_PTR(pids
[i
]));
2311 if (n_columns
!= 0) {
2314 k
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2316 e
= ellipsize(name
, k
, 100);
2321 more
= i
+1 < n
|| cg
->children
;
2322 special
= special_glyph(more
? SPECIAL_GLYPH_TREE_BRANCH
: SPECIAL_GLYPH_TREE_RIGHT
);
2324 fprintf(stdout
, "%s%s%*"PID_PRI
" %s\n",
2333 struct CGroupInfo
**children
, *child
;
2336 /* Order subcgroups by their name */
2337 children
= newa(struct CGroupInfo
*, cg
->n_children
);
2338 LIST_FOREACH(siblings
, child
, cg
->children
)
2339 children
[n
++] = child
;
2340 assert(n
== cg
->n_children
);
2341 typesafe_qsort(children
, n
, cgroup_info_compare_func
);
2344 n_columns
= MAX(LESS_BY(n_columns
, 2U), 20U);
2346 for (i
= 0; i
< n
; i
++) {
2347 _cleanup_free_
char *pp
= NULL
;
2348 const char *name
, *special
;
2351 child
= children
[i
];
2353 name
= strrchr(child
->cgroup_path
, '/');
2359 special
= special_glyph(more
? SPECIAL_GLYPH_TREE_BRANCH
: SPECIAL_GLYPH_TREE_RIGHT
);
2361 fputs(prefix
, stdout
);
2362 fputs(special
, stdout
);
2363 fputs(name
, stdout
);
2364 fputc('\n', stdout
);
2366 special
= special_glyph(more
? SPECIAL_GLYPH_TREE_VERTICAL
: SPECIAL_GLYPH_TREE_SPACE
);
2368 pp
= strappend(prefix
, special
);
2372 r
= dump_processes(cgroups
, child
->cgroup_path
, pp
, n_columns
, flags
);
2382 static int dump_extra_processes(
2386 OutputFlags flags
) {
2388 _cleanup_free_ pid_t
*pids
= NULL
;
2389 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
2390 struct CGroupInfo
*cg
;
2391 size_t n_allocated
= 0, n
= 0, k
;
2395 /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
2396 * combined, sorted, linear list. */
2398 HASHMAP_FOREACH(cg
, cgroups
, i
) {
2406 if (hashmap_isempty(cg
->pids
))
2409 r
= hashmap_ensure_allocated(&names
, &trivial_hash_ops
);
2413 if (!GREEDY_REALLOC(pids
, n_allocated
, n
+ hashmap_size(cg
->pids
)))
2416 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
) {
2417 pids
[n
++] = PTR_TO_PID(pidp
);
2419 r
= hashmap_put(names
, pidp
, (void*) name
);
2428 typesafe_qsort(pids
, n
, pid_compare_func
);
2429 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2431 for (k
= 0; k
< n
; k
++) {
2432 _cleanup_free_
char *e
= NULL
;
2435 name
= hashmap_get(names
, PID_TO_PTR(pids
[k
]));
2438 if (n_columns
!= 0) {
2441 z
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2443 e
= ellipsize(name
, z
, 100);
2448 fprintf(stdout
, "%s%s %*" PID_PRI
" %s\n",
2450 special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET
),
2458 int unit_show_processes(
2461 const char *cgroup_path
,
2465 sd_bus_error
*error
) {
2467 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2468 Hashmap
*cgroups
= NULL
;
2469 struct CGroupInfo
*cg
;
2475 if (flags
& OUTPUT_FULL_WIDTH
)
2477 else if (n_columns
<= 0)
2478 n_columns
= columns();
2480 prefix
= strempty(prefix
);
2482 r
= sd_bus_call_method(
2484 "org.freedesktop.systemd1",
2485 "/org/freedesktop/systemd1",
2486 "org.freedesktop.systemd1.Manager",
2495 cgroups
= hashmap_new(&path_hash_ops
);
2499 r
= sd_bus_message_enter_container(reply
, 'a', "(sus)");
2504 const char *path
= NULL
, *name
= NULL
;
2507 r
= sd_bus_message_read(reply
, "(sus)", &path
, &pid
, &name
);
2513 r
= add_process(cgroups
, path
, pid
, name
);
2518 r
= sd_bus_message_exit_container(reply
);
2522 r
= dump_processes(cgroups
, cgroup_path
, prefix
, n_columns
, flags
);
2526 r
= dump_extra_processes(cgroups
, prefix
, n_columns
, flags
);
2529 while ((cg
= hashmap_first(cgroups
)))
2530 remove_cgroup(cgroups
, cg
);
2532 hashmap_free(cgroups
);
2537 int unit_load_state(sd_bus
*bus
, const char *name
, char **load_state
) {
2538 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2539 _cleanup_free_
char *path
= NULL
;
2542 path
= unit_dbus_path_from_name(name
);
2546 /* This function warns on it's own, because otherwise it'd be awkward to pass
2547 * the dbus error message around. */
2549 r
= sd_bus_get_property_string(
2551 "org.freedesktop.systemd1",
2553 "org.freedesktop.systemd1.Unit",
2558 return log_error_errno(r
, "Failed to get load state of %s: %s", name
, bus_error_message(&error
, r
));