1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2016 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include "alloc-util.h"
22 #include "bus-internal.h"
23 #include "bus-unit-util.h"
26 #include "cgroup-util.h"
27 #include "condition.h"
28 #include "cpu-set-util.h"
30 #include "errno-list.h"
33 #include "hexdecoct.h"
34 #include "hostname-util.h"
35 #include "in-addr-util.h"
37 #include "locale-util.h"
38 #include "mount-util.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 #include "process-util.h"
43 #include "rlimit-util.h"
44 #include "securebits-util.h"
45 #include "signal-util.h"
46 #include "socket-protocol-list.h"
47 #include "string-util.h"
48 #include "syslog-util.h"
49 #include "terminal-util.h"
51 #include "user-util.h"
55 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
61 return sd_bus_message_read(
76 #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
77 static int bus_append_##parse_func( \
84 r = parse_func(eq, &val); \
86 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
88 r = sd_bus_message_append(m, "(sv)", field, \
89 bus_type, (cast_type) val); \
91 return bus_log_create_error(r); \
96 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
97 static int bus_append_##parse_func( \
103 r = parse_func(eq); \
105 log_error("Failed to parse %s: %s", field, eq); \
109 r = sd_bus_message_append(m, "(sv)", field, \
110 bus_type, (int32_t) r); \
112 return bus_log_create_error(r); \
117 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
118 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
119 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
120 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
121 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
122 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
123 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
124 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
125 DEFINE_BUS_APPEND_PARSE("i", signal_from_string_try_harder
);
126 DEFINE_BUS_APPEND_PARSE("i", socket_protocol_from_name
);
127 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
128 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
129 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
130 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
131 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
132 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
133 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
134 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
135 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
136 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
137 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
138 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
140 static inline int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
143 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
145 return bus_log_create_error(r
);
150 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
154 r
= sd_bus_message_open_container(m
, 'r', "sv");
156 return bus_log_create_error(r
);
158 r
= sd_bus_message_append_basic(m
, 's', field
);
160 return bus_log_create_error(r
);
162 r
= sd_bus_message_open_container(m
, 'v', "as");
164 return bus_log_create_error(r
);
166 r
= sd_bus_message_open_container(m
, 'a', "s");
168 return bus_log_create_error(r
);
171 _cleanup_free_
char *word
= NULL
;
173 r
= extract_first_word(&p
, &word
, NULL
, flags
);
179 return log_error_errno(r
, "Invalid syntax: %s", eq
);
181 r
= sd_bus_message_append_basic(m
, 's', word
);
183 return bus_log_create_error(r
);
186 r
= sd_bus_message_close_container(m
);
188 return bus_log_create_error(r
);
190 r
= sd_bus_message_close_container(m
);
192 return bus_log_create_error(r
);
194 r
= sd_bus_message_close_container(m
);
196 return bus_log_create_error(r
);
201 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
204 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
206 return bus_log_create_error(r
);
208 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
210 return bus_log_create_error(r
);
212 r
= sd_bus_message_open_container(m
, 'v', "ay");
214 return bus_log_create_error(r
);
216 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
218 return bus_log_create_error(r
);
220 r
= sd_bus_message_close_container(m
);
222 return bus_log_create_error(r
);
224 r
= sd_bus_message_close_container(m
);
226 return bus_log_create_error(r
);
231 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
237 r
= parse_sec(eq
, &t
);
239 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
242 n
= newa(char, l
+ 2);
243 /* Change suffix Sec → USec */
244 strcpy(mempcpy(n
, field
, l
- 3), "USec");
246 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
248 return bus_log_create_error(r
);
253 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
257 r
= parse_size(eq
, base
, &v
);
259 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
261 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
263 return bus_log_create_error(r
);
268 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
269 bool ignore_failure
= false, explicit_path
= false, done
= false;
270 _cleanup_strv_free_
char **l
= NULL
;
271 _cleanup_free_
char *path
= NULL
;
281 ignore_failure
= true;
290 explicit_path
= true;
297 /* The bus API doesn't support +, ! and !! currently, unfortunately. :-( */
298 log_error("Sorry, but +, ! and !! are currently not supported for transient services.");
308 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
310 return log_error_errno(r
, "Failed to parse path: %m");
313 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
315 return log_error_errno(r
, "Failed to parse command line: %m");
317 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
319 return bus_log_create_error(r
);
321 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
323 return bus_log_create_error(r
);
325 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
327 return bus_log_create_error(r
);
329 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
331 return bus_log_create_error(r
);
333 if (!strv_isempty(l
)) {
335 r
= sd_bus_message_open_container(m
, 'r', "sasb");
337 return bus_log_create_error(r
);
339 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
341 return bus_log_create_error(r
);
343 r
= sd_bus_message_append_strv(m
, l
);
345 return bus_log_create_error(r
);
347 r
= sd_bus_message_append(m
, "b", ignore_failure
);
349 return bus_log_create_error(r
);
351 r
= sd_bus_message_close_container(m
);
353 return bus_log_create_error(r
);
356 r
= sd_bus_message_close_container(m
);
358 return bus_log_create_error(r
);
360 r
= sd_bus_message_close_container(m
);
362 return bus_log_create_error(r
);
364 r
= sd_bus_message_close_container(m
);
366 return bus_log_create_error(r
);
371 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
377 r
= sd_bus_message_open_container(m
, 'r', "iayu");
381 r
= sd_bus_message_append(m
, "i", family
);
385 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
389 r
= sd_bus_message_append(m
, "u", prefixlen
);
393 return sd_bus_message_close_container(m
);
396 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
399 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
401 return bus_append_string(m
, field
, eq
);
403 if (STR_IN_SET(field
,
404 "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
405 "TasksAccounting", "IPAccounting"))
407 return bus_append_parse_boolean(m
, field
, eq
);
409 if (STR_IN_SET(field
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
411 return bus_append_cg_weight_parse(m
, field
, eq
);
413 if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares"))
415 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
417 if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight"))
419 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
421 if (streq(field
, "Delegate")) {
423 r
= parse_boolean(eq
);
425 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_QUOTES
);
427 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
429 return bus_log_create_error(r
);
434 if (STR_IN_SET(field
, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
436 if (isempty(eq
) || streq(eq
, "infinity")) {
437 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
439 return bus_log_create_error(r
);
443 r
= parse_percent(eq
);
447 /* When this is a percentage we'll convert this into a relative value in the range
448 * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related
449 * ones). This way the physical memory size can be determined server-side */
451 n
= strjoina(field
, "Scale");
452 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) UINT32_MAX
* r
) / 100U));
454 return bus_log_create_error(r
);
459 if (streq(field
, "TasksMax"))
460 return bus_append_safe_atou64(m
, field
, eq
);
462 return bus_append_parse_size(m
, field
, eq
, 1024);
466 if (streq(field
, "CPUQuota")) {
469 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
471 r
= parse_percent_unbounded(eq
);
473 log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
477 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (usec_t
) r
* USEC_PER_SEC
/ 100U);
481 return bus_log_create_error(r
);
486 if (streq(field
, "DeviceAllow")) {
489 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
491 const char *path
= eq
, *rwm
= NULL
, *e
;
495 path
= strndupa(eq
, e
- eq
);
499 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
503 return bus_log_create_error(r
);
508 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
511 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
513 const char *path
, *bandwidth
, *e
;
518 log_error("Failed to parse %s value %s.", field
, eq
);
522 path
= strndupa(eq
, e
- eq
);
525 if (streq(bandwidth
, "infinity")) {
526 bytes
= CGROUP_LIMIT_MAX
;
528 r
= parse_size(bandwidth
, 1000, &bytes
);
530 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
533 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
537 return bus_log_create_error(r
);
542 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
545 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
547 const char *path
, *weight
, *e
;
552 log_error("Failed to parse %s value %s.", field
, eq
);
556 path
= strndupa(eq
, e
- eq
);
559 r
= safe_atou64(weight
, &u
);
561 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
563 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
567 return bus_log_create_error(r
);
572 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
573 unsigned char prefixlen
;
574 union in_addr_union prefix
= {};
578 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
580 return bus_log_create_error(r
);
585 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
587 return bus_log_create_error(r
);
589 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
591 return bus_log_create_error(r
);
593 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
595 return bus_log_create_error(r
);
597 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
599 return bus_log_create_error(r
);
601 if (streq(eq
, "any")) {
602 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
604 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
606 return bus_log_create_error(r
);
608 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
610 return bus_log_create_error(r
);
612 } else if (is_localhost(eq
)) {
613 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
615 prefix
.in
.s_addr
= htobe32(0x7f000000);
616 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
618 return bus_log_create_error(r
);
620 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
621 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
625 } else if (streq(eq
, "link-local")) {
626 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
628 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
629 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
631 return bus_log_create_error(r
);
633 prefix
.in6
= (struct in6_addr
) {
634 .s6_addr32
[0] = htobe32(0xfe800000)
636 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
638 return bus_log_create_error(r
);
640 } else if (streq(eq
, "multicast")) {
641 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
643 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
644 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
646 return bus_log_create_error(r
);
648 prefix
.in6
= (struct in6_addr
) {
649 .s6_addr32
[0] = htobe32(0xff000000)
651 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
653 return bus_log_create_error(r
);
656 r
= in_addr_prefix_from_string_auto(eq
, &family
, &prefix
, &prefixlen
);
658 return log_error_errno(r
, "Failed to parse IP address prefix: %s", eq
);
660 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
662 return bus_log_create_error(r
);
665 r
= sd_bus_message_close_container(m
);
667 return bus_log_create_error(r
);
669 r
= sd_bus_message_close_container(m
);
671 return bus_log_create_error(r
);
673 r
= sd_bus_message_close_container(m
);
675 return bus_log_create_error(r
);
683 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
685 if (streq(field
, "Where"))
687 return bus_append_string(m
, field
, eq
);
689 if (streq(field
, "DirectoryMode"))
691 return bus_append_parse_mode(m
, field
, eq
);
693 if (streq(field
, "TimeoutIdleSec"))
695 return bus_append_parse_sec_rename(m
, field
, eq
);
700 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
703 if (STR_IN_SET(field
,
705 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
706 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
707 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
708 "RuntimeDirectoryPreserve", "Personality", "KeyringMode"))
710 return bus_append_string(m
, field
, eq
);
712 if (STR_IN_SET(field
,
713 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
714 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
715 "NoNewPrivileges", "SyslogLevelPrefix",
716 "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
717 "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups",
718 "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality"))
720 return bus_append_parse_boolean(m
, field
, eq
);
722 if (STR_IN_SET(field
,
723 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
724 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
725 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
726 "SupplementaryGroups", "SystemCallArchitectures"))
728 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
730 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
732 return bus_append_log_level_from_string(m
, field
, eq
);
734 if (streq(field
, "SyslogFacility"))
736 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
738 if (streq(field
, "SecureBits"))
740 return bus_append_secure_bits_from_string(m
, field
, eq
);
742 if (streq(field
, "CPUSchedulingPolicy"))
744 return bus_append_sched_policy_from_string(m
, field
, eq
);
746 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
748 return bus_append_safe_atoi(m
, field
, eq
);
750 if (streq(field
, "Nice"))
752 return bus_append_parse_nice(m
, field
, eq
);
754 if (streq(field
, "SystemCallErrorNumber"))
756 return bus_append_parse_errno(m
, field
, eq
);
758 if (streq(field
, "IOSchedulingClass"))
760 return bus_append_ioprio_class_from_string(m
, field
, eq
);
762 if (streq(field
, "IOSchedulingPriority"))
764 return bus_append_ioprio_parse_priority(m
, field
, eq
);
766 if (STR_IN_SET(field
,
767 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
768 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
770 return bus_append_parse_mode(m
, field
, eq
);
772 if (streq(field
, "TimerSlackNSec"))
774 return bus_append_parse_nsec(m
, field
, eq
);
776 if (streq(field
, "MountFlags"))
778 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
780 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
782 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
784 if (streq(field
, "EnvironmentFile")) {
787 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
789 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
790 eq
[0] == '-' ? eq
+ 1 : eq
,
793 return bus_log_create_error(r
);
798 if (streq(field
, "LogExtraFields")) {
800 r
= sd_bus_message_open_container(m
, 'r', "sv");
802 return bus_log_create_error(r
);
804 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
806 return bus_log_create_error(r
);
808 r
= sd_bus_message_open_container(m
, 'v', "aay");
810 return bus_log_create_error(r
);
812 r
= sd_bus_message_open_container(m
, 'a', "ay");
814 return bus_log_create_error(r
);
816 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
818 return bus_log_create_error(r
);
820 r
= sd_bus_message_close_container(m
);
822 return bus_log_create_error(r
);
824 r
= sd_bus_message_close_container(m
);
826 return bus_log_create_error(r
);
828 r
= sd_bus_message_close_container(m
);
830 return bus_log_create_error(r
);
835 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
836 const char *n
, *appended
;
838 if ((n
= startswith(eq
, "fd:"))) {
839 appended
= strjoina(field
, "FileDescriptorName");
840 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
841 } else if ((n
= startswith(eq
, "file:"))) {
842 appended
= strjoina(field
, "File");
843 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
845 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
848 return bus_log_create_error(r
);
853 if (streq(field
, "StandardInputText")) {
854 _cleanup_free_
char *unescaped
= NULL
;
856 r
= cunescape(eq
, 0, &unescaped
);
858 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
860 if (!strextend(&unescaped
, "\n", NULL
))
863 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
864 * interface anyway */
866 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
869 if (streq(field
, "StandardInputData")) {
870 _cleanup_free_
void *decoded
= NULL
;
873 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
875 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
877 return bus_append_byte_array(m
, field
, decoded
, sz
);
880 rl
= rlimit_from_string(field
);
885 r
= rlimit_parse(rl
, eq
, &l
);
887 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
889 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
891 return bus_log_create_error(r
);
893 sn
= strjoina(field
, "Soft");
894 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
896 return bus_log_create_error(r
);
901 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
910 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
912 return bus_log_create_error(r
);
917 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
927 r
= capability_set_from_string(p
, &sum
);
929 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
931 sum
= invert
? ~sum
: sum
;
933 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
935 return bus_log_create_error(r
);
940 if (streq(field
, "CPUAffinity")) {
941 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
943 r
= parse_cpu_set(eq
, &cpuset
);
945 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
947 return bus_append_byte_array(m
, field
, cpuset
, CPU_ALLOC_SIZE(r
));
950 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
959 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
961 return bus_log_create_error(r
);
963 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
965 return bus_log_create_error(r
);
967 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
969 return bus_log_create_error(r
);
971 r
= sd_bus_message_open_container(m
, 'r', "bas");
973 return bus_log_create_error(r
);
975 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
977 return bus_log_create_error(r
);
979 r
= sd_bus_message_open_container(m
, 'a', "s");
981 return bus_log_create_error(r
);
984 _cleanup_free_
char *word
= NULL
;
986 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
992 return log_error_errno(r
, "Invalid syntax: %s", eq
);
994 r
= sd_bus_message_append_basic(m
, 's', word
);
996 return bus_log_create_error(r
);
999 r
= sd_bus_message_close_container(m
);
1001 return bus_log_create_error(r
);
1003 r
= sd_bus_message_close_container(m
);
1005 return bus_log_create_error(r
);
1007 r
= sd_bus_message_close_container(m
);
1009 return bus_log_create_error(r
);
1011 r
= sd_bus_message_close_container(m
);
1013 return bus_log_create_error(r
);
1018 if (streq(field
, "RestrictNamespaces")) {
1019 bool invert
= false;
1020 unsigned long flags
= 0;
1027 r
= parse_boolean(eq
);
1031 flags
= NAMESPACE_FLAGS_ALL
;
1033 r
= namespace_flag_from_string_many(eq
, &flags
);
1035 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1039 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1041 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1043 return bus_log_create_error(r
);
1048 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1051 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1053 return bus_log_create_error(r
);
1055 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1057 return bus_log_create_error(r
);
1059 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1061 return bus_log_create_error(r
);
1063 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1065 return bus_log_create_error(r
);
1068 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1069 char *s
= NULL
, *d
= NULL
;
1070 bool ignore_enoent
= false;
1071 uint64_t flags
= MS_REC
;
1073 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1075 return log_error_errno(r
, "Failed to parse argument: %m");
1081 ignore_enoent
= true;
1085 if (p
&& p
[-1] == ':') {
1086 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1088 return log_error_errno(r
, "Failed to parse argument: %m");
1090 log_error("Missing argument after ':': %s", eq
);
1096 if (p
&& p
[-1] == ':') {
1097 _cleanup_free_
char *options
= NULL
;
1099 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
1101 return log_error_errno(r
, "Failed to parse argument: %m");
1103 if (isempty(options
) || streq(options
, "rbind"))
1105 else if (streq(options
, "norbind"))
1108 log_error("Unknown options: %s", eq
);
1116 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1118 return bus_log_create_error(r
);
1121 r
= sd_bus_message_close_container(m
);
1123 return bus_log_create_error(r
);
1125 r
= sd_bus_message_close_container(m
);
1127 return bus_log_create_error(r
);
1129 r
= sd_bus_message_close_container(m
);
1131 return bus_log_create_error(r
);
1136 if (streq(field
, "TemporaryFileSystem")) {
1139 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1141 return bus_log_create_error(r
);
1143 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1145 return bus_log_create_error(r
);
1147 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1149 return bus_log_create_error(r
);
1151 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1153 return bus_log_create_error(r
);
1156 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1159 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1161 return log_error_errno(r
, "Failed to parse argument: %m");
1166 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1168 return log_error_errno(r
, "Failed to parse argument: %m");
1170 return log_error("Failed to parse argument: %m");
1172 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1174 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
);
1185 r
= sd_bus_message_close_container(m
);
1187 return bus_log_create_error(r
);
1195 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1197 if (streq(field
, "KillMode"))
1199 return bus_append_string(m
, field
, eq
);
1201 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1203 return bus_append_parse_boolean(m
, field
, eq
);
1205 if (streq(field
, "KillSignal"))
1207 return bus_append_signal_from_string_try_harder(m
, field
, eq
);
1212 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1214 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1216 return bus_append_string(m
, field
, eq
);
1218 if (streq(field
, "TimeoutSec"))
1220 return bus_append_parse_sec_rename(m
, field
, eq
);
1222 if (streq(field
, "DirectoryMode"))
1224 return bus_append_parse_mode(m
, field
, eq
);
1226 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1228 return bus_append_parse_boolean(m
, field
, eq
);
1233 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1236 if (streq(field
, "MakeDirectory"))
1238 return bus_append_parse_boolean(m
, field
, eq
);
1240 if (streq(field
, "DirectoryMode"))
1242 return bus_append_parse_mode(m
, field
, eq
);
1244 if (STR_IN_SET(field
,
1245 "PathExists", "PathExistsGlob", "PathChanged",
1246 "PathModified", "DirectoryNotEmpty")) {
1249 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1251 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1253 return bus_log_create_error(r
);
1261 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1264 if (STR_IN_SET(field
,
1265 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1266 "USBFunctionDescriptors", "USBFunctionStrings"))
1268 return bus_append_string(m
, field
, eq
);
1270 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1272 return bus_append_parse_boolean(m
, field
, eq
);
1274 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1276 return bus_append_parse_sec_rename(m
, field
, eq
);
1278 if (streq(field
, "TimeoutSec")) {
1280 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1284 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1287 if (streq(field
, "FileDescriptorStoreMax"))
1289 return bus_append_safe_atou(m
, field
, eq
);
1291 if (STR_IN_SET(field
,
1292 "ExecStartPre", "ExecStart", "ExecStartPost",
1293 "ExecReload", "ExecStop", "ExecStopPost"))
1295 return bus_append_exec_command(m
, field
, eq
);
1297 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1298 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1299 size_t sz_status
= 0, sz_signal
= 0;
1303 _cleanup_free_
char *word
= NULL
;
1306 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1312 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1314 r
= safe_atoi(word
, &val
);
1316 val
= signal_from_string_try_harder(word
);
1318 return log_error_errno(r
, "Invalid status or signal %s in %s: %m", word
, field
);
1320 signal
= reallocarray(signal
, sz_signal
+ 1, sizeof(int));
1324 signal
[sz_signal
++] = val
;
1326 status
= reallocarray(status
, sz_status
+ 1, sizeof(int));
1330 status
[sz_status
++] = val
;
1334 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1336 return bus_log_create_error(r
);
1338 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1340 return bus_log_create_error(r
);
1342 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1344 return bus_log_create_error(r
);
1346 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1348 return bus_log_create_error(r
);
1350 r
= sd_bus_message_append_array(m
, 'i', status
, sz_status
);
1352 return bus_log_create_error(r
);
1354 r
= sd_bus_message_append_array(m
, 'i', signal
, sz_signal
);
1356 return bus_log_create_error(r
);
1358 r
= sd_bus_message_close_container(m
);
1360 return bus_log_create_error(r
);
1362 r
= sd_bus_message_close_container(m
);
1364 return bus_log_create_error(r
);
1366 r
= sd_bus_message_close_container(m
);
1368 return bus_log_create_error(r
);
1376 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1379 if (STR_IN_SET(field
,
1380 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1381 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1383 return bus_append_parse_boolean(m
, field
, eq
);
1385 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1387 return bus_append_safe_atoi(m
, field
, eq
);
1389 if (streq(field
, "IPTOS"))
1391 return bus_append_ip_tos_from_string(m
, field
, eq
);
1393 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1395 return bus_append_safe_atou(m
, field
, eq
);
1397 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1399 return bus_append_parse_mode(m
, field
, eq
);
1401 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1403 return bus_append_safe_atoi64(m
, field
, eq
);
1405 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1407 return bus_append_parse_sec_rename(m
, field
, eq
);
1409 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1411 return bus_append_parse_size(m
, field
, eq
, 1024);
1413 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1415 return bus_append_exec_command(m
, field
, eq
);
1417 if (STR_IN_SET(field
,
1418 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1419 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1420 "SocketUser", "SocketGroup"))
1422 return bus_append_string(m
, field
, eq
);
1424 if (streq(field
, "Symlinks"))
1426 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1428 if (streq(field
, "SocketProtocol"))
1430 return bus_append_socket_protocol_from_name(m
, field
, eq
);
1432 if (STR_IN_SET(field
,
1433 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1434 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1437 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1439 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1441 return bus_log_create_error(r
);
1448 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1451 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent"))
1453 return bus_append_parse_boolean(m
, field
, eq
);
1455 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1457 return bus_append_parse_sec_rename(m
, field
, eq
);
1459 if (STR_IN_SET(field
,
1460 "OnActiveSec", "OnBootSec", "OnStartupSec",
1461 "OnUnitActiveSec","OnUnitInactiveSec")) {
1464 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1467 r
= parse_sec(eq
, &t
);
1469 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1471 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1474 return bus_log_create_error(r
);
1479 if (streq(field
, "OnCalendar")) {
1482 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1484 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1486 return bus_log_create_error(r
);
1494 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1495 ConditionType t
= _CONDITION_TYPE_INVALID
;
1496 bool is_condition
= false;
1499 if (STR_IN_SET(field
,
1500 "Description", "SourcePath", "OnFailureJobMode",
1501 "JobTimeoutAction", "JobTimeoutRebootArgument",
1502 "StartLimitAction", "FailureAction", "SuccessAction",
1503 "RebootArgument", "CollectMode"))
1505 return bus_append_string(m
, field
, eq
);
1507 if (STR_IN_SET(field
,
1508 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1509 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1511 return bus_append_parse_boolean(m
, field
, eq
);
1513 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1515 return bus_append_parse_sec_rename(m
, field
, eq
);
1517 if (streq(field
, "StartLimitBurst"))
1519 return bus_append_safe_atou(m
, field
, eq
);
1521 if (unit_dependency_from_string(field
) >= 0 ||
1522 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1524 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1526 t
= condition_type_from_string(field
);
1528 is_condition
= true;
1530 t
= assert_type_from_string(field
);
1533 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1536 int trigger
, negate
;
1538 trigger
= *p
== '|';
1546 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1547 field
, trigger
, negate
, p
);
1550 return bus_log_create_error(r
);
1558 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1559 const char *eq
, *field
;
1565 eq
= strchr(assignment
, '=');
1567 log_error("Not an assignment: %s", assignment
);
1571 field
= strndupa(assignment
, eq
- assignment
);
1576 r
= bus_append_cgroup_property(m
, field
, eq
);
1580 r
= bus_append_execute_property(m
, field
, eq
);
1584 r
= bus_append_kill_property(m
, field
, eq
);
1588 r
= bus_append_service_property(m
, field
, eq
);
1594 r
= bus_append_cgroup_property(m
, field
, eq
);
1598 r
= bus_append_execute_property(m
, field
, eq
);
1602 r
= bus_append_kill_property(m
, field
, eq
);
1606 r
= bus_append_socket_property(m
, field
, eq
);
1612 r
= bus_append_timer_property(m
, field
, eq
);
1618 r
= bus_append_path_property(m
, field
, eq
);
1624 r
= bus_append_cgroup_property(m
, field
, eq
);
1631 if (streq(field
, "TimeoutStopSec"))
1632 return bus_append_parse_sec_rename(m
, field
, eq
);
1634 r
= bus_append_cgroup_property(m
, field
, eq
);
1638 r
= bus_append_kill_property(m
, field
, eq
);
1644 r
= bus_append_cgroup_property(m
, field
, eq
);
1648 r
= bus_append_execute_property(m
, field
, eq
);
1652 r
= bus_append_kill_property(m
, field
, eq
);
1656 r
= bus_append_mount_property(m
, field
, eq
);
1662 case UNIT_AUTOMOUNT
:
1663 r
= bus_append_automount_property(m
, field
, eq
);
1672 log_error("Not supported unit type");
1676 log_error("Invalid unit type");
1680 r
= bus_append_unit_property(m
, field
, eq
);
1684 log_error("Unknown assignment: %s", assignment
);
1688 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1694 STRV_FOREACH(i
, l
) {
1695 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1703 typedef struct BusWaitForJobs
{
1710 sd_bus_slot
*slot_job_removed
;
1711 sd_bus_slot
*slot_disconnected
;
1714 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1717 log_error("Warning! D-Bus connection terminated.");
1718 sd_bus_close(sd_bus_message_get_bus(m
));
1723 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1724 const char *path
, *unit
, *result
;
1725 BusWaitForJobs
*d
= userdata
;
1733 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1735 bus_log_parse_error(r
);
1739 found
= set_remove(d
->jobs
, (char*) path
);
1745 if (!isempty(result
))
1746 d
->result
= strdup(result
);
1749 d
->name
= strdup(unit
);
1754 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1758 set_free_free(d
->jobs
);
1760 sd_bus_slot_unref(d
->slot_disconnected
);
1761 sd_bus_slot_unref(d
->slot_job_removed
);
1763 sd_bus_unref(d
->bus
);
1771 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1772 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1778 d
= new0(BusWaitForJobs
, 1);
1782 d
->bus
= sd_bus_ref(bus
);
1784 /* When we are a bus client we match by sender. Direct
1785 * connections OTOH have no initialized sender field, and
1786 * hence we ignore the sender then */
1787 r
= sd_bus_match_signal_async(
1789 &d
->slot_job_removed
,
1790 bus
->bus_client
? "org.freedesktop.systemd1" : NULL
,
1791 "/org/freedesktop/systemd1",
1792 "org.freedesktop.systemd1.Manager",
1794 match_job_removed
, NULL
, d
);
1798 r
= sd_bus_match_signal_async(
1800 &d
->slot_disconnected
,
1801 "org.freedesktop.DBus.Local",
1803 "org.freedesktop.DBus.Local",
1805 match_disconnected
, NULL
, d
);
1815 static int bus_process_wait(sd_bus
*bus
) {
1819 r
= sd_bus_process(bus
, NULL
);
1825 r
= sd_bus_wait(bus
, (uint64_t) -1);
1831 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1832 _cleanup_free_
char *dbus_path
= NULL
;
1838 if (!endswith(d
->name
, ".service"))
1841 dbus_path
= unit_dbus_path_from_name(d
->name
);
1845 return sd_bus_get_property_string(d
->bus
,
1846 "org.freedesktop.systemd1",
1848 "org.freedesktop.systemd1.Service",
1854 static const struct {
1855 const char *result
, *explanation
;
1856 } explanations
[] = {
1857 { "resources", "of unavailable resources or another system error" },
1858 { "protocol", "the service did not take the steps required by its unit configuration" },
1859 { "timeout", "a timeout was exceeded" },
1860 { "exit-code", "the control process exited with error code" },
1861 { "signal", "a fatal signal was delivered to the control process" },
1862 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1863 { "watchdog", "the service failed to send watchdog ping" },
1864 { "start-limit", "start of the service was attempted too often" }
1867 static void log_job_error_with_service_result(const char* service
, const char *result
, const char* const* extra_args
) {
1868 _cleanup_free_
char *service_shell_quoted
= NULL
;
1869 const char *systemctl
= "systemctl", *journalctl
= "journalctl";
1873 service_shell_quoted
= shell_maybe_quote(service
, ESCAPE_BACKSLASH
);
1875 if (!strv_isempty((char**) extra_args
)) {
1876 _cleanup_free_
char *t
;
1878 t
= strv_join((char**) extra_args
, " ");
1879 systemctl
= strjoina("systemctl ", t
? : "<args>");
1880 journalctl
= strjoina("journalctl ", t
? : "<args>");
1883 if (!isempty(result
)) {
1886 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1887 if (streq(result
, explanations
[i
].result
))
1890 if (i
< ELEMENTSOF(explanations
)) {
1891 log_error("Job for %s failed because %s.\n"
1892 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1894 explanations
[i
].explanation
,
1896 service_shell_quoted
?: "<service>",
1902 log_error("Job for %s failed.\n"
1903 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1906 service_shell_quoted
?: "<service>",
1910 /* For some results maybe additional explanation is required */
1911 if (streq_ptr(result
, "start-limit"))
1912 log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
1913 "followed by \"%1$s start %2$s\" again.",
1915 service_shell_quoted
?: "<service>");
1918 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1924 if (streq(d
->result
, "canceled"))
1925 log_error("Job for %s canceled.", strna(d
->name
));
1926 else if (streq(d
->result
, "timeout"))
1927 log_error("Job for %s timed out.", strna(d
->name
));
1928 else if (streq(d
->result
, "dependency"))
1929 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
1930 else if (streq(d
->result
, "invalid"))
1931 log_error("%s is not active, cannot reload.", strna(d
->name
));
1932 else if (streq(d
->result
, "assert"))
1933 log_error("Assertion failed on job for %s.", strna(d
->name
));
1934 else if (streq(d
->result
, "unsupported"))
1935 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
1936 else if (streq(d
->result
, "collected"))
1937 log_error("Queued job for %s was garbage collected.", strna(d
->name
));
1938 else if (!STR_IN_SET(d
->result
, "done", "skipped")) {
1940 _cleanup_free_
char *result
= NULL
;
1943 q
= bus_job_get_service_result(d
, &result
);
1945 log_debug_errno(q
, "Failed to get Result property of unit %s: %m", d
->name
);
1947 log_job_error_with_service_result(d
->name
, result
, extra_args
);
1949 log_error("Job failed. See \"journalctl -xe\" for details.");
1953 if (STR_IN_SET(d
->result
, "canceled", "collected"))
1955 else if (streq(d
->result
, "timeout"))
1957 else if (streq(d
->result
, "dependency"))
1959 else if (streq(d
->result
, "invalid"))
1961 else if (streq(d
->result
, "assert"))
1963 else if (streq(d
->result
, "unsupported"))
1965 else if (!STR_IN_SET(d
->result
, "done", "skipped"))
1971 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1976 while (!set_isempty(d
->jobs
)) {
1979 q
= bus_process_wait(d
->bus
);
1981 return log_error_errno(q
, "Failed to wait for response: %m");
1984 q
= check_wait_response(d
, quiet
, extra_args
);
1985 /* Return the first error as it is most likely to be
1987 if (q
< 0 && r
== 0)
1990 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
1993 d
->name
= mfree(d
->name
);
1994 d
->result
= mfree(d
->result
);
2000 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2005 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2009 return set_put_strdup(d
->jobs
, path
);
2012 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2015 r
= bus_wait_for_jobs_add(d
, path
);
2019 return bus_wait_for_jobs(d
, quiet
, NULL
);
2022 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2023 const char *type
, *path
, *source
;
2026 /* changes is dereferenced when calling unit_file_dump_changes() later,
2027 * so we have to make sure this is not NULL. */
2031 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2033 return bus_log_parse_error(r
);
2035 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2036 /* We expect only "success" changes to be sent over the bus.
2037 Hence, reject anything negative. */
2038 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
2041 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
2045 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2050 return bus_log_parse_error(r
);
2052 r
= sd_bus_message_exit_container(m
);
2054 return bus_log_parse_error(r
);
2056 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2062 bool is_const
; /* If false, cgroup_path should be free()'d */
2064 Hashmap
*pids
; /* PID → process name */
2067 struct CGroupInfo
*parent
;
2068 LIST_FIELDS(struct CGroupInfo
, siblings
);
2069 LIST_HEAD(struct CGroupInfo
, children
);
2073 static bool IS_ROOT(const char *p
) {
2074 return isempty(p
) || streq(p
, "/");
2077 static int add_cgroup(Hashmap
*cgroups
, const char *path
, bool is_const
, struct CGroupInfo
**ret
) {
2078 struct CGroupInfo
*parent
= NULL
, *cg
;
2087 cg
= hashmap_get(cgroups
, path
);
2093 if (!IS_ROOT(path
)) {
2096 e
= strrchr(path
, '/');
2100 pp
= strndupa(path
, e
- path
);
2104 r
= add_cgroup(cgroups
, pp
, false, &parent
);
2109 cg
= new0(struct CGroupInfo
, 1);
2114 cg
->cgroup_path
= (char*) path
;
2116 cg
->cgroup_path
= strdup(path
);
2117 if (!cg
->cgroup_path
) {
2123 cg
->is_const
= is_const
;
2124 cg
->parent
= parent
;
2126 r
= hashmap_put(cgroups
, cg
->cgroup_path
, cg
);
2129 free(cg
->cgroup_path
);
2135 LIST_PREPEND(siblings
, parent
->children
, cg
);
2136 parent
->n_children
++;
2143 static int add_process(
2149 struct CGroupInfo
*cg
;
2156 r
= add_cgroup(cgroups
, path
, true, &cg
);
2160 r
= hashmap_ensure_allocated(&cg
->pids
, &trivial_hash_ops
);
2164 return hashmap_put(cg
->pids
, PID_TO_PTR(pid
), (void*) name
);
2167 static void remove_cgroup(Hashmap
*cgroups
, struct CGroupInfo
*cg
) {
2171 while (cg
->children
)
2172 remove_cgroup(cgroups
, cg
->children
);
2174 hashmap_remove(cgroups
, cg
->cgroup_path
);
2177 free(cg
->cgroup_path
);
2179 hashmap_free(cg
->pids
);
2182 LIST_REMOVE(siblings
, cg
->parent
->children
, cg
);
2187 static int cgroup_info_compare_func(const void *a
, const void *b
) {
2188 const struct CGroupInfo
*x
= *(const struct CGroupInfo
* const*) a
, *y
= *(const struct CGroupInfo
* const*) b
;
2193 return strcmp(x
->cgroup_path
, y
->cgroup_path
);
2196 static int dump_processes(
2198 const char *cgroup_path
,
2201 OutputFlags flags
) {
2203 struct CGroupInfo
*cg
;
2208 if (IS_ROOT(cgroup_path
))
2211 cg
= hashmap_get(cgroups
, cgroup_path
);
2215 if (!hashmap_isempty(cg
->pids
)) {
2223 /* Order processes by their PID */
2224 pids
= newa(pid_t
, hashmap_size(cg
->pids
));
2226 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
)
2227 pids
[n
++] = PTR_TO_PID(pidp
);
2229 assert(n
== hashmap_size(cg
->pids
));
2230 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
2232 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2234 for (i
= 0; i
< n
; i
++) {
2235 _cleanup_free_
char *e
= NULL
;
2236 const char *special
;
2239 name
= hashmap_get(cg
->pids
, PID_TO_PTR(pids
[i
]));
2242 if (n_columns
!= 0) {
2245 k
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2247 e
= ellipsize(name
, k
, 100);
2252 more
= i
+1 < n
|| cg
->children
;
2253 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
2255 fprintf(stdout
, "%s%s%*"PID_PRI
" %s\n",
2264 struct CGroupInfo
**children
, *child
;
2267 /* Order subcgroups by their name */
2268 children
= newa(struct CGroupInfo
*, cg
->n_children
);
2269 LIST_FOREACH(siblings
, child
, cg
->children
)
2270 children
[n
++] = child
;
2271 assert(n
== cg
->n_children
);
2272 qsort_safe(children
, n
, sizeof(struct CGroupInfo
*), cgroup_info_compare_func
);
2275 n_columns
= MAX(LESS_BY(n_columns
, 2U), 20U);
2277 for (i
= 0; i
< n
; i
++) {
2278 _cleanup_free_
char *pp
= NULL
;
2279 const char *name
, *special
;
2282 child
= children
[i
];
2284 name
= strrchr(child
->cgroup_path
, '/');
2290 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
2292 fputs(prefix
, stdout
);
2293 fputs(special
, stdout
);
2294 fputs(name
, stdout
);
2295 fputc('\n', stdout
);
2297 special
= special_glyph(more
? TREE_VERTICAL
: TREE_SPACE
);
2299 pp
= strappend(prefix
, special
);
2303 r
= dump_processes(cgroups
, child
->cgroup_path
, pp
, n_columns
, flags
);
2313 static int dump_extra_processes(
2317 OutputFlags flags
) {
2319 _cleanup_free_ pid_t
*pids
= NULL
;
2320 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
2321 struct CGroupInfo
*cg
;
2322 size_t n_allocated
= 0, n
= 0, k
;
2326 /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
2327 * combined, sorted, linear list. */
2329 HASHMAP_FOREACH(cg
, cgroups
, i
) {
2337 if (hashmap_isempty(cg
->pids
))
2340 r
= hashmap_ensure_allocated(&names
, &trivial_hash_ops
);
2344 if (!GREEDY_REALLOC(pids
, n_allocated
, n
+ hashmap_size(cg
->pids
)))
2347 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
) {
2348 pids
[n
++] = PTR_TO_PID(pidp
);
2350 r
= hashmap_put(names
, pidp
, (void*) name
);
2359 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
2360 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2362 for (k
= 0; k
< n
; k
++) {
2363 _cleanup_free_
char *e
= NULL
;
2366 name
= hashmap_get(names
, PID_TO_PTR(pids
[k
]));
2369 if (n_columns
!= 0) {
2372 z
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2374 e
= ellipsize(name
, z
, 100);
2379 fprintf(stdout
, "%s%s %*" PID_PRI
" %s\n",
2381 special_glyph(TRIANGULAR_BULLET
),
2389 int unit_show_processes(
2392 const char *cgroup_path
,
2396 sd_bus_error
*error
) {
2398 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2399 Hashmap
*cgroups
= NULL
;
2400 struct CGroupInfo
*cg
;
2406 if (flags
& OUTPUT_FULL_WIDTH
)
2408 else if (n_columns
<= 0)
2409 n_columns
= columns();
2411 prefix
= strempty(prefix
);
2413 r
= sd_bus_call_method(
2415 "org.freedesktop.systemd1",
2416 "/org/freedesktop/systemd1",
2417 "org.freedesktop.systemd1.Manager",
2426 cgroups
= hashmap_new(&path_hash_ops
);
2430 r
= sd_bus_message_enter_container(reply
, 'a', "(sus)");
2435 const char *path
= NULL
, *name
= NULL
;
2438 r
= sd_bus_message_read(reply
, "(sus)", &path
, &pid
, &name
);
2444 r
= add_process(cgroups
, path
, pid
, name
);
2449 r
= sd_bus_message_exit_container(reply
);
2453 r
= dump_processes(cgroups
, cgroup_path
, prefix
, n_columns
, flags
);
2457 r
= dump_extra_processes(cgroups
, prefix
, n_columns
, flags
);
2460 while ((cg
= hashmap_first(cgroups
)))
2461 remove_cgroup(cgroups
, cg
);
2463 hashmap_free(cgroups
);