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); \
95 struct __useless_struct_to_allow_trailing_semicolon__
97 #define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
98 static int bus_append_##parse_func( \
104 r = parse_func(eq); \
106 log_error("Failed to parse %s: %s", field, eq); \
110 r = sd_bus_message_append(m, "(sv)", field, \
111 bus_type, (int32_t) r); \
113 return bus_log_create_error(r); \
117 struct __useless_struct_to_allow_trailing_semicolon__
119 DEFINE_BUS_APPEND_PARSE("b", parse_boolean
);
120 DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string
);
121 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string
);
122 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string
);
123 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string
);
124 DEFINE_BUS_APPEND_PARSE("i", parse_errno
);
125 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string
);
126 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string
);
127 DEFINE_BUS_APPEND_PARSE("i", signal_from_string_try_harder
);
128 DEFINE_BUS_APPEND_PARSE("i", socket_protocol_from_name
);
129 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority
);
130 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice
);
131 DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi
);
132 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t
, parse_nsec
);
133 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse
);
134 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse
);
135 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse
);
136 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string
);
137 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64
);
138 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t
, parse_mode
);
139 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou
);
140 DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64
);
142 static inline int bus_append_string(sd_bus_message
*m
, const char *field
, const char *eq
) {
145 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
147 return bus_log_create_error(r
);
152 static int bus_append_strv(sd_bus_message
*m
, const char *field
, const char *eq
, ExtractFlags flags
) {
156 r
= sd_bus_message_open_container(m
, 'r', "sv");
158 return bus_log_create_error(r
);
160 r
= sd_bus_message_append_basic(m
, 's', field
);
162 return bus_log_create_error(r
);
164 r
= sd_bus_message_open_container(m
, 'v', "as");
166 return bus_log_create_error(r
);
168 r
= sd_bus_message_open_container(m
, 'a', "s");
170 return bus_log_create_error(r
);
173 _cleanup_free_
char *word
= NULL
;
175 r
= extract_first_word(&p
, &word
, NULL
, flags
);
181 return log_error_errno(r
, "Invalid syntax: %s", eq
);
183 r
= sd_bus_message_append_basic(m
, 's', word
);
185 return bus_log_create_error(r
);
188 r
= sd_bus_message_close_container(m
);
190 return bus_log_create_error(r
);
192 r
= sd_bus_message_close_container(m
);
194 return bus_log_create_error(r
);
196 r
= sd_bus_message_close_container(m
);
198 return bus_log_create_error(r
);
203 static int bus_append_byte_array(sd_bus_message
*m
, const char *field
, const void *buf
, size_t n
) {
206 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
208 return bus_log_create_error(r
);
210 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
212 return bus_log_create_error(r
);
214 r
= sd_bus_message_open_container(m
, 'v', "ay");
216 return bus_log_create_error(r
);
218 r
= sd_bus_message_append_array(m
, 'y', buf
, n
);
220 return bus_log_create_error(r
);
222 r
= sd_bus_message_close_container(m
);
224 return bus_log_create_error(r
);
226 r
= sd_bus_message_close_container(m
);
228 return bus_log_create_error(r
);
233 static int bus_append_parse_sec_rename(sd_bus_message
*m
, const char *field
, const char *eq
) {
239 r
= parse_sec(eq
, &t
);
241 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
244 n
= newa(char, l
+ 2);
245 /* Change suffix Sec → USec */
246 strcpy(mempcpy(n
, field
, l
- 3), "USec");
248 r
= sd_bus_message_append(m
, "(sv)", n
, "t", t
);
250 return bus_log_create_error(r
);
255 static int bus_append_parse_size(sd_bus_message
*m
, const char *field
, const char *eq
, uint64_t base
) {
259 r
= parse_size(eq
, base
, &v
);
261 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
263 r
= sd_bus_message_append(m
, "(sv)", field
, "t", v
);
265 return bus_log_create_error(r
);
270 static int bus_append_exec_command(sd_bus_message
*m
, const char *field
, const char *eq
) {
271 bool ignore_failure
= false, explicit_path
= false, done
= false;
272 _cleanup_strv_free_
char **l
= NULL
;
273 _cleanup_free_
char *path
= NULL
;
283 ignore_failure
= true;
292 explicit_path
= true;
299 /* The bus API doesn't support +, ! and !! currently, unfortunately. :-( */
300 log_error("Sorry, but +, ! and !! are currently not supported for transient services.");
310 r
= extract_first_word(&eq
, &path
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
312 return log_error_errno(r
, "Failed to parse path: %m");
315 r
= strv_split_extract(&l
, eq
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
317 return log_error_errno(r
, "Failed to parse command line: %m");
319 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
321 return bus_log_create_error(r
);
323 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
325 return bus_log_create_error(r
);
327 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
329 return bus_log_create_error(r
);
331 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
333 return bus_log_create_error(r
);
335 if (!strv_isempty(l
)) {
337 r
= sd_bus_message_open_container(m
, 'r', "sasb");
339 return bus_log_create_error(r
);
341 r
= sd_bus_message_append(m
, "s", path
?: l
[0]);
343 return bus_log_create_error(r
);
345 r
= sd_bus_message_append_strv(m
, l
);
347 return bus_log_create_error(r
);
349 r
= sd_bus_message_append(m
, "b", ignore_failure
);
351 return bus_log_create_error(r
);
353 r
= sd_bus_message_close_container(m
);
355 return bus_log_create_error(r
);
358 r
= sd_bus_message_close_container(m
);
360 return bus_log_create_error(r
);
362 r
= sd_bus_message_close_container(m
);
364 return bus_log_create_error(r
);
366 r
= sd_bus_message_close_container(m
);
368 return bus_log_create_error(r
);
373 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
379 r
= sd_bus_message_open_container(m
, 'r', "iayu");
383 r
= sd_bus_message_append(m
, "i", family
);
387 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
391 r
= sd_bus_message_append(m
, "u", prefixlen
);
395 return sd_bus_message_close_container(m
);
398 static int bus_append_cgroup_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
401 if (STR_IN_SET(field
, "DevicePolicy", "Slice"))
403 return bus_append_string(m
, field
, eq
);
405 if (STR_IN_SET(field
,
406 "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
407 "TasksAccounting", "IPAccounting"))
409 return bus_append_parse_boolean(m
, field
, eq
);
411 if (STR_IN_SET(field
, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight"))
413 return bus_append_cg_weight_parse(m
, field
, eq
);
415 if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares"))
417 return bus_append_cg_cpu_shares_parse(m
, field
, eq
);
419 if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight"))
421 return bus_append_cg_blkio_weight_parse(m
, field
, eq
);
423 if (streq(field
, "Delegate")) {
425 r
= parse_boolean(eq
);
427 return bus_append_strv(m
, "DelegateControllers", eq
, EXTRACT_QUOTES
);
429 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", r
);
431 return bus_log_create_error(r
);
436 if (STR_IN_SET(field
, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
438 if (isempty(eq
) || streq(eq
, "infinity")) {
439 r
= sd_bus_message_append(m
, "(sv)", field
, "t", CGROUP_LIMIT_MAX
);
441 return bus_log_create_error(r
);
445 r
= parse_percent(eq
);
449 /* When this is a percentage we'll convert this into a relative value in the range
450 * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related
451 * ones). This way the physical memory size can be determined server-side */
453 n
= strjoina(field
, "Scale");
454 r
= sd_bus_message_append(m
, "(sv)", n
, "u", (uint32_t) (((uint64_t) UINT32_MAX
* r
) / 100U));
456 return bus_log_create_error(r
);
461 if (streq(field
, "TasksMax"))
462 return bus_append_safe_atou64(m
, field
, eq
);
464 return bus_append_parse_size(m
, field
, eq
, 1024);
468 if (streq(field
, "CPUQuota")) {
471 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
473 r
= parse_percent_unbounded(eq
);
475 log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
479 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (usec_t
) r
* USEC_PER_SEC
/ 100U);
483 return bus_log_create_error(r
);
488 if (streq(field
, "DeviceAllow")) {
491 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
493 const char *path
= eq
, *rwm
= NULL
, *e
;
497 path
= strndupa(eq
, e
- eq
);
501 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
505 return bus_log_create_error(r
);
510 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
513 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
515 const char *path
, *bandwidth
, *e
;
520 log_error("Failed to parse %s value %s.", field
, eq
);
524 path
= strndupa(eq
, e
- eq
);
527 if (streq(bandwidth
, "infinity")) {
528 bytes
= CGROUP_LIMIT_MAX
;
530 r
= parse_size(bandwidth
, 1000, &bytes
);
532 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
535 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
539 return bus_log_create_error(r
);
544 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
547 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
549 const char *path
, *weight
, *e
;
554 log_error("Failed to parse %s value %s.", field
, eq
);
558 path
= strndupa(eq
, e
- eq
);
561 r
= safe_atou64(weight
, &u
);
563 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
565 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
569 return bus_log_create_error(r
);
574 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
575 unsigned char prefixlen
;
576 union in_addr_union prefix
= {};
580 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
582 return bus_log_create_error(r
);
587 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
589 return bus_log_create_error(r
);
591 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
593 return bus_log_create_error(r
);
595 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
597 return bus_log_create_error(r
);
599 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
601 return bus_log_create_error(r
);
603 if (streq(eq
, "any")) {
604 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
606 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
608 return bus_log_create_error(r
);
610 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
612 return bus_log_create_error(r
);
614 } else if (is_localhost(eq
)) {
615 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
617 prefix
.in
.s_addr
= htobe32(0x7f000000);
618 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
620 return bus_log_create_error(r
);
622 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
623 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
627 } else if (streq(eq
, "link-local")) {
628 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
630 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
631 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
633 return bus_log_create_error(r
);
635 prefix
.in6
= (struct in6_addr
) {
636 .s6_addr32
[0] = htobe32(0xfe800000)
638 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
640 return bus_log_create_error(r
);
642 } else if (streq(eq
, "multicast")) {
643 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
645 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
646 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
648 return bus_log_create_error(r
);
650 prefix
.in6
= (struct in6_addr
) {
651 .s6_addr32
[0] = htobe32(0xff000000)
653 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
655 return bus_log_create_error(r
);
658 r
= in_addr_prefix_from_string_auto(eq
, &family
, &prefix
, &prefixlen
);
660 return log_error_errno(r
, "Failed to parse IP address prefix: %s", eq
);
662 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
664 return bus_log_create_error(r
);
667 r
= sd_bus_message_close_container(m
);
669 return bus_log_create_error(r
);
671 r
= sd_bus_message_close_container(m
);
673 return bus_log_create_error(r
);
675 r
= sd_bus_message_close_container(m
);
677 return bus_log_create_error(r
);
685 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
687 if (streq(field
, "Where"))
689 return bus_append_string(m
, field
, eq
);
691 if (streq(field
, "DirectoryMode"))
693 return bus_append_parse_mode(m
, field
, eq
);
695 if (streq(field
, "TimeoutIdleSec"))
697 return bus_append_parse_sec_rename(m
, field
, eq
);
702 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
705 if (STR_IN_SET(field
,
707 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
708 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
709 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
710 "RuntimeDirectoryPreserve", "Personality", "KeyringMode"))
712 return bus_append_string(m
, field
, eq
);
714 if (STR_IN_SET(field
,
715 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
716 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
717 "NoNewPrivileges", "SyslogLevelPrefix",
718 "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
719 "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups",
720 "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality"))
722 return bus_append_parse_boolean(m
, field
, eq
);
724 if (STR_IN_SET(field
,
725 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
726 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
727 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
728 "SupplementaryGroups", "SystemCallArchitectures"))
730 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
732 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
734 return bus_append_log_level_from_string(m
, field
, eq
);
736 if (streq(field
, "SyslogFacility"))
738 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
740 if (streq(field
, "SecureBits"))
742 return bus_append_secure_bits_from_string(m
, field
, eq
);
744 if (streq(field
, "CPUSchedulingPolicy"))
746 return bus_append_sched_policy_from_string(m
, field
, eq
);
748 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
750 return bus_append_safe_atoi(m
, field
, eq
);
752 if (streq(field
, "Nice"))
754 return bus_append_parse_nice(m
, field
, eq
);
756 if (streq(field
, "SystemCallErrorNumber"))
758 return bus_append_parse_errno(m
, field
, eq
);
760 if (streq(field
, "IOSchedulingClass"))
762 return bus_append_ioprio_class_from_string(m
, field
, eq
);
764 if (streq(field
, "IOSchedulingPriority"))
766 return bus_append_ioprio_parse_priority(m
, field
, eq
);
768 if (STR_IN_SET(field
,
769 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
770 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
772 return bus_append_parse_mode(m
, field
, eq
);
774 if (streq(field
, "TimerSlackNSec"))
776 return bus_append_parse_nsec(m
, field
, eq
);
778 if (streq(field
, "MountFlags"))
780 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
782 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
784 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
786 if (streq(field
, "EnvironmentFile")) {
789 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
791 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
792 eq
[0] == '-' ? eq
+ 1 : eq
,
795 return bus_log_create_error(r
);
800 if (streq(field
, "LogExtraFields")) {
802 r
= sd_bus_message_open_container(m
, 'r', "sv");
804 return bus_log_create_error(r
);
806 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
808 return bus_log_create_error(r
);
810 r
= sd_bus_message_open_container(m
, 'v', "aay");
812 return bus_log_create_error(r
);
814 r
= sd_bus_message_open_container(m
, 'a', "ay");
816 return bus_log_create_error(r
);
818 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
820 return bus_log_create_error(r
);
822 r
= sd_bus_message_close_container(m
);
824 return bus_log_create_error(r
);
826 r
= sd_bus_message_close_container(m
);
828 return bus_log_create_error(r
);
830 r
= sd_bus_message_close_container(m
);
832 return bus_log_create_error(r
);
837 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
838 const char *n
, *appended
;
840 if ((n
= startswith(eq
, "fd:"))) {
841 appended
= strjoina(field
, "FileDescriptorName");
842 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
843 } else if ((n
= startswith(eq
, "file:"))) {
844 appended
= strjoina(field
, "File");
845 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
847 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
850 return bus_log_create_error(r
);
855 if (streq(field
, "StandardInputText")) {
856 _cleanup_free_
char *unescaped
= NULL
;
858 r
= cunescape(eq
, 0, &unescaped
);
860 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
862 if (!strextend(&unescaped
, "\n", NULL
))
865 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
866 * interface anyway */
868 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
871 if (streq(field
, "StandardInputData")) {
872 _cleanup_free_
void *decoded
= NULL
;
875 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
877 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
879 return bus_append_byte_array(m
, field
, decoded
, sz
);
882 rl
= rlimit_from_string(field
);
887 r
= rlimit_parse(rl
, eq
, &l
);
889 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
891 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
893 return bus_log_create_error(r
);
895 sn
= strjoina(field
, "Soft");
896 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
898 return bus_log_create_error(r
);
903 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
912 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
914 return bus_log_create_error(r
);
919 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
929 r
= capability_set_from_string(p
, &sum
);
931 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
933 sum
= invert
? ~sum
: sum
;
935 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
937 return bus_log_create_error(r
);
942 if (streq(field
, "CPUAffinity")) {
943 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
945 r
= parse_cpu_set(eq
, &cpuset
);
947 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
949 return bus_append_byte_array(m
, field
, cpuset
, CPU_ALLOC_SIZE(r
));
952 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
961 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
963 return bus_log_create_error(r
);
965 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
967 return bus_log_create_error(r
);
969 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
971 return bus_log_create_error(r
);
973 r
= sd_bus_message_open_container(m
, 'r', "bas");
975 return bus_log_create_error(r
);
977 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
979 return bus_log_create_error(r
);
981 r
= sd_bus_message_open_container(m
, 'a', "s");
983 return bus_log_create_error(r
);
986 _cleanup_free_
char *word
= NULL
;
988 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
994 return log_error_errno(r
, "Invalid syntax: %s", eq
);
996 r
= sd_bus_message_append_basic(m
, 's', word
);
998 return bus_log_create_error(r
);
1001 r
= sd_bus_message_close_container(m
);
1003 return bus_log_create_error(r
);
1005 r
= sd_bus_message_close_container(m
);
1007 return bus_log_create_error(r
);
1009 r
= sd_bus_message_close_container(m
);
1011 return bus_log_create_error(r
);
1013 r
= sd_bus_message_close_container(m
);
1015 return bus_log_create_error(r
);
1020 if (streq(field
, "RestrictNamespaces")) {
1021 bool invert
= false;
1022 unsigned long flags
= 0;
1029 r
= parse_boolean(eq
);
1033 flags
= NAMESPACE_FLAGS_ALL
;
1035 r
= namespace_flag_from_string_many(eq
, &flags
);
1037 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1041 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1043 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1045 return bus_log_create_error(r
);
1050 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1053 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1055 return bus_log_create_error(r
);
1057 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1059 return bus_log_create_error(r
);
1061 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1063 return bus_log_create_error(r
);
1065 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1067 return bus_log_create_error(r
);
1070 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1071 char *s
= NULL
, *d
= NULL
;
1072 bool ignore_enoent
= false;
1073 uint64_t flags
= MS_REC
;
1075 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1077 return log_error_errno(r
, "Failed to parse argument: %m");
1083 ignore_enoent
= true;
1087 if (p
&& p
[-1] == ':') {
1088 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1090 return log_error_errno(r
, "Failed to parse argument: %m");
1092 log_error("Missing argument after ':': %s", eq
);
1098 if (p
&& p
[-1] == ':') {
1099 _cleanup_free_
char *options
= NULL
;
1101 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
1103 return log_error_errno(r
, "Failed to parse argument: %m");
1105 if (isempty(options
) || streq(options
, "rbind"))
1107 else if (streq(options
, "norbind"))
1110 log_error("Unknown options: %s", eq
);
1118 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1120 return bus_log_create_error(r
);
1123 r
= sd_bus_message_close_container(m
);
1125 return bus_log_create_error(r
);
1127 r
= sd_bus_message_close_container(m
);
1129 return bus_log_create_error(r
);
1131 r
= sd_bus_message_close_container(m
);
1133 return bus_log_create_error(r
);
1141 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1143 if (streq(field
, "KillMode"))
1145 return bus_append_string(m
, field
, eq
);
1147 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1149 return bus_append_parse_boolean(m
, field
, eq
);
1151 if (streq(field
, "KillSignal"))
1153 return bus_append_signal_from_string_try_harder(m
, field
, eq
);
1158 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1160 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1162 return bus_append_string(m
, field
, eq
);
1164 if (streq(field
, "TimeoutSec"))
1166 return bus_append_parse_sec_rename(m
, field
, eq
);
1168 if (streq(field
, "DirectoryMode"))
1170 return bus_append_parse_mode(m
, field
, eq
);
1172 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1174 return bus_append_parse_boolean(m
, field
, eq
);
1179 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1182 if (streq(field
, "MakeDirectory"))
1184 return bus_append_parse_boolean(m
, field
, eq
);
1186 if (streq(field
, "DirectoryMode"))
1188 return bus_append_parse_mode(m
, field
, eq
);
1190 if (STR_IN_SET(field
,
1191 "PathExists", "PathExistsGlob", "PathChanged",
1192 "PathModified", "DirectoryNotEmpty")) {
1195 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1197 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1199 return bus_log_create_error(r
);
1207 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1210 if (STR_IN_SET(field
,
1211 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1212 "USBFunctionDescriptors", "USBFunctionStrings"))
1214 return bus_append_string(m
, field
, eq
);
1216 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1218 return bus_append_parse_boolean(m
, field
, eq
);
1220 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1222 return bus_append_parse_sec_rename(m
, field
, eq
);
1224 if (streq(field
, "TimeoutSec")) {
1226 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1230 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1233 if (streq(field
, "FileDescriptorStoreMax"))
1235 return bus_append_safe_atou(m
, field
, eq
);
1237 if (STR_IN_SET(field
,
1238 "ExecStartPre", "ExecStart", "ExecStartPost",
1239 "ExecReload", "ExecStop", "ExecStopPost"))
1241 return bus_append_exec_command(m
, field
, eq
);
1243 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1244 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1245 size_t sz_status
= 0, sz_signal
= 0;
1249 _cleanup_free_
char *word
= NULL
;
1252 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1258 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1260 r
= safe_atoi(word
, &val
);
1262 val
= signal_from_string_try_harder(word
);
1264 return log_error_errno(r
, "Invalid status or signal %s in %s: %m", word
, field
);
1266 signal
= realloc_multiply(signal
, sizeof(int), sz_signal
+ 1);
1270 signal
[sz_signal
++] = val
;
1272 status
= realloc_multiply(status
, sizeof(int), sz_status
+ 1);
1276 status
[sz_status
++] = val
;
1280 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1282 return bus_log_create_error(r
);
1284 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1286 return bus_log_create_error(r
);
1288 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1290 return bus_log_create_error(r
);
1292 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1294 return bus_log_create_error(r
);
1296 r
= sd_bus_message_append_array(m
, 'i', status
, sz_status
);
1298 return bus_log_create_error(r
);
1300 r
= sd_bus_message_append_array(m
, 'i', signal
, sz_signal
);
1302 return bus_log_create_error(r
);
1304 r
= sd_bus_message_close_container(m
);
1306 return bus_log_create_error(r
);
1308 r
= sd_bus_message_close_container(m
);
1310 return bus_log_create_error(r
);
1312 r
= sd_bus_message_close_container(m
);
1314 return bus_log_create_error(r
);
1322 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1325 if (STR_IN_SET(field
,
1326 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1327 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1329 return bus_append_parse_boolean(m
, field
, eq
);
1331 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1333 return bus_append_safe_atoi(m
, field
, eq
);
1335 if (streq(field
, "IPTOS"))
1337 return bus_append_ip_tos_from_string(m
, field
, eq
);
1339 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1341 return bus_append_safe_atou(m
, field
, eq
);
1343 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1345 return bus_append_parse_mode(m
, field
, eq
);
1347 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1349 return bus_append_safe_atoi64(m
, field
, eq
);
1351 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1353 return bus_append_parse_sec_rename(m
, field
, eq
);
1355 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1357 return bus_append_parse_size(m
, field
, eq
, 1024);
1359 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1361 return bus_append_exec_command(m
, field
, eq
);
1363 if (STR_IN_SET(field
,
1364 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1365 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1366 "SocketUser", "SocketGroup"))
1368 return bus_append_string(m
, field
, eq
);
1370 if (streq(field
, "Symlinks"))
1372 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1374 if (streq(field
, "SocketProtocol"))
1376 return bus_append_socket_protocol_from_name(m
, field
, eq
);
1378 if (STR_IN_SET(field
,
1379 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1380 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1383 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1385 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ strlen("Listen"), eq
);
1387 return bus_log_create_error(r
);
1394 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1397 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent"))
1399 return bus_append_parse_boolean(m
, field
, eq
);
1401 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1403 return bus_append_parse_sec_rename(m
, field
, eq
);
1405 if (STR_IN_SET(field
,
1406 "OnActiveSec", "OnBootSec", "OnStartupSec",
1407 "OnUnitActiveSec","OnUnitInactiveSec")) {
1410 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1413 r
= parse_sec(eq
, &t
);
1415 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1417 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1420 return bus_log_create_error(r
);
1425 if (streq(field
, "OnCalendar")) {
1428 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1430 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1432 return bus_log_create_error(r
);
1440 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1441 ConditionType t
= _CONDITION_TYPE_INVALID
;
1442 bool is_condition
= false;
1445 if (STR_IN_SET(field
,
1446 "Description", "SourcePath", "OnFailureJobMode",
1447 "JobTimeoutAction", "JobTimeoutRebootArgument",
1448 "StartLimitAction", "FailureAction", "SuccessAction",
1449 "RebootArgument", "CollectMode"))
1451 return bus_append_string(m
, field
, eq
);
1453 if (STR_IN_SET(field
,
1454 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1455 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1457 return bus_append_parse_boolean(m
, field
, eq
);
1459 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1461 return bus_append_parse_sec_rename(m
, field
, eq
);
1463 if (streq(field
, "StartLimitBurst"))
1465 return bus_append_safe_atou(m
, field
, eq
);
1467 if (unit_dependency_from_string(field
) >= 0 ||
1468 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1470 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1472 t
= condition_type_from_string(field
);
1474 is_condition
= true;
1476 t
= assert_type_from_string(field
);
1479 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1482 int trigger
, negate
;
1484 trigger
= *p
== '|';
1492 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1493 field
, trigger
, negate
, p
);
1496 return bus_log_create_error(r
);
1504 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1505 const char *eq
, *field
;
1511 eq
= strchr(assignment
, '=');
1513 log_error("Not an assignment: %s", assignment
);
1517 field
= strndupa(assignment
, eq
- assignment
);
1522 r
= bus_append_cgroup_property(m
, field
, eq
);
1526 r
= bus_append_execute_property(m
, field
, eq
);
1530 r
= bus_append_kill_property(m
, field
, eq
);
1534 r
= bus_append_service_property(m
, field
, eq
);
1540 r
= bus_append_cgroup_property(m
, field
, eq
);
1544 r
= bus_append_execute_property(m
, field
, eq
);
1548 r
= bus_append_kill_property(m
, field
, eq
);
1552 r
= bus_append_socket_property(m
, field
, eq
);
1558 r
= bus_append_timer_property(m
, field
, eq
);
1564 r
= bus_append_path_property(m
, field
, eq
);
1570 r
= bus_append_cgroup_property(m
, field
, eq
);
1577 if (streq(field
, "TimeoutStopSec"))
1578 return bus_append_parse_sec_rename(m
, field
, eq
);
1580 r
= bus_append_cgroup_property(m
, field
, eq
);
1584 r
= bus_append_kill_property(m
, field
, eq
);
1590 r
= bus_append_cgroup_property(m
, field
, eq
);
1594 r
= bus_append_execute_property(m
, field
, eq
);
1598 r
= bus_append_kill_property(m
, field
, eq
);
1602 r
= bus_append_mount_property(m
, field
, eq
);
1608 case UNIT_AUTOMOUNT
:
1609 r
= bus_append_automount_property(m
, field
, eq
);
1618 log_error("Not supported unit type");
1622 log_error("Invalid unit type");
1626 r
= bus_append_unit_property(m
, field
, eq
);
1630 log_error("Unknown assignment: %s", assignment
);
1634 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1640 STRV_FOREACH(i
, l
) {
1641 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1649 typedef struct BusWaitForJobs
{
1656 sd_bus_slot
*slot_job_removed
;
1657 sd_bus_slot
*slot_disconnected
;
1660 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1663 log_error("Warning! D-Bus connection terminated.");
1664 sd_bus_close(sd_bus_message_get_bus(m
));
1669 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1670 const char *path
, *unit
, *result
;
1671 BusWaitForJobs
*d
= userdata
;
1679 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1681 bus_log_parse_error(r
);
1685 found
= set_remove(d
->jobs
, (char*) path
);
1691 if (!isempty(result
))
1692 d
->result
= strdup(result
);
1695 d
->name
= strdup(unit
);
1700 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1704 set_free_free(d
->jobs
);
1706 sd_bus_slot_unref(d
->slot_disconnected
);
1707 sd_bus_slot_unref(d
->slot_job_removed
);
1709 sd_bus_unref(d
->bus
);
1717 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1718 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1724 d
= new0(BusWaitForJobs
, 1);
1728 d
->bus
= sd_bus_ref(bus
);
1730 /* When we are a bus client we match by sender. Direct
1731 * connections OTOH have no initialized sender field, and
1732 * hence we ignore the sender then */
1733 r
= sd_bus_match_signal_async(
1735 &d
->slot_job_removed
,
1736 bus
->bus_client
? "org.freedesktop.systemd1" : NULL
,
1737 "/org/freedesktop/systemd1",
1738 "org.freedesktop.systemd1.Manager",
1740 match_job_removed
, NULL
, d
);
1744 r
= sd_bus_match_signal_async(
1746 &d
->slot_disconnected
,
1747 "org.freedesktop.DBus.Local",
1749 "org.freedesktop.DBus.Local",
1751 match_disconnected
, NULL
, d
);
1761 static int bus_process_wait(sd_bus
*bus
) {
1765 r
= sd_bus_process(bus
, NULL
);
1771 r
= sd_bus_wait(bus
, (uint64_t) -1);
1777 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1778 _cleanup_free_
char *dbus_path
= NULL
;
1784 if (!endswith(d
->name
, ".service"))
1787 dbus_path
= unit_dbus_path_from_name(d
->name
);
1791 return sd_bus_get_property_string(d
->bus
,
1792 "org.freedesktop.systemd1",
1794 "org.freedesktop.systemd1.Service",
1800 static const struct {
1801 const char *result
, *explanation
;
1802 } explanations
[] = {
1803 { "resources", "of unavailable resources or another system error" },
1804 { "protocol", "the service did not take the steps required by its unit configuration" },
1805 { "timeout", "a timeout was exceeded" },
1806 { "exit-code", "the control process exited with error code" },
1807 { "signal", "a fatal signal was delivered to the control process" },
1808 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1809 { "watchdog", "the service failed to send watchdog ping" },
1810 { "start-limit", "start of the service was attempted too often" }
1813 static void log_job_error_with_service_result(const char* service
, const char *result
, const char* const* extra_args
) {
1814 _cleanup_free_
char *service_shell_quoted
= NULL
;
1815 const char *systemctl
= "systemctl", *journalctl
= "journalctl";
1819 service_shell_quoted
= shell_maybe_quote(service
, ESCAPE_BACKSLASH
);
1821 if (!strv_isempty((char**) extra_args
)) {
1822 _cleanup_free_
char *t
;
1824 t
= strv_join((char**) extra_args
, " ");
1825 systemctl
= strjoina("systemctl ", t
? : "<args>");
1826 journalctl
= strjoina("journalctl ", t
? : "<args>");
1829 if (!isempty(result
)) {
1832 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1833 if (streq(result
, explanations
[i
].result
))
1836 if (i
< ELEMENTSOF(explanations
)) {
1837 log_error("Job for %s failed because %s.\n"
1838 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1840 explanations
[i
].explanation
,
1842 service_shell_quoted
?: "<service>",
1848 log_error("Job for %s failed.\n"
1849 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1852 service_shell_quoted
?: "<service>",
1856 /* For some results maybe additional explanation is required */
1857 if (streq_ptr(result
, "start-limit"))
1858 log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
1859 "followed by \"%1$s start %2$s\" again.",
1861 service_shell_quoted
?: "<service>");
1864 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1870 if (streq(d
->result
, "canceled"))
1871 log_error("Job for %s canceled.", strna(d
->name
));
1872 else if (streq(d
->result
, "timeout"))
1873 log_error("Job for %s timed out.", strna(d
->name
));
1874 else if (streq(d
->result
, "dependency"))
1875 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
1876 else if (streq(d
->result
, "invalid"))
1877 log_error("%s is not active, cannot reload.", strna(d
->name
));
1878 else if (streq(d
->result
, "assert"))
1879 log_error("Assertion failed on job for %s.", strna(d
->name
));
1880 else if (streq(d
->result
, "unsupported"))
1881 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
1882 else if (streq(d
->result
, "collected"))
1883 log_error("Queued job for %s was garbage collected.", strna(d
->name
));
1884 else if (!STR_IN_SET(d
->result
, "done", "skipped")) {
1886 _cleanup_free_
char *result
= NULL
;
1889 q
= bus_job_get_service_result(d
, &result
);
1891 log_debug_errno(q
, "Failed to get Result property of unit %s: %m", d
->name
);
1893 log_job_error_with_service_result(d
->name
, result
, extra_args
);
1895 log_error("Job failed. See \"journalctl -xe\" for details.");
1899 if (STR_IN_SET(d
->result
, "canceled", "collected"))
1901 else if (streq(d
->result
, "timeout"))
1903 else if (streq(d
->result
, "dependency"))
1905 else if (streq(d
->result
, "invalid"))
1907 else if (streq(d
->result
, "assert"))
1909 else if (streq(d
->result
, "unsupported"))
1911 else if (!STR_IN_SET(d
->result
, "done", "skipped"))
1917 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1922 while (!set_isempty(d
->jobs
)) {
1925 q
= bus_process_wait(d
->bus
);
1927 return log_error_errno(q
, "Failed to wait for response: %m");
1930 q
= check_wait_response(d
, quiet
, extra_args
);
1931 /* Return the first error as it is most likely to be
1933 if (q
< 0 && r
== 0)
1936 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
1939 d
->name
= mfree(d
->name
);
1940 d
->result
= mfree(d
->result
);
1946 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
1951 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
1955 return set_put_strdup(d
->jobs
, path
);
1958 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
1961 r
= bus_wait_for_jobs_add(d
, path
);
1965 return bus_wait_for_jobs(d
, quiet
, NULL
);
1968 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
1969 const char *type
, *path
, *source
;
1972 /* changes is dereferenced when calling unit_file_dump_changes() later,
1973 * so we have to make sure this is not NULL. */
1977 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1979 return bus_log_parse_error(r
);
1981 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1982 /* We expect only "success" changes to be sent over the bus.
1983 Hence, reject anything negative. */
1984 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1987 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1991 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1996 return bus_log_parse_error(r
);
1998 r
= sd_bus_message_exit_container(m
);
2000 return bus_log_parse_error(r
);
2002 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2008 bool is_const
; /* If false, cgroup_path should be free()'d */
2010 Hashmap
*pids
; /* PID → process name */
2013 struct CGroupInfo
*parent
;
2014 LIST_FIELDS(struct CGroupInfo
, siblings
);
2015 LIST_HEAD(struct CGroupInfo
, children
);
2019 static bool IS_ROOT(const char *p
) {
2020 return isempty(p
) || streq(p
, "/");
2023 static int add_cgroup(Hashmap
*cgroups
, const char *path
, bool is_const
, struct CGroupInfo
**ret
) {
2024 struct CGroupInfo
*parent
= NULL
, *cg
;
2033 cg
= hashmap_get(cgroups
, path
);
2039 if (!IS_ROOT(path
)) {
2042 e
= strrchr(path
, '/');
2046 pp
= strndupa(path
, e
- path
);
2050 r
= add_cgroup(cgroups
, pp
, false, &parent
);
2055 cg
= new0(struct CGroupInfo
, 1);
2060 cg
->cgroup_path
= (char*) path
;
2062 cg
->cgroup_path
= strdup(path
);
2063 if (!cg
->cgroup_path
) {
2069 cg
->is_const
= is_const
;
2070 cg
->parent
= parent
;
2072 r
= hashmap_put(cgroups
, cg
->cgroup_path
, cg
);
2075 free(cg
->cgroup_path
);
2081 LIST_PREPEND(siblings
, parent
->children
, cg
);
2082 parent
->n_children
++;
2089 static int add_process(
2095 struct CGroupInfo
*cg
;
2102 r
= add_cgroup(cgroups
, path
, true, &cg
);
2106 r
= hashmap_ensure_allocated(&cg
->pids
, &trivial_hash_ops
);
2110 return hashmap_put(cg
->pids
, PID_TO_PTR(pid
), (void*) name
);
2113 static void remove_cgroup(Hashmap
*cgroups
, struct CGroupInfo
*cg
) {
2117 while (cg
->children
)
2118 remove_cgroup(cgroups
, cg
->children
);
2120 hashmap_remove(cgroups
, cg
->cgroup_path
);
2123 free(cg
->cgroup_path
);
2125 hashmap_free(cg
->pids
);
2128 LIST_REMOVE(siblings
, cg
->parent
->children
, cg
);
2133 static int cgroup_info_compare_func(const void *a
, const void *b
) {
2134 const struct CGroupInfo
*x
= *(const struct CGroupInfo
* const*) a
, *y
= *(const struct CGroupInfo
* const*) b
;
2139 return strcmp(x
->cgroup_path
, y
->cgroup_path
);
2142 static int dump_processes(
2144 const char *cgroup_path
,
2147 OutputFlags flags
) {
2149 struct CGroupInfo
*cg
;
2154 if (IS_ROOT(cgroup_path
))
2157 cg
= hashmap_get(cgroups
, cgroup_path
);
2161 if (!hashmap_isempty(cg
->pids
)) {
2169 /* Order processes by their PID */
2170 pids
= newa(pid_t
, hashmap_size(cg
->pids
));
2172 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
)
2173 pids
[n
++] = PTR_TO_PID(pidp
);
2175 assert(n
== hashmap_size(cg
->pids
));
2176 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
2178 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2180 for (i
= 0; i
< n
; i
++) {
2181 _cleanup_free_
char *e
= NULL
;
2182 const char *special
;
2185 name
= hashmap_get(cg
->pids
, PID_TO_PTR(pids
[i
]));
2188 if (n_columns
!= 0) {
2191 k
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2193 e
= ellipsize(name
, k
, 100);
2198 more
= i
+1 < n
|| cg
->children
;
2199 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
2201 fprintf(stdout
, "%s%s%*"PID_PRI
" %s\n",
2210 struct CGroupInfo
**children
, *child
;
2213 /* Order subcgroups by their name */
2214 children
= newa(struct CGroupInfo
*, cg
->n_children
);
2215 LIST_FOREACH(siblings
, child
, cg
->children
)
2216 children
[n
++] = child
;
2217 assert(n
== cg
->n_children
);
2218 qsort_safe(children
, n
, sizeof(struct CGroupInfo
*), cgroup_info_compare_func
);
2221 n_columns
= MAX(LESS_BY(n_columns
, 2U), 20U);
2223 for (i
= 0; i
< n
; i
++) {
2224 _cleanup_free_
char *pp
= NULL
;
2225 const char *name
, *special
;
2228 child
= children
[i
];
2230 name
= strrchr(child
->cgroup_path
, '/');
2236 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
2238 fputs(prefix
, stdout
);
2239 fputs(special
, stdout
);
2240 fputs(name
, stdout
);
2241 fputc('\n', stdout
);
2243 special
= special_glyph(more
? TREE_VERTICAL
: TREE_SPACE
);
2245 pp
= strappend(prefix
, special
);
2249 r
= dump_processes(cgroups
, child
->cgroup_path
, pp
, n_columns
, flags
);
2259 static int dump_extra_processes(
2263 OutputFlags flags
) {
2265 _cleanup_free_ pid_t
*pids
= NULL
;
2266 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
2267 struct CGroupInfo
*cg
;
2268 size_t n_allocated
= 0, n
= 0, k
;
2272 /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
2273 * combined, sorted, linear list. */
2275 HASHMAP_FOREACH(cg
, cgroups
, i
) {
2283 if (hashmap_isempty(cg
->pids
))
2286 r
= hashmap_ensure_allocated(&names
, &trivial_hash_ops
);
2290 if (!GREEDY_REALLOC(pids
, n_allocated
, n
+ hashmap_size(cg
->pids
)))
2293 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
) {
2294 pids
[n
++] = PTR_TO_PID(pidp
);
2296 r
= hashmap_put(names
, pidp
, (void*) name
);
2305 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
2306 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2308 for (k
= 0; k
< n
; k
++) {
2309 _cleanup_free_
char *e
= NULL
;
2312 name
= hashmap_get(names
, PID_TO_PTR(pids
[k
]));
2315 if (n_columns
!= 0) {
2318 z
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2320 e
= ellipsize(name
, z
, 100);
2325 fprintf(stdout
, "%s%s %*" PID_PRI
" %s\n",
2327 special_glyph(TRIANGULAR_BULLET
),
2335 int unit_show_processes(
2338 const char *cgroup_path
,
2342 sd_bus_error
*error
) {
2344 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2345 Hashmap
*cgroups
= NULL
;
2346 struct CGroupInfo
*cg
;
2352 if (flags
& OUTPUT_FULL_WIDTH
)
2354 else if (n_columns
<= 0)
2355 n_columns
= columns();
2357 prefix
= strempty(prefix
);
2359 r
= sd_bus_call_method(
2361 "org.freedesktop.systemd1",
2362 "/org/freedesktop/systemd1",
2363 "org.freedesktop.systemd1.Manager",
2372 cgroups
= hashmap_new(&string_hash_ops
);
2376 r
= sd_bus_message_enter_container(reply
, 'a', "(sus)");
2381 const char *path
= NULL
, *name
= NULL
;
2384 r
= sd_bus_message_read(reply
, "(sus)", &path
, &pid
, &name
);
2390 r
= add_process(cgroups
, path
, pid
, name
);
2395 r
= sd_bus_message_exit_container(reply
);
2399 r
= dump_processes(cgroups
, cgroup_path
, prefix
, n_columns
, flags
);
2403 r
= dump_extra_processes(cgroups
, prefix
, n_columns
, flags
);
2406 while ((cg
= hashmap_first(cgroups
)))
2407 remove_cgroup(cgroups
, cg
);
2409 hashmap_free(cgroups
);