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
);
1813 static int bus_process_wait(sd_bus
*bus
) {
1817 r
= sd_bus_process(bus
, NULL
);
1823 r
= sd_bus_wait(bus
, (uint64_t) -1);
1829 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1830 _cleanup_free_
char *dbus_path
= NULL
;
1836 if (!endswith(d
->name
, ".service"))
1839 dbus_path
= unit_dbus_path_from_name(d
->name
);
1843 return sd_bus_get_property_string(d
->bus
,
1844 "org.freedesktop.systemd1",
1846 "org.freedesktop.systemd1.Service",
1852 static const struct {
1853 const char *result
, *explanation
;
1854 } explanations
[] = {
1855 { "resources", "of unavailable resources or another system error" },
1856 { "protocol", "the service did not take the steps required by its unit configuration" },
1857 { "timeout", "a timeout was exceeded" },
1858 { "exit-code", "the control process exited with error code" },
1859 { "signal", "a fatal signal was delivered to the control process" },
1860 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1861 { "watchdog", "the service failed to send watchdog ping" },
1862 { "start-limit", "start of the service was attempted too often" }
1865 static void log_job_error_with_service_result(const char* service
, const char *result
, const char* const* extra_args
) {
1866 _cleanup_free_
char *service_shell_quoted
= NULL
;
1867 const char *systemctl
= "systemctl", *journalctl
= "journalctl";
1871 service_shell_quoted
= shell_maybe_quote(service
, ESCAPE_BACKSLASH
);
1873 if (!strv_isempty((char**) extra_args
)) {
1874 _cleanup_free_
char *t
;
1876 t
= strv_join((char**) extra_args
, " ");
1877 systemctl
= strjoina("systemctl ", t
? : "<args>");
1878 journalctl
= strjoina("journalctl ", t
? : "<args>");
1881 if (!isempty(result
)) {
1884 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1885 if (streq(result
, explanations
[i
].result
))
1888 if (i
< ELEMENTSOF(explanations
)) {
1889 log_error("Job for %s failed because %s.\n"
1890 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1892 explanations
[i
].explanation
,
1894 service_shell_quoted
?: "<service>",
1900 log_error("Job for %s failed.\n"
1901 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1904 service_shell_quoted
?: "<service>",
1908 /* For some results maybe additional explanation is required */
1909 if (streq_ptr(result
, "start-limit"))
1910 log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
1911 "followed by \"%1$s start %2$s\" again.",
1913 service_shell_quoted
?: "<service>");
1916 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1922 if (streq(d
->result
, "canceled"))
1923 log_error("Job for %s canceled.", strna(d
->name
));
1924 else if (streq(d
->result
, "timeout"))
1925 log_error("Job for %s timed out.", strna(d
->name
));
1926 else if (streq(d
->result
, "dependency"))
1927 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
1928 else if (streq(d
->result
, "invalid"))
1929 log_error("%s is not active, cannot reload.", strna(d
->name
));
1930 else if (streq(d
->result
, "assert"))
1931 log_error("Assertion failed on job for %s.", strna(d
->name
));
1932 else if (streq(d
->result
, "unsupported"))
1933 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
1934 else if (streq(d
->result
, "collected"))
1935 log_error("Queued job for %s was garbage collected.", strna(d
->name
));
1936 else if (!STR_IN_SET(d
->result
, "done", "skipped")) {
1938 _cleanup_free_
char *result
= NULL
;
1941 q
= bus_job_get_service_result(d
, &result
);
1943 log_debug_errno(q
, "Failed to get Result property of unit %s: %m", d
->name
);
1945 log_job_error_with_service_result(d
->name
, result
, extra_args
);
1947 log_error("Job failed. See \"journalctl -xe\" for details.");
1951 if (STR_IN_SET(d
->result
, "canceled", "collected"))
1953 else if (streq(d
->result
, "timeout"))
1955 else if (streq(d
->result
, "dependency"))
1957 else if (streq(d
->result
, "invalid"))
1959 else if (streq(d
->result
, "assert"))
1961 else if (streq(d
->result
, "unsupported"))
1963 else if (!STR_IN_SET(d
->result
, "done", "skipped"))
1969 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1974 while (!set_isempty(d
->jobs
)) {
1977 q
= bus_process_wait(d
->bus
);
1979 return log_error_errno(q
, "Failed to wait for response: %m");
1982 q
= check_wait_response(d
, quiet
, extra_args
);
1983 /* Return the first error as it is most likely to be
1985 if (q
< 0 && r
== 0)
1988 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
1991 d
->name
= mfree(d
->name
);
1992 d
->result
= mfree(d
->result
);
1998 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
2003 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
2007 return set_put_strdup(d
->jobs
, path
);
2010 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
2013 r
= bus_wait_for_jobs_add(d
, path
);
2017 return bus_wait_for_jobs(d
, quiet
, NULL
);
2020 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
2021 const char *type
, *path
, *source
;
2024 /* changes is dereferenced when calling unit_file_dump_changes() later,
2025 * so we have to make sure this is not NULL. */
2029 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
2031 return bus_log_parse_error(r
);
2033 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
2034 /* We expect only "success" changes to be sent over the bus.
2035 Hence, reject anything negative. */
2036 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
2039 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
2043 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
2048 return bus_log_parse_error(r
);
2050 r
= sd_bus_message_exit_container(m
);
2052 return bus_log_parse_error(r
);
2054 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
2060 bool is_const
; /* If false, cgroup_path should be free()'d */
2062 Hashmap
*pids
; /* PID → process name */
2065 struct CGroupInfo
*parent
;
2066 LIST_FIELDS(struct CGroupInfo
, siblings
);
2067 LIST_HEAD(struct CGroupInfo
, children
);
2071 static bool IS_ROOT(const char *p
) {
2072 return isempty(p
) || streq(p
, "/");
2075 static int add_cgroup(Hashmap
*cgroups
, const char *path
, bool is_const
, struct CGroupInfo
**ret
) {
2076 struct CGroupInfo
*parent
= NULL
, *cg
;
2085 cg
= hashmap_get(cgroups
, path
);
2091 if (!IS_ROOT(path
)) {
2094 e
= strrchr(path
, '/');
2098 pp
= strndupa(path
, e
- path
);
2102 r
= add_cgroup(cgroups
, pp
, false, &parent
);
2107 cg
= new0(struct CGroupInfo
, 1);
2112 cg
->cgroup_path
= (char*) path
;
2114 cg
->cgroup_path
= strdup(path
);
2115 if (!cg
->cgroup_path
) {
2121 cg
->is_const
= is_const
;
2122 cg
->parent
= parent
;
2124 r
= hashmap_put(cgroups
, cg
->cgroup_path
, cg
);
2127 free(cg
->cgroup_path
);
2133 LIST_PREPEND(siblings
, parent
->children
, cg
);
2134 parent
->n_children
++;
2141 static int add_process(
2147 struct CGroupInfo
*cg
;
2154 r
= add_cgroup(cgroups
, path
, true, &cg
);
2158 r
= hashmap_ensure_allocated(&cg
->pids
, &trivial_hash_ops
);
2162 return hashmap_put(cg
->pids
, PID_TO_PTR(pid
), (void*) name
);
2165 static void remove_cgroup(Hashmap
*cgroups
, struct CGroupInfo
*cg
) {
2169 while (cg
->children
)
2170 remove_cgroup(cgroups
, cg
->children
);
2172 hashmap_remove(cgroups
, cg
->cgroup_path
);
2175 free(cg
->cgroup_path
);
2177 hashmap_free(cg
->pids
);
2180 LIST_REMOVE(siblings
, cg
->parent
->children
, cg
);
2185 static int cgroup_info_compare_func(const void *a
, const void *b
) {
2186 const struct CGroupInfo
*x
= *(const struct CGroupInfo
* const*) a
, *y
= *(const struct CGroupInfo
* const*) b
;
2191 return strcmp(x
->cgroup_path
, y
->cgroup_path
);
2194 static int dump_processes(
2196 const char *cgroup_path
,
2199 OutputFlags flags
) {
2201 struct CGroupInfo
*cg
;
2206 if (IS_ROOT(cgroup_path
))
2209 cg
= hashmap_get(cgroups
, cgroup_path
);
2213 if (!hashmap_isempty(cg
->pids
)) {
2221 /* Order processes by their PID */
2222 pids
= newa(pid_t
, hashmap_size(cg
->pids
));
2224 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
)
2225 pids
[n
++] = PTR_TO_PID(pidp
);
2227 assert(n
== hashmap_size(cg
->pids
));
2228 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
2230 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2232 for (i
= 0; i
< n
; i
++) {
2233 _cleanup_free_
char *e
= NULL
;
2234 const char *special
;
2237 name
= hashmap_get(cg
->pids
, PID_TO_PTR(pids
[i
]));
2240 if (n_columns
!= 0) {
2243 k
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2245 e
= ellipsize(name
, k
, 100);
2250 more
= i
+1 < n
|| cg
->children
;
2251 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
2253 fprintf(stdout
, "%s%s%*"PID_PRI
" %s\n",
2262 struct CGroupInfo
**children
, *child
;
2265 /* Order subcgroups by their name */
2266 children
= newa(struct CGroupInfo
*, cg
->n_children
);
2267 LIST_FOREACH(siblings
, child
, cg
->children
)
2268 children
[n
++] = child
;
2269 assert(n
== cg
->n_children
);
2270 qsort_safe(children
, n
, sizeof(struct CGroupInfo
*), cgroup_info_compare_func
);
2273 n_columns
= MAX(LESS_BY(n_columns
, 2U), 20U);
2275 for (i
= 0; i
< n
; i
++) {
2276 _cleanup_free_
char *pp
= NULL
;
2277 const char *name
, *special
;
2280 child
= children
[i
];
2282 name
= strrchr(child
->cgroup_path
, '/');
2288 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
2290 fputs(prefix
, stdout
);
2291 fputs(special
, stdout
);
2292 fputs(name
, stdout
);
2293 fputc('\n', stdout
);
2295 special
= special_glyph(more
? TREE_VERTICAL
: TREE_SPACE
);
2297 pp
= strappend(prefix
, special
);
2301 r
= dump_processes(cgroups
, child
->cgroup_path
, pp
, n_columns
, flags
);
2311 static int dump_extra_processes(
2315 OutputFlags flags
) {
2317 _cleanup_free_ pid_t
*pids
= NULL
;
2318 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
2319 struct CGroupInfo
*cg
;
2320 size_t n_allocated
= 0, n
= 0, k
;
2324 /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
2325 * combined, sorted, linear list. */
2327 HASHMAP_FOREACH(cg
, cgroups
, i
) {
2335 if (hashmap_isempty(cg
->pids
))
2338 r
= hashmap_ensure_allocated(&names
, &trivial_hash_ops
);
2342 if (!GREEDY_REALLOC(pids
, n_allocated
, n
+ hashmap_size(cg
->pids
)))
2345 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
) {
2346 pids
[n
++] = PTR_TO_PID(pidp
);
2348 r
= hashmap_put(names
, pidp
, (void*) name
);
2357 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
2358 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
2360 for (k
= 0; k
< n
; k
++) {
2361 _cleanup_free_
char *e
= NULL
;
2364 name
= hashmap_get(names
, PID_TO_PTR(pids
[k
]));
2367 if (n_columns
!= 0) {
2370 z
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
2372 e
= ellipsize(name
, z
, 100);
2377 fprintf(stdout
, "%s%s %*" PID_PRI
" %s\n",
2379 special_glyph(TRIANGULAR_BULLET
),
2387 int unit_show_processes(
2390 const char *cgroup_path
,
2394 sd_bus_error
*error
) {
2396 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2397 Hashmap
*cgroups
= NULL
;
2398 struct CGroupInfo
*cg
;
2404 if (flags
& OUTPUT_FULL_WIDTH
)
2406 else if (n_columns
<= 0)
2407 n_columns
= columns();
2409 prefix
= strempty(prefix
);
2411 r
= sd_bus_call_method(
2413 "org.freedesktop.systemd1",
2414 "/org/freedesktop/systemd1",
2415 "org.freedesktop.systemd1.Manager",
2424 cgroups
= hashmap_new(&path_hash_ops
);
2428 r
= sd_bus_message_enter_container(reply
, 'a', "(sus)");
2433 const char *path
= NULL
, *name
= NULL
;
2436 r
= sd_bus_message_read(reply
, "(sus)", &path
, &pid
, &name
);
2442 r
= add_process(cgroups
, path
, pid
, name
);
2447 r
= sd_bus_message_exit_container(reply
);
2451 r
= dump_processes(cgroups
, cgroup_path
, prefix
, n_columns
, flags
);
2455 r
= dump_extra_processes(cgroups
, prefix
, n_columns
, flags
);
2458 while ((cg
= hashmap_first(cgroups
)))
2459 remove_cgroup(cgroups
, cg
);
2461 hashmap_free(cgroups
);