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);
465 if (streq(field
, "CPUQuota")) {
468 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
470 r
= parse_percent_unbounded(eq
);
472 log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
476 r
= sd_bus_message_append(m
, "(sv)", "CPUQuotaPerSecUSec", "t", (usec_t
) r
* USEC_PER_SEC
/ 100U);
480 return bus_log_create_error(r
);
485 if (streq(field
, "DeviceAllow")) {
488 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 0);
490 const char *path
= eq
, *rwm
= NULL
, *e
;
494 path
= strndupa(eq
, e
- eq
);
498 r
= sd_bus_message_append(m
, "(sv)", field
, "a(ss)", 1, path
, strempty(rwm
));
502 return bus_log_create_error(r
);
507 if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
510 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
512 const char *path
, *bandwidth
, *e
;
517 log_error("Failed to parse %s value %s.", field
, eq
);
521 path
= strndupa(eq
, e
- eq
);
524 if (streq(bandwidth
, "infinity")) {
525 bytes
= CGROUP_LIMIT_MAX
;
527 r
= parse_size(bandwidth
, 1000, &bytes
);
529 return log_error_errno(r
, "Failed to parse byte value %s: %m", bandwidth
);
532 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, bytes
);
536 return bus_log_create_error(r
);
541 if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
544 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 0);
546 const char *path
, *weight
, *e
;
551 log_error("Failed to parse %s value %s.", field
, eq
);
555 path
= strndupa(eq
, e
- eq
);
558 r
= safe_atou64(weight
, &u
);
560 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, weight
);
562 r
= sd_bus_message_append(m
, "(sv)", field
, "a(st)", 1, path
, u
);
566 return bus_log_create_error(r
);
571 if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
572 unsigned char prefixlen
;
573 union in_addr_union prefix
= {};
577 r
= sd_bus_message_append(m
, "(sv)", field
, "a(iayu)", 0);
579 return bus_log_create_error(r
);
584 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
586 return bus_log_create_error(r
);
588 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
590 return bus_log_create_error(r
);
592 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
594 return bus_log_create_error(r
);
596 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
598 return bus_log_create_error(r
);
600 if (streq(eq
, "any")) {
601 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
603 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
605 return bus_log_create_error(r
);
607 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
609 return bus_log_create_error(r
);
611 } else if (is_localhost(eq
)) {
612 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
614 prefix
.in
.s_addr
= htobe32(0x7f000000);
615 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
617 return bus_log_create_error(r
);
619 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
620 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
624 } else if (streq(eq
, "link-local")) {
625 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
627 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
628 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
630 return bus_log_create_error(r
);
632 prefix
.in6
= (struct in6_addr
) {
633 .s6_addr32
[0] = htobe32(0xfe800000)
635 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
637 return bus_log_create_error(r
);
639 } else if (streq(eq
, "multicast")) {
640 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
642 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
643 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
645 return bus_log_create_error(r
);
647 prefix
.in6
= (struct in6_addr
) {
648 .s6_addr32
[0] = htobe32(0xff000000)
650 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
652 return bus_log_create_error(r
);
655 r
= in_addr_prefix_from_string_auto(eq
, &family
, &prefix
, &prefixlen
);
657 return log_error_errno(r
, "Failed to parse IP address prefix: %s", eq
);
659 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
661 return bus_log_create_error(r
);
664 r
= sd_bus_message_close_container(m
);
666 return bus_log_create_error(r
);
668 r
= sd_bus_message_close_container(m
);
670 return bus_log_create_error(r
);
672 r
= sd_bus_message_close_container(m
);
674 return bus_log_create_error(r
);
682 static int bus_append_automount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
684 if (streq(field
, "Where"))
686 return bus_append_string(m
, field
, eq
);
688 if (streq(field
, "DirectoryMode"))
690 return bus_append_parse_mode(m
, field
, eq
);
692 if (streq(field
, "TimeoutIdleSec"))
694 return bus_append_parse_sec_rename(m
, field
, eq
);
699 static int bus_append_execute_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
702 if (STR_IN_SET(field
,
704 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
705 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
706 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
707 "RuntimeDirectoryPreserve", "Personality", "KeyringMode"))
709 return bus_append_string(m
, field
, eq
);
711 if (STR_IN_SET(field
,
712 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
713 "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
714 "NoNewPrivileges", "SyslogLevelPrefix",
715 "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
716 "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups",
717 "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality"))
719 return bus_append_parse_boolean(m
, field
, eq
);
721 if (STR_IN_SET(field
,
722 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
723 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
724 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
725 "SupplementaryGroups", "SystemCallArchitectures"))
727 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
729 if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax"))
731 return bus_append_log_level_from_string(m
, field
, eq
);
733 if (streq(field
, "SyslogFacility"))
735 return bus_append_log_facility_unshifted_from_string(m
, field
, eq
);
737 if (streq(field
, "SecureBits"))
739 return bus_append_secure_bits_from_string(m
, field
, eq
);
741 if (streq(field
, "CPUSchedulingPolicy"))
743 return bus_append_sched_policy_from_string(m
, field
, eq
);
745 if (STR_IN_SET(field
, "CPUSchedulingPriority", "OOMScoreAdjust"))
747 return bus_append_safe_atoi(m
, field
, eq
);
749 if (streq(field
, "Nice"))
751 return bus_append_parse_nice(m
, field
, eq
);
753 if (streq(field
, "SystemCallErrorNumber"))
755 return bus_append_parse_errno(m
, field
, eq
);
757 if (streq(field
, "IOSchedulingClass"))
759 return bus_append_ioprio_class_from_string(m
, field
, eq
);
761 if (streq(field
, "IOSchedulingPriority"))
763 return bus_append_ioprio_parse_priority(m
, field
, eq
);
765 if (STR_IN_SET(field
,
766 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
767 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
769 return bus_append_parse_mode(m
, field
, eq
);
771 if (streq(field
, "TimerSlackNSec"))
773 return bus_append_parse_nsec(m
, field
, eq
);
775 if (streq(field
, "MountFlags"))
777 return bus_append_mount_propagation_flags_from_string(m
, field
, eq
);
779 if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment"))
781 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
783 if (streq(field
, "EnvironmentFile")) {
786 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 0);
788 r
= sd_bus_message_append(m
, "(sv)", "EnvironmentFiles", "a(sb)", 1,
789 eq
[0] == '-' ? eq
+ 1 : eq
,
792 return bus_log_create_error(r
);
797 if (streq(field
, "LogExtraFields")) {
799 r
= sd_bus_message_open_container(m
, 'r', "sv");
801 return bus_log_create_error(r
);
803 r
= sd_bus_message_append_basic(m
, 's', "LogExtraFields");
805 return bus_log_create_error(r
);
807 r
= sd_bus_message_open_container(m
, 'v', "aay");
809 return bus_log_create_error(r
);
811 r
= sd_bus_message_open_container(m
, 'a', "ay");
813 return bus_log_create_error(r
);
815 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
817 return bus_log_create_error(r
);
819 r
= sd_bus_message_close_container(m
);
821 return bus_log_create_error(r
);
823 r
= sd_bus_message_close_container(m
);
825 return bus_log_create_error(r
);
827 r
= sd_bus_message_close_container(m
);
829 return bus_log_create_error(r
);
834 if (STR_IN_SET(field
, "StandardInput", "StandardOutput", "StandardError")) {
835 const char *n
, *appended
;
837 if ((n
= startswith(eq
, "fd:"))) {
838 appended
= strjoina(field
, "FileDescriptorName");
839 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
840 } else if ((n
= startswith(eq
, "file:"))) {
841 appended
= strjoina(field
, "File");
842 r
= sd_bus_message_append(m
, "(sv)", appended
, "s", n
);
844 r
= sd_bus_message_append(m
, "(sv)", field
, "s", eq
);
847 return bus_log_create_error(r
);
852 if (streq(field
, "StandardInputText")) {
853 _cleanup_free_
char *unescaped
= NULL
;
855 r
= cunescape(eq
, 0, &unescaped
);
857 return log_error_errno(r
, "Failed to unescape text '%s': %m", eq
);
859 if (!strextend(&unescaped
, "\n", NULL
))
862 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
863 * interface anyway */
865 return bus_append_byte_array(m
, field
, unescaped
, strlen(unescaped
));
868 if (streq(field
, "StandardInputData")) {
869 _cleanup_free_
void *decoded
= NULL
;
872 r
= unbase64mem(eq
, (size_t) -1, &decoded
, &sz
);
874 return log_error_errno(r
, "Failed to decode base64 data '%s': %m", eq
);
876 return bus_append_byte_array(m
, field
, decoded
, sz
);
879 rl
= rlimit_from_string(field
);
884 r
= rlimit_parse(rl
, eq
, &l
);
886 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
888 r
= sd_bus_message_append(m
, "(sv)", field
, "t", l
.rlim_max
);
890 return bus_log_create_error(r
);
892 sn
= strjoina(field
, "Soft");
893 r
= sd_bus_message_append(m
, "(sv)", sn
, "t", l
.rlim_cur
);
895 return bus_log_create_error(r
);
900 if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
909 r
= sd_bus_message_append(m
, "(sv)", field
, "(bs)", ignore
, s
);
911 return bus_log_create_error(r
);
916 if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
926 r
= capability_set_from_string(p
, &sum
);
928 return log_error_errno(r
, "Failed to parse %s value %s: %m", field
, eq
);
930 sum
= invert
? ~sum
: sum
;
932 r
= sd_bus_message_append(m
, "(sv)", field
, "t", sum
);
934 return bus_log_create_error(r
);
939 if (streq(field
, "CPUAffinity")) {
940 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
942 r
= parse_cpu_set(eq
, &cpuset
);
944 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
946 return bus_append_byte_array(m
, field
, cpuset
, CPU_ALLOC_SIZE(r
));
949 if (STR_IN_SET(field
, "RestrictAddressFamilies", "SystemCallFilter")) {
958 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
960 return bus_log_create_error(r
);
962 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
964 return bus_log_create_error(r
);
966 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
968 return bus_log_create_error(r
);
970 r
= sd_bus_message_open_container(m
, 'r', "bas");
972 return bus_log_create_error(r
);
974 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
976 return bus_log_create_error(r
);
978 r
= sd_bus_message_open_container(m
, 'a', "s");
980 return bus_log_create_error(r
);
983 _cleanup_free_
char *word
= NULL
;
985 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
991 return log_error_errno(r
, "Invalid syntax: %s", eq
);
993 r
= sd_bus_message_append_basic(m
, 's', word
);
995 return bus_log_create_error(r
);
998 r
= sd_bus_message_close_container(m
);
1000 return bus_log_create_error(r
);
1002 r
= sd_bus_message_close_container(m
);
1004 return bus_log_create_error(r
);
1006 r
= sd_bus_message_close_container(m
);
1008 return bus_log_create_error(r
);
1010 r
= sd_bus_message_close_container(m
);
1012 return bus_log_create_error(r
);
1017 if (streq(field
, "RestrictNamespaces")) {
1018 bool invert
= false;
1019 unsigned long flags
= 0;
1026 r
= parse_boolean(eq
);
1030 flags
= NAMESPACE_FLAGS_ALL
;
1032 r
= namespace_flag_from_string_many(eq
, &flags
);
1034 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1038 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1040 r
= sd_bus_message_append(m
, "(sv)", field
, "t", (uint64_t) flags
);
1042 return bus_log_create_error(r
);
1047 if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1050 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1052 return bus_log_create_error(r
);
1054 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1056 return bus_log_create_error(r
);
1058 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1060 return bus_log_create_error(r
);
1062 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1064 return bus_log_create_error(r
);
1067 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1068 char *s
= NULL
, *d
= NULL
;
1069 bool ignore_enoent
= false;
1070 uint64_t flags
= MS_REC
;
1072 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1074 return log_error_errno(r
, "Failed to parse argument: %m");
1080 ignore_enoent
= true;
1084 if (p
&& p
[-1] == ':') {
1085 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1087 return log_error_errno(r
, "Failed to parse argument: %m");
1089 log_error("Missing argument after ':': %s", eq
);
1095 if (p
&& p
[-1] == ':') {
1096 _cleanup_free_
char *options
= NULL
;
1098 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
1100 return log_error_errno(r
, "Failed to parse argument: %m");
1102 if (isempty(options
) || streq(options
, "rbind"))
1104 else if (streq(options
, "norbind"))
1107 log_error("Unknown options: %s", eq
);
1115 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1117 return bus_log_create_error(r
);
1120 r
= sd_bus_message_close_container(m
);
1122 return bus_log_create_error(r
);
1124 r
= sd_bus_message_close_container(m
);
1126 return bus_log_create_error(r
);
1128 r
= sd_bus_message_close_container(m
);
1130 return bus_log_create_error(r
);
1135 if (streq(field
, "TemporaryFileSystem")) {
1138 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1140 return bus_log_create_error(r
);
1142 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1144 return bus_log_create_error(r
);
1146 r
= sd_bus_message_open_container(m
, 'v', "a(ss)");
1148 return bus_log_create_error(r
);
1150 r
= sd_bus_message_open_container(m
, 'a', "(ss)");
1152 return bus_log_create_error(r
);
1155 _cleanup_free_
char *word
= NULL
, *path
= NULL
;
1158 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1160 return log_error_errno(r
, "Failed to parse argument: %m");
1165 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1167 return log_error_errno(r
, "Failed to parse argument: %m");
1169 return log_error("Failed to parse argument: %m");
1171 r
= sd_bus_message_append(m
, "(ss)", path
, w
);
1173 return bus_log_create_error(r
);
1176 r
= sd_bus_message_close_container(m
);
1178 return bus_log_create_error(r
);
1180 r
= sd_bus_message_close_container(m
);
1182 return bus_log_create_error(r
);
1184 r
= sd_bus_message_close_container(m
);
1186 return bus_log_create_error(r
);
1194 static int bus_append_kill_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1196 if (streq(field
, "KillMode"))
1198 return bus_append_string(m
, field
, eq
);
1200 if (STR_IN_SET(field
, "SendSIGHUP", "SendSIGKILL"))
1202 return bus_append_parse_boolean(m
, field
, eq
);
1204 if (streq(field
, "KillSignal"))
1206 return bus_append_signal_from_string_try_harder(m
, field
, eq
);
1211 static int bus_append_mount_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1213 if (STR_IN_SET(field
, "What", "Where", "Options", "Type"))
1215 return bus_append_string(m
, field
, eq
);
1217 if (streq(field
, "TimeoutSec"))
1219 return bus_append_parse_sec_rename(m
, field
, eq
);
1221 if (streq(field
, "DirectoryMode"))
1223 return bus_append_parse_mode(m
, field
, eq
);
1225 if (STR_IN_SET(field
, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1227 return bus_append_parse_boolean(m
, field
, eq
);
1232 static int bus_append_path_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1235 if (streq(field
, "MakeDirectory"))
1237 return bus_append_parse_boolean(m
, field
, eq
);
1239 if (streq(field
, "DirectoryMode"))
1241 return bus_append_parse_mode(m
, field
, eq
);
1243 if (STR_IN_SET(field
,
1244 "PathExists", "PathExistsGlob", "PathChanged",
1245 "PathModified", "DirectoryNotEmpty")) {
1248 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 0);
1250 r
= sd_bus_message_append(m
, "(sv)", "Paths", "a(ss)", 1, field
, eq
);
1252 return bus_log_create_error(r
);
1260 static int bus_append_service_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1263 if (STR_IN_SET(field
,
1264 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
1265 "USBFunctionDescriptors", "USBFunctionStrings"))
1267 return bus_append_string(m
, field
, eq
);
1269 if (STR_IN_SET(field
, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
1271 return bus_append_parse_boolean(m
, field
, eq
);
1273 if (STR_IN_SET(field
, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
1275 return bus_append_parse_sec_rename(m
, field
, eq
);
1277 if (streq(field
, "TimeoutSec")) {
1279 r
= bus_append_parse_sec_rename(m
, "TimeoutStartSec", eq
);
1283 return bus_append_parse_sec_rename(m
, "TimeoutStopSec", eq
);
1286 if (streq(field
, "FileDescriptorStoreMax"))
1288 return bus_append_safe_atou(m
, field
, eq
);
1290 if (STR_IN_SET(field
,
1291 "ExecStartPre", "ExecStart", "ExecStartPost",
1292 "ExecReload", "ExecStop", "ExecStopPost"))
1294 return bus_append_exec_command(m
, field
, eq
);
1296 if (STR_IN_SET(field
, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1297 _cleanup_free_
int *status
= NULL
, *signal
= NULL
;
1298 size_t sz_status
= 0, sz_signal
= 0;
1302 _cleanup_free_
char *word
= NULL
;
1305 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1311 return log_error_errno(r
, "Invalid syntax in %s: %s", field
, eq
);
1313 r
= safe_atoi(word
, &val
);
1315 val
= signal_from_string_try_harder(word
);
1317 return log_error_errno(r
, "Invalid status or signal %s in %s: %m", word
, field
);
1319 signal
= reallocarray(signal
, sz_signal
+ 1, sizeof(int));
1323 signal
[sz_signal
++] = val
;
1325 status
= reallocarray(status
, sz_status
+ 1, sizeof(int));
1329 status
[sz_status
++] = val
;
1333 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
1335 return bus_log_create_error(r
);
1337 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
1339 return bus_log_create_error(r
);
1341 r
= sd_bus_message_open_container(m
, 'v', "(aiai)");
1343 return bus_log_create_error(r
);
1345 r
= sd_bus_message_open_container(m
, 'r', "aiai");
1347 return bus_log_create_error(r
);
1349 r
= sd_bus_message_append_array(m
, 'i', status
, sz_status
);
1351 return bus_log_create_error(r
);
1353 r
= sd_bus_message_append_array(m
, 'i', signal
, sz_signal
);
1355 return bus_log_create_error(r
);
1357 r
= sd_bus_message_close_container(m
);
1359 return bus_log_create_error(r
);
1361 r
= sd_bus_message_close_container(m
);
1363 return bus_log_create_error(r
);
1365 r
= sd_bus_message_close_container(m
);
1367 return bus_log_create_error(r
);
1375 static int bus_append_socket_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1378 if (STR_IN_SET(field
,
1379 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1380 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1382 return bus_append_parse_boolean(m
, field
, eq
);
1384 if (STR_IN_SET(field
, "Priority", "IPTTL", "Mark"))
1386 return bus_append_safe_atoi(m
, field
, eq
);
1388 if (streq(field
, "IPTOS"))
1390 return bus_append_ip_tos_from_string(m
, field
, eq
);
1392 if (STR_IN_SET(field
, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1394 return bus_append_safe_atou(m
, field
, eq
);
1396 if (STR_IN_SET(field
, "SocketMode", "DirectoryMode"))
1398 return bus_append_parse_mode(m
, field
, eq
);
1400 if (STR_IN_SET(field
, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1402 return bus_append_safe_atoi64(m
, field
, eq
);
1404 if (STR_IN_SET(field
, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1406 return bus_append_parse_sec_rename(m
, field
, eq
);
1408 if (STR_IN_SET(field
, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1410 return bus_append_parse_size(m
, field
, eq
, 1024);
1412 if (STR_IN_SET(field
, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1414 return bus_append_exec_command(m
, field
, eq
);
1416 if (STR_IN_SET(field
,
1417 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1418 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1419 "SocketUser", "SocketGroup"))
1421 return bus_append_string(m
, field
, eq
);
1423 if (streq(field
, "Symlinks"))
1425 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1427 if (streq(field
, "SocketProtocol"))
1429 return bus_append_socket_protocol_from_name(m
, field
, eq
);
1431 if (STR_IN_SET(field
,
1432 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1433 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1436 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 0);
1438 r
= sd_bus_message_append(m
, "(sv)", "Listen", "a(ss)", 1, field
+ STRLEN("Listen"), eq
);
1440 return bus_log_create_error(r
);
1447 static int bus_append_timer_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1450 if (STR_IN_SET(field
, "WakeSystem", "RemainAfterElapse", "Persistent"))
1452 return bus_append_parse_boolean(m
, field
, eq
);
1454 if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec"))
1456 return bus_append_parse_sec_rename(m
, field
, eq
);
1458 if (STR_IN_SET(field
,
1459 "OnActiveSec", "OnBootSec", "OnStartupSec",
1460 "OnUnitActiveSec","OnUnitInactiveSec")) {
1463 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 0);
1466 r
= parse_sec(eq
, &t
);
1468 return log_error_errno(r
, "Failed to parse %s=%s: %m", field
, eq
);
1470 r
= sd_bus_message_append(m
, "(sv)", "TimersMonotonic", "a(st)", 1, field
, t
);
1473 return bus_log_create_error(r
);
1478 if (streq(field
, "OnCalendar")) {
1481 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 0);
1483 r
= sd_bus_message_append(m
, "(sv)", "TimersCalendar", "a(ss)", 1, field
, eq
);
1485 return bus_log_create_error(r
);
1493 static int bus_append_unit_property(sd_bus_message
*m
, const char *field
, const char *eq
) {
1494 ConditionType t
= _CONDITION_TYPE_INVALID
;
1495 bool is_condition
= false;
1498 if (STR_IN_SET(field
,
1499 "Description", "SourcePath", "OnFailureJobMode",
1500 "JobTimeoutAction", "JobTimeoutRebootArgument",
1501 "StartLimitAction", "FailureAction", "SuccessAction",
1502 "RebootArgument", "CollectMode"))
1504 return bus_append_string(m
, field
, eq
);
1506 if (STR_IN_SET(field
,
1507 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1508 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
1510 return bus_append_parse_boolean(m
, field
, eq
);
1512 if (STR_IN_SET(field
, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1514 return bus_append_parse_sec_rename(m
, field
, eq
);
1516 if (streq(field
, "StartLimitBurst"))
1518 return bus_append_safe_atou(m
, field
, eq
);
1520 if (unit_dependency_from_string(field
) >= 0 ||
1521 STR_IN_SET(field
, "Documentation", "RequiresMountsFor"))
1523 return bus_append_strv(m
, field
, eq
, EXTRACT_QUOTES
);
1525 t
= condition_type_from_string(field
);
1527 is_condition
= true;
1529 t
= assert_type_from_string(field
);
1532 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 0);
1535 int trigger
, negate
;
1537 trigger
= *p
== '|';
1545 r
= sd_bus_message_append(m
, "(sv)", is_condition
? "Conditions" : "Asserts", "a(sbbs)", 1,
1546 field
, trigger
, negate
, p
);
1549 return bus_log_create_error(r
);
1557 int bus_append_unit_property_assignment(sd_bus_message
*m
, UnitType t
, const char *assignment
) {
1558 const char *eq
, *field
;
1564 eq
= strchr(assignment
, '=');
1566 log_error("Not an assignment: %s", assignment
);
1570 field
= strndupa(assignment
, eq
- assignment
);
1575 r
= bus_append_cgroup_property(m
, field
, eq
);
1579 r
= bus_append_execute_property(m
, field
, eq
);
1583 r
= bus_append_kill_property(m
, field
, eq
);
1587 r
= bus_append_service_property(m
, field
, eq
);
1593 r
= bus_append_cgroup_property(m
, field
, eq
);
1597 r
= bus_append_execute_property(m
, field
, eq
);
1601 r
= bus_append_kill_property(m
, field
, eq
);
1605 r
= bus_append_socket_property(m
, field
, eq
);
1611 r
= bus_append_timer_property(m
, field
, eq
);
1617 r
= bus_append_path_property(m
, field
, eq
);
1623 r
= bus_append_cgroup_property(m
, field
, eq
);
1630 if (streq(field
, "TimeoutStopSec"))
1631 return bus_append_parse_sec_rename(m
, field
, eq
);
1633 r
= bus_append_cgroup_property(m
, field
, eq
);
1637 r
= bus_append_kill_property(m
, field
, eq
);
1643 r
= bus_append_cgroup_property(m
, field
, eq
);
1647 r
= bus_append_execute_property(m
, field
, eq
);
1651 r
= bus_append_kill_property(m
, field
, eq
);
1655 r
= bus_append_mount_property(m
, field
, eq
);
1661 case UNIT_AUTOMOUNT
:
1662 r
= bus_append_automount_property(m
, field
, eq
);
1671 log_error("Not supported unit type");
1675 log_error("Invalid unit type");
1679 r
= bus_append_unit_property(m
, field
, eq
);
1683 log_error("Unknown assignment: %s", assignment
);
1687 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, UnitType t
, char **l
) {
1693 STRV_FOREACH(i
, l
) {
1694 r
= bus_append_unit_property_assignment(m
, t
, *i
);
1702 typedef struct BusWaitForJobs
{
1709 sd_bus_slot
*slot_job_removed
;
1710 sd_bus_slot
*slot_disconnected
;
1713 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1716 log_error("Warning! D-Bus connection terminated.");
1717 sd_bus_close(sd_bus_message_get_bus(m
));
1722 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1723 const char *path
, *unit
, *result
;
1724 BusWaitForJobs
*d
= userdata
;
1732 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1734 bus_log_parse_error(r
);
1738 found
= set_remove(d
->jobs
, (char*) path
);
1744 if (!isempty(result
))
1745 d
->result
= strdup(result
);
1748 d
->name
= strdup(unit
);
1753 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1757 set_free_free(d
->jobs
);
1759 sd_bus_slot_unref(d
->slot_disconnected
);
1760 sd_bus_slot_unref(d
->slot_job_removed
);
1762 sd_bus_unref(d
->bus
);
1770 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1771 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1777 d
= new0(BusWaitForJobs
, 1);
1781 d
->bus
= sd_bus_ref(bus
);
1783 /* When we are a bus client we match by sender. Direct
1784 * connections OTOH have no initialized sender field, and
1785 * hence we ignore the sender then */
1786 r
= sd_bus_match_signal_async(
1788 &d
->slot_job_removed
,
1789 bus
->bus_client
? "org.freedesktop.systemd1" : NULL
,
1790 "/org/freedesktop/systemd1",
1791 "org.freedesktop.systemd1.Manager",
1793 match_job_removed
, NULL
, d
);
1797 r
= sd_bus_match_signal_async(
1799 &d
->slot_disconnected
,
1800 "org.freedesktop.DBus.Local",
1802 "org.freedesktop.DBus.Local",
1804 match_disconnected
, NULL
, d
);
1814 static int bus_process_wait(sd_bus
*bus
) {
1818 r
= sd_bus_process(bus
, NULL
);
1824 r
= sd_bus_wait(bus
, (uint64_t) -1);
1830 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1831 _cleanup_free_
char *dbus_path
= NULL
;
1837 if (!endswith(d
->name
, ".service"))
1840 dbus_path
= unit_dbus_path_from_name(d
->name
);
1844 return sd_bus_get_property_string(d
->bus
,
1845 "org.freedesktop.systemd1",
1847 "org.freedesktop.systemd1.Service",
1853 static const struct {
1854 const char *result
, *explanation
;
1855 } explanations
[] = {
1856 { "resources", "of unavailable resources or another system error" },
1857 { "protocol", "the service did not take the steps required by its unit configuration" },
1858 { "timeout", "a timeout was exceeded" },
1859 { "exit-code", "the control process exited with error code" },
1860 { "signal", "a fatal signal was delivered to the control process" },
1861 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1862 { "watchdog", "the service failed to send watchdog ping" },
1863 { "start-limit", "start of the service was attempted too often" }
1866 static void log_job_error_with_service_result(const char* service
, const char *result
, const char* const* extra_args
) {
1867 _cleanup_free_
char *service_shell_quoted
= NULL
;
1868 const char *systemctl
= "systemctl", *journalctl
= "journalctl";
1872 service_shell_quoted
= shell_maybe_quote(service
, ESCAPE_BACKSLASH
);
1874 if (!strv_isempty((char**) extra_args
)) {
1875 _cleanup_free_
char *t
;
1877 t
= strv_join((char**) extra_args
, " ");
1878 systemctl
= strjoina("systemctl ", t
? : "<args>");
1879 journalctl
= strjoina("journalctl ", t
? : "<args>");
1882 if (!isempty(result
)) {
1885 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1886 if (streq(result
, explanations
[i
].result
))
1889 if (i
< ELEMENTSOF(explanations
)) {
1890 log_error("Job for %s failed because %s.\n"
1891 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1893 explanations
[i
].explanation
,
1895 service_shell_quoted
?: "<service>",
1901 log_error("Job for %s failed.\n"
1902 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1905 service_shell_quoted
?: "<service>",
1909 /* For some results maybe additional explanation is required */
1910 if (streq_ptr(result
, "start-limit"))
1911 log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
1912 "followed by \"%1$s start %2$s\" again.",
1914 service_shell_quoted
?: "<service>");
1917 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1923 if (streq(d
->result
, "canceled"))
1924 log_error("Job for %s canceled.", strna(d
->name
));
1925 else if (streq(d
->result
, "timeout"))
1926 log_error("Job for %s timed out.", strna(d
->name
));
1927 else if (streq(d
->result
, "dependency"))
1928 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
1929 else if (streq(d
->result
, "invalid"))
1930 log_error("%s is not active, cannot reload.", strna(d
->name
));
1931 else if (streq(d
->result
, "assert"))
1932 log_error("Assertion failed on job for %s.", strna(d
->name
));
1933 else if (streq(d
->result
, "unsupported"))
1934 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
1935 else if (streq(d
->result
, "collected"))
1936 log_error("Queued job for %s was garbage collected.", strna(d
->name
));
1937 else if (!STR_IN_SET(d
->result
, "done", "skipped")) {
1939 _cleanup_free_
char *result
= NULL
;
1942 q
= bus_job_get_service_result(d
, &result
);
1944 log_debug_errno(q
, "Failed to get Result property of unit %s: %m", d
->name
);
1946 log_job_error_with_service_result(d
->name
, result
, extra_args
);
1948 log_error("Job failed. See \"journalctl -xe\" for details.");
1952 if (STR_IN_SET(d
->result
, "canceled", "collected"))
1954 else if (streq(d
->result
, "timeout"))
1956 else if (streq(d
->result
, "dependency"))
1958 else if (streq(d
->result
, "invalid"))
1960 else if (streq(d
->result
, "assert"))
1962 else if (streq(d
->result
, "unsupported"))
1964 else if (!STR_IN_SET(d
->result
, "done", "skipped"))
1970 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1975 while (!set_isempty(d
->jobs
)) {
1978 q
= bus_process_wait(d
->bus
);
1980 return log_error_errno(q
, "Failed to wait for response: %m");
1983 q
= check_wait_response(d
, quiet
, extra_args
);
1984 /* Return the first error as it is most likely to be
1986 if (q
< 0 && r
== 0)
1989 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
1992 d
->name
= mfree(d
->name
);
1993 d
->result
= mfree(d
->result
);
1999 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2004 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2008 return set_put_strdup(d
->jobs
, path
);
2011 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2014 r
= bus_wait_for_jobs_add(d
, path
);
2018 return bus_wait_for_jobs(d
, quiet
, NULL
);
2021 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2022 const char *type
, *path
, *source
;
2025 /* changes is dereferenced when calling unit_file_dump_changes() later,
2026 * so we have to make sure this is not NULL. */
2030 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2032 return bus_log_parse_error(r
);
2034 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2035 /* We expect only "success" changes to be sent over the bus.
2036 Hence, reject anything negative. */
2037 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
2040 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
2044 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2049 return bus_log_parse_error(r
);
2051 r
= sd_bus_message_exit_container(m
);
2053 return bus_log_parse_error(r
);
2055 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2061 bool is_const
; /* If false, cgroup_path should be free()'d */
2063 Hashmap
*pids
; /* PID → process name */
2066 struct CGroupInfo
*parent
;
2067 LIST_FIELDS(struct CGroupInfo
, siblings
);
2068 LIST_HEAD(struct CGroupInfo
, children
);
2072 static bool IS_ROOT(const char *p
) {
2073 return isempty(p
) || streq(p
, "/");
2076 static int add_cgroup(Hashmap
*cgroups
, const char *path
, bool is_const
, struct CGroupInfo
**ret
) {
2077 struct CGroupInfo
*parent
= NULL
, *cg
;
2086 cg
= hashmap_get(cgroups
, path
);
2092 if (!IS_ROOT(path
)) {
2095 e
= strrchr(path
, '/');
2099 pp
= strndupa(path
, e
- path
);
2103 r
= add_cgroup(cgroups
, pp
, false, &parent
);
2108 cg
= new0(struct CGroupInfo
, 1);
2113 cg
->cgroup_path
= (char*) path
;
2115 cg
->cgroup_path
= strdup(path
);
2116 if (!cg
->cgroup_path
) {
2122 cg
->is_const
= is_const
;
2123 cg
->parent
= parent
;
2125 r
= hashmap_put(cgroups
, cg
->cgroup_path
, cg
);
2128 free(cg
->cgroup_path
);
2134 LIST_PREPEND(siblings
, parent
->children
, cg
);
2135 parent
->n_children
++;
2142 static int add_process(
2148 struct CGroupInfo
*cg
;
2155 r
= add_cgroup(cgroups
, path
, true, &cg
);
2159 r
= hashmap_ensure_allocated(&cg
->pids
, &trivial_hash_ops
);
2163 return hashmap_put(cg
->pids
, PID_TO_PTR(pid
), (void*) name
);
2166 static void remove_cgroup(Hashmap
*cgroups
, struct CGroupInfo
*cg
) {
2170 while (cg
->children
)
2171 remove_cgroup(cgroups
, cg
->children
);
2173 hashmap_remove(cgroups
, cg
->cgroup_path
);
2176 free(cg
->cgroup_path
);
2178 hashmap_free(cg
->pids
);
2181 LIST_REMOVE(siblings
, cg
->parent
->children
, cg
);
2186 static int cgroup_info_compare_func(const void *a
, const void *b
) {
2187 const struct CGroupInfo
*x
= *(const struct CGroupInfo
* const*) a
, *y
= *(const struct CGroupInfo
* const*) b
;
2192 return strcmp(x
->cgroup_path
, y
->cgroup_path
);
2195 static int dump_processes(
2197 const char *cgroup_path
,
2200 OutputFlags flags
) {
2202 struct CGroupInfo
*cg
;
2207 if (IS_ROOT(cgroup_path
))
2210 cg
= hashmap_get(cgroups
, cgroup_path
);
2214 if (!hashmap_isempty(cg
->pids
)) {
2222 /* Order processes by their PID */
2223 pids
= newa(pid_t
, hashmap_size(cg
->pids
));
2225 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
)
2226 pids
[n
++] = PTR_TO_PID(pidp
);
2228 assert(n
== hashmap_size(cg
->pids
));
2229 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
2231 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2233 for (i
= 0; i
< n
; i
++) {
2234 _cleanup_free_
char *e
= NULL
;
2235 const char *special
;
2238 name
= hashmap_get(cg
->pids
, PID_TO_PTR(pids
[i
]));
2241 if (n_columns
!= 0) {
2244 k
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2246 e
= ellipsize(name
, k
, 100);
2251 more
= i
+1 < n
|| cg
->children
;
2252 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
2254 fprintf(stdout
, "%s%s%*"PID_PRI
" %s\n",
2263 struct CGroupInfo
**children
, *child
;
2266 /* Order subcgroups by their name */
2267 children
= newa(struct CGroupInfo
*, cg
->n_children
);
2268 LIST_FOREACH(siblings
, child
, cg
->children
)
2269 children
[n
++] = child
;
2270 assert(n
== cg
->n_children
);
2271 qsort_safe(children
, n
, sizeof(struct CGroupInfo
*), cgroup_info_compare_func
);
2274 n_columns
= MAX(LESS_BY(n_columns
, 2U), 20U);
2276 for (i
= 0; i
< n
; i
++) {
2277 _cleanup_free_
char *pp
= NULL
;
2278 const char *name
, *special
;
2281 child
= children
[i
];
2283 name
= strrchr(child
->cgroup_path
, '/');
2289 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
2291 fputs(prefix
, stdout
);
2292 fputs(special
, stdout
);
2293 fputs(name
, stdout
);
2294 fputc('\n', stdout
);
2296 special
= special_glyph(more
? TREE_VERTICAL
: TREE_SPACE
);
2298 pp
= strappend(prefix
, special
);
2302 r
= dump_processes(cgroups
, child
->cgroup_path
, pp
, n_columns
, flags
);
2312 static int dump_extra_processes(
2316 OutputFlags flags
) {
2318 _cleanup_free_ pid_t
*pids
= NULL
;
2319 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
2320 struct CGroupInfo
*cg
;
2321 size_t n_allocated
= 0, n
= 0, k
;
2325 /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
2326 * combined, sorted, linear list. */
2328 HASHMAP_FOREACH(cg
, cgroups
, i
) {
2336 if (hashmap_isempty(cg
->pids
))
2339 r
= hashmap_ensure_allocated(&names
, &trivial_hash_ops
);
2343 if (!GREEDY_REALLOC(pids
, n_allocated
, n
+ hashmap_size(cg
->pids
)))
2346 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
) {
2347 pids
[n
++] = PTR_TO_PID(pidp
);
2349 r
= hashmap_put(names
, pidp
, (void*) name
);
2358 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
2359 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2361 for (k
= 0; k
< n
; k
++) {
2362 _cleanup_free_
char *e
= NULL
;
2365 name
= hashmap_get(names
, PID_TO_PTR(pids
[k
]));
2368 if (n_columns
!= 0) {
2371 z
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2373 e
= ellipsize(name
, z
, 100);
2378 fprintf(stdout
, "%s%s %*" PID_PRI
" %s\n",
2380 special_glyph(TRIANGULAR_BULLET
),
2388 int unit_show_processes(
2391 const char *cgroup_path
,
2395 sd_bus_error
*error
) {
2397 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2398 Hashmap
*cgroups
= NULL
;
2399 struct CGroupInfo
*cg
;
2405 if (flags
& OUTPUT_FULL_WIDTH
)
2407 else if (n_columns
<= 0)
2408 n_columns
= columns();
2410 prefix
= strempty(prefix
);
2412 r
= sd_bus_call_method(
2414 "org.freedesktop.systemd1",
2415 "/org/freedesktop/systemd1",
2416 "org.freedesktop.systemd1.Manager",
2425 cgroups
= hashmap_new(&path_hash_ops
);
2429 r
= sd_bus_message_enter_container(reply
, 'a', "(sus)");
2434 const char *path
= NULL
, *name
= NULL
;
2437 r
= sd_bus_message_read(reply
, "(sus)", &path
, &pid
, &name
);
2443 r
= add_process(cgroups
, path
, pid
, name
);
2448 r
= sd_bus_message_exit_container(reply
);
2452 r
= dump_processes(cgroups
, cgroup_path
, prefix
, n_columns
, flags
);
2456 r
= dump_extra_processes(cgroups
, prefix
, n_columns
, flags
);
2459 while ((cg
= hashmap_first(cgroups
)))
2460 remove_cgroup(cgroups
, cg
);
2462 hashmap_free(cgroups
);