2 This file is part of systemd.
4 Copyright 2016 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "alloc-util.h"
21 #include "bus-internal.h"
22 #include "bus-unit-util.h"
25 #include "cgroup-util.h"
26 #include "cpu-set-util.h"
28 #include "errno-list.h"
31 #include "hostname-util.h"
32 #include "in-addr-util.h"
34 #include "locale-util.h"
35 #include "mount-util.h"
37 #include "parse-util.h"
38 #include "path-util.h"
39 #include "process-util.h"
40 #include "rlimit-util.h"
41 #include "securebits-util.h"
42 #include "signal-util.h"
43 #include "string-util.h"
44 #include "syslog-util.h"
45 #include "terminal-util.h"
46 #include "user-util.h"
50 int bus_parse_unit_info(sd_bus_message
*message
, UnitInfo
*u
) {
56 return sd_bus_message_read(
71 static int bus_append_ip_address_access(sd_bus_message
*m
, int family
, const union in_addr_union
*prefix
, unsigned char prefixlen
) {
77 r
= sd_bus_message_open_container(m
, 'r', "iayu");
81 r
= sd_bus_message_append(m
, "i", family
);
85 r
= sd_bus_message_append_array(m
, 'y', prefix
, FAMILY_ADDRESS_SIZE(family
));
89 r
= sd_bus_message_append(m
, "u", prefixlen
);
93 return sd_bus_message_close_container(m
);
96 int bus_append_unit_property_assignment(sd_bus_message
*m
, const char *assignment
) {
97 const char *eq
, *field
;
104 eq
= strchr(assignment
, '=');
106 log_error("Not an assignment: %s", assignment
);
110 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
112 return bus_log_create_error(r
);
114 field
= strndupa(assignment
, eq
- assignment
);
117 if (streq(field
, "CPUQuota")) {
120 r
= sd_bus_message_append(m
, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY
);
122 r
= parse_percent_unbounded(eq
);
124 log_error_errno(r
, "CPU quota '%s' invalid.", eq
);
128 r
= sd_bus_message_append(m
, "sv", "CPUQuotaPerSecUSec", "t", (usec_t
) r
* USEC_PER_SEC
/ 100U);
133 } else if (streq(field
, "EnvironmentFile")) {
135 r
= sd_bus_message_append(m
, "sv", "EnvironmentFiles", "a(sb)", 1,
136 eq
[0] == '-' ? eq
+ 1 : eq
,
140 } else if (STR_IN_SET(field
, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) {
145 r
= parse_sec(eq
, &t
);
147 return log_error_errno(r
, "Failed to parse %s= parameter: %s", field
, eq
);
150 n
= newa(char, l
+ 2);
154 /* Change suffix Sec → USec */
155 strcpy(mempcpy(n
, field
, l
- 3), "USec");
156 r
= sd_bus_message_append(m
, "sv", n
, "t", t
);
159 } else if (streq(field
, "LogExtraFields")) {
161 r
= sd_bus_message_append(m
, "s", "LogExtraFields");
165 r
= sd_bus_message_open_container(m
, 'v', "aay");
169 r
= sd_bus_message_open_container(m
, 'a', "ay");
173 r
= sd_bus_message_append_array(m
, 'y', eq
, strlen(eq
));
177 r
= sd_bus_message_close_container(m
);
181 r
= sd_bus_message_close_container(m
);
184 } else if (STR_IN_SET(field
, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) {
187 if (isempty(eq
) || streq(eq
, "infinity"))
188 bytes
= CGROUP_LIMIT_MAX
;
190 r
= parse_percent(eq
);
194 /* When this is a percentage we'll convert this into a relative value in the range
195 * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related
196 * ones). This way the physical memory size can be determined server-side */
198 n
= strjoina(field
, "Scale");
199 r
= sd_bus_message_append(m
, "sv", n
, "u", (uint32_t) (((uint64_t) UINT32_MAX
* r
) / 100U));
203 r
= parse_size(eq
, 1024, &bytes
);
205 return log_error_errno(r
, "Failed to parse bytes specification %s", assignment
);
209 r
= sd_bus_message_append(m
, "sv", field
, "t", bytes
);
212 } else if (streq(field
, "Delegate")) {
214 r
= parse_boolean(eq
);
218 r
= sd_bus_message_append(m
, "s", "DelegateControllers");
222 r
= sd_bus_message_open_container(m
, 'v', "as");
226 r
= sd_bus_message_open_container(m
, 'a', "s");
231 _cleanup_free_
char *word
= NULL
;
233 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
239 return log_error_errno(r
, "Invalid syntax: %s", eq
);
241 r
= sd_bus_message_append(m
, "s", word
);
246 r
= sd_bus_message_close_container(m
);
250 r
= sd_bus_message_close_container(m
);
252 r
= sd_bus_message_append(m
, "sv", "Delegate", "b", r
);
256 } else if (streq(field
, "TasksMax")) {
259 if (isempty(eq
) || streq(eq
, "infinity"))
262 r
= parse_percent(eq
);
264 r
= sd_bus_message_append(m
, "sv", "TasksMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX
* r
) / 100U));
267 r
= safe_atou64(eq
, &t
);
269 return log_error_errno(r
, "Failed to parse maximum tasks specification %s", assignment
);
274 r
= sd_bus_message_append(m
, "sv", "TasksMax", "t", t
);
278 r
= sd_bus_message_append_basic(m
, SD_BUS_TYPE_STRING
, field
);
280 return bus_log_create_error(r
);
282 rl
= rlimit_from_string(field
);
287 r
= rlimit_parse(rl
, eq
, &l
);
289 return log_error_errno(r
, "Failed to parse resource limit: %s", eq
);
291 r
= sd_bus_message_append(m
, "v", "t", l
.rlim_max
);
293 return bus_log_create_error(r
);
295 r
= sd_bus_message_close_container(m
);
297 return bus_log_create_error(r
);
299 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_STRUCT
, "sv");
301 return bus_log_create_error(r
);
303 sn
= strjoina(field
, "Soft");
304 r
= sd_bus_message_append(m
, "sv", sn
, "t", l
.rlim_cur
);
306 } else if (STR_IN_SET(field
,
307 "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
308 "TasksAccounting", "IPAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem",
309 "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
310 "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
311 "NoNewPrivileges", "SyslogLevelPrefix", "RemainAfterElapse",
312 "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
313 "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS",
314 "CPUSchedulingResetOnFork", "LockPersonality")) {
316 r
= parse_boolean(eq
);
318 return log_error_errno(r
, "Failed to parse boolean assignment %s.", assignment
);
320 r
= sd_bus_message_append(m
, "v", "b", r
);
322 } else if (STR_IN_SET(field
, "CPUWeight", "StartupCPUWeight")) {
325 r
= cg_weight_parse(eq
, &u
);
327 log_error("Failed to parse %s value %s.", field
, eq
);
331 r
= sd_bus_message_append(m
, "v", "t", u
);
333 } else if (STR_IN_SET(field
, "CPUShares", "StartupCPUShares")) {
336 r
= cg_cpu_shares_parse(eq
, &u
);
338 log_error("Failed to parse %s value %s.", field
, eq
);
342 r
= sd_bus_message_append(m
, "v", "t", u
);
344 } else if (STR_IN_SET(field
, "IOWeight", "StartupIOWeight")) {
347 r
= cg_weight_parse(eq
, &u
);
349 log_error("Failed to parse %s value %s.", field
, eq
);
353 r
= sd_bus_message_append(m
, "v", "t", u
);
355 } else if (STR_IN_SET(field
, "BlockIOWeight", "StartupBlockIOWeight")) {
358 r
= cg_blkio_weight_parse(eq
, &u
);
360 log_error("Failed to parse %s value %s.", field
, eq
);
364 r
= sd_bus_message_append(m
, "v", "t", u
);
366 } else if (STR_IN_SET(field
,
367 "User", "Group", "DevicePolicy", "KillMode",
368 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
369 "StandardInput", "StandardOutput", "StandardError",
370 "Description", "Slice", "Type", "WorkingDirectory",
371 "RootDirectory", "SyslogIdentifier", "ProtectSystem",
372 "ProtectHome", "SELinuxContext", "Restart", "RootImage",
373 "NotifyAccess", "RuntimeDirectoryPreserve", "Personality",
374 "KeyringMode", "CollectMode"))
375 r
= sd_bus_message_append(m
, "v", "s", eq
);
377 else if (STR_IN_SET(field
, "AppArmorProfile", "SmackProcessLabel")) {
389 r
= sd_bus_message_append(m
, "v", "(bs)", ignore
, s
);
391 } else if (STR_IN_SET(field
, "SyslogLevel", "LogLevelMax")) {
394 level
= log_level_from_string(eq
);
396 log_error("Failed to parse %s value %s.", field
, eq
);
400 r
= sd_bus_message_append(m
, "v", "i", level
);
402 } else if (streq(field
, "SyslogFacility")) {
405 facility
= log_facility_unshifted_from_string(eq
);
407 log_error("Failed to parse %s value %s.", field
, eq
);
411 r
= sd_bus_message_append(m
, "v", "i", facility
);
413 } else if (streq(field
, "SecureBits")) {
415 r
= secure_bits_from_string(eq
);
417 log_error("Failed to parse %s value %s.", field
, eq
);
421 r
= sd_bus_message_append(m
, "v", "i", r
);
423 } else if (STR_IN_SET(field
, "CapabilityBoundingSet", "AmbientCapabilities")) {
434 r
= capability_set_from_string(p
, &sum
);
436 log_error("Failed to parse %s value %s.", field
, eq
);
440 sum
= invert
? ~sum
: sum
;
442 r
= sd_bus_message_append(m
, "v", "t", sum
);
444 } else if (streq(field
, "DeviceAllow")) {
447 r
= sd_bus_message_append(m
, "v", "a(ss)", 0);
449 const char *path
, *rwm
, *e
;
453 path
= strndupa(eq
, e
- eq
);
460 if (!is_deviceallow_pattern(path
)) {
461 log_error("%s is not a device file in /dev.", path
);
465 r
= sd_bus_message_append(m
, "v", "a(ss)", 1, path
, rwm
);
468 } else if (cgroup_io_limit_type_from_string(field
) >= 0 || STR_IN_SET(field
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
471 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
473 const char *path
, *bandwidth
, *e
;
478 path
= strndupa(eq
, e
- eq
);
481 log_error("Failed to parse %s value %s.", field
, eq
);
485 if (!path_startswith(path
, "/dev")) {
486 log_error("%s is not a device file in /dev.", path
);
490 if (streq(bandwidth
, "infinity")) {
491 bytes
= CGROUP_LIMIT_MAX
;
493 r
= parse_size(bandwidth
, 1000, &bytes
);
495 log_error("Failed to parse byte value %s.", bandwidth
);
500 r
= sd_bus_message_append(m
, "v", "a(st)", 1, path
, bytes
);
503 } else if (STR_IN_SET(field
, "IODeviceWeight", "BlockIODeviceWeight")) {
506 r
= sd_bus_message_append(m
, "v", "a(st)", 0);
508 const char *path
, *weight
, *e
;
513 path
= strndupa(eq
, e
- eq
);
516 log_error("Failed to parse %s value %s.", field
, eq
);
520 if (!path_startswith(path
, "/dev")) {
521 log_error("%s is not a device file in /dev.", path
);
525 r
= safe_atou64(weight
, &u
);
527 log_error("Failed to parse %s value %s.", field
, weight
);
530 r
= sd_bus_message_append(m
, "v", "a(st)", 1, path
, u
);
533 } else if (STR_IN_SET(field
, "IPAddressAllow", "IPAddressDeny")) {
536 r
= sd_bus_message_append(m
, "v", "a(iayu)", 0);
538 unsigned char prefixlen
;
539 union in_addr_union prefix
= {};
542 r
= sd_bus_message_open_container(m
, 'v', "a(iayu)");
544 return bus_log_create_error(r
);
546 r
= sd_bus_message_open_container(m
, 'a', "(iayu)");
548 return bus_log_create_error(r
);
550 if (streq(eq
, "any")) {
551 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
553 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 0);
555 return bus_log_create_error(r
);
557 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 0);
559 return bus_log_create_error(r
);
561 } else if (is_localhost(eq
)) {
562 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
564 prefix
.in
.s_addr
= htobe32(0x7f000000);
565 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 8);
567 return bus_log_create_error(r
);
569 prefix
.in6
= (struct in6_addr
) IN6ADDR_LOOPBACK_INIT
;
570 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 128);
574 } else if (streq(eq
, "link-local")) {
576 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
578 prefix
.in
.s_addr
= htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
579 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 16);
581 return bus_log_create_error(r
);
583 prefix
.in6
= (struct in6_addr
) {
584 .s6_addr32
[0] = htobe32(0xfe800000)
586 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 64);
588 return bus_log_create_error(r
);
590 } else if (streq(eq
, "multicast")) {
592 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
594 prefix
.in
.s_addr
= htobe32((UINT32_C(224) << 24));
595 r
= bus_append_ip_address_access(m
, AF_INET
, &prefix
, 4);
597 return bus_log_create_error(r
);
599 prefix
.in6
= (struct in6_addr
) {
600 .s6_addr32
[0] = htobe32(0xff000000)
602 r
= bus_append_ip_address_access(m
, AF_INET6
, &prefix
, 8);
604 return bus_log_create_error(r
);
607 r
= in_addr_prefix_from_string_auto(eq
, &family
, &prefix
, &prefixlen
);
609 return log_error_errno(r
, "Failed to parse IP address prefix: %s", eq
);
611 r
= bus_append_ip_address_access(m
, family
, &prefix
, prefixlen
);
613 return bus_log_create_error(r
);
616 r
= sd_bus_message_close_container(m
);
618 return bus_log_create_error(r
);
620 r
= sd_bus_message_close_container(m
);
622 return bus_log_create_error(r
);
625 } else if (streq(field
, "CPUSchedulingPolicy")) {
628 n
= sched_policy_from_string(eq
);
630 return log_error_errno(r
, "Failed to parse CPUSchedulingPolicy: %s", eq
);
632 r
= sd_bus_message_append(m
, "v", "i", (int32_t) n
);
634 } else if (streq(field
, "CPUSchedulingPriority")) {
637 r
= safe_atoi(eq
, &n
);
639 return log_error_errno(r
, "Failed to parse CPUSchedulingPriority: %s", eq
);
640 if (!sched_priority_is_valid(n
))
641 return log_error_errno(r
, "Invalid CPUSchedulingPriority: %s", eq
);
643 r
= sd_bus_message_append(m
, "v", "i", (int32_t) n
);
645 } else if (streq(field
, "CPUAffinity")) {
646 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
649 ncpus
= parse_cpu_set(eq
, &cpuset
);
651 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
653 r
= sd_bus_message_open_container(m
, 'v', "ay");
655 return bus_log_create_error(r
);
658 sd_bus_message_append_array(m
, 'y', cpuset
, CPU_ALLOC_SIZE(ncpus
));
660 r
= sd_bus_message_close_container(m
);
662 } else if (streq(field
, "Nice")) {
665 r
= parse_nice(eq
, &n
);
667 return log_error_errno(r
, "Failed to parse nice value: %s", eq
);
669 r
= sd_bus_message_append(m
, "v", "i", (int32_t) n
);
673 } else if (streq(field
, "SystemCallFilter")) {
675 _cleanup_strv_free_
char **l
= NULL
;
685 if (whitelist
!= 0) {
686 r
= strv_extend(&l
, "@default");
692 _cleanup_free_
char *word
= NULL
;
694 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
696 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
700 r
= strv_extend(&l
, word
);
705 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
707 return bus_log_create_error(r
);
709 r
= sd_bus_message_open_container(m
, 'r', "bas");
711 return bus_log_create_error(r
);
713 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
715 return bus_log_create_error(r
);
717 r
= sd_bus_message_append_strv(m
, l
);
719 return bus_log_create_error(r
);
721 r
= sd_bus_message_close_container(m
);
723 return bus_log_create_error(r
);
725 r
= sd_bus_message_close_container(m
);
727 return bus_log_create_error(r
);
729 } else if (streq(field
, "SystemCallArchitectures")) {
732 r
= sd_bus_message_open_container(m
, 'v', "as");
734 return bus_log_create_error(r
);
736 r
= sd_bus_message_open_container(m
, 'a', "s");
738 return bus_log_create_error(r
);
741 _cleanup_free_
char *word
= NULL
;
743 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
745 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
749 r
= sd_bus_message_append_basic(m
, 's', word
);
751 return bus_log_create_error(r
);
754 r
= sd_bus_message_close_container(m
);
756 return bus_log_create_error(r
);
758 r
= sd_bus_message_close_container(m
);
760 } else if (streq(field
, "SystemCallErrorNumber")) {
765 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
767 r
= sd_bus_message_append(m
, "v", "i", (int32_t) n
);
769 } else if (streq(field
, "RestrictAddressFamilies")) {
771 _cleanup_strv_free_
char **l
= NULL
;
781 _cleanup_free_
char *word
= NULL
;
783 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
785 return log_error_errno(r
, "Failed to parse %s value: %s", field
, eq
);
789 r
= strv_extend(&l
, word
);
794 r
= sd_bus_message_open_container(m
, 'v', "(bas)");
796 return bus_log_create_error(r
);
798 r
= sd_bus_message_open_container(m
, 'r', "bas");
800 return bus_log_create_error(r
);
802 r
= sd_bus_message_append_basic(m
, 'b', &whitelist
);
804 return bus_log_create_error(r
);
806 r
= sd_bus_message_append_strv(m
, l
);
808 return bus_log_create_error(r
);
810 r
= sd_bus_message_close_container(m
);
812 return bus_log_create_error(r
);
814 r
= sd_bus_message_close_container(m
);
816 return bus_log_create_error(r
);
818 } else if (streq(field
, "FileDescriptorStoreMax")) {
821 r
= safe_atou(eq
, &u
);
823 return log_error_errno(r
, "Failed to parse file descriptor store limit: %s", eq
);
825 r
= sd_bus_message_append(m
, "v", "u", (uint32_t) u
);
827 } else if (streq(field
, "IOSchedulingClass")) {
830 c
= ioprio_class_from_string(eq
);
832 return log_error_errno(r
, "Failed to parse IO scheduling class: %s", eq
);
834 r
= sd_bus_message_append(m
, "v", "i", (int32_t) c
);
836 } else if (streq(field
, "IOSchedulingPriority")) {
839 r
= ioprio_parse_priority(eq
, &q
);
841 return log_error_errno(r
, "Failed to parse IO scheduling priority: %s", eq
);
843 r
= sd_bus_message_append(m
, "v", "i", (int32_t) q
);
845 } else if (STR_IN_SET(field
, "Environment", "UnsetEnvironment", "PassEnvironment")) {
848 r
= sd_bus_message_open_container(m
, 'v', "as");
850 return bus_log_create_error(r
);
852 r
= sd_bus_message_open_container(m
, 'a', "s");
854 return bus_log_create_error(r
);
857 _cleanup_free_
char *word
= NULL
;
859 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
861 log_error("Failed to parse Environment value %s", eq
);
867 if (streq(field
, "Environment")) {
868 if (!env_assignment_is_valid(word
)) {
869 log_error("Invalid environment assignment: %s", word
);
872 } else if (streq(field
, "UnsetEnvironment")) {
873 if (!env_assignment_is_valid(word
) && !env_name_is_valid(word
)) {
874 log_error("Invalid environment name or assignment: %s", word
);
877 } else { /* PassEnvironment */
878 if (!env_name_is_valid(word
)) {
879 log_error("Invalid environment variable name: %s", word
);
884 r
= sd_bus_message_append_basic(m
, 's', word
);
886 return bus_log_create_error(r
);
889 r
= sd_bus_message_close_container(m
);
891 return bus_log_create_error(r
);
893 r
= sd_bus_message_close_container(m
);
895 } else if (streq(field
, "KillSignal")) {
898 sig
= signal_from_string_try_harder(eq
);
900 log_error("Failed to parse %s value %s.", field
, eq
);
904 r
= sd_bus_message_append(m
, "v", "i", sig
);
906 } else if (streq(field
, "TimerSlackNSec")) {
909 r
= parse_nsec(eq
, &n
);
911 log_error("Failed to parse %s value %s", field
, eq
);
915 r
= sd_bus_message_append(m
, "v", "t", n
);
916 } else if (streq(field
, "OOMScoreAdjust")) {
919 r
= safe_atoi(eq
, &oa
);
921 log_error("Failed to parse %s value %s", field
, eq
);
925 if (!oom_score_adjust_is_valid(oa
)) {
926 log_error("OOM score adjust value out of range");
930 r
= sd_bus_message_append(m
, "v", "i", oa
);
931 } else if (STR_IN_SET(field
, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
932 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) {
935 r
= sd_bus_message_open_container(m
, 'v', "as");
937 return bus_log_create_error(r
);
939 r
= sd_bus_message_open_container(m
, 'a', "s");
941 return bus_log_create_error(r
);
944 _cleanup_free_
char *word
= NULL
;
947 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
949 log_error("Failed to parse %s value %s", field
, eq
);
955 if (!utf8_is_valid(word
)) {
956 log_error("Failed to parse %s value %s", field
, eq
);
960 offset
= word
[0] == '-';
961 offset
+= word
[offset
] == '+';
963 if (!path_is_absolute(word
+ offset
)) {
964 log_error("Failed to parse %s value %s", field
, eq
);
968 path_kill_slashes(word
+ offset
);
970 r
= sd_bus_message_append_basic(m
, 's', word
);
972 return bus_log_create_error(r
);
975 r
= sd_bus_message_close_container(m
);
977 return bus_log_create_error(r
);
979 r
= sd_bus_message_close_container(m
);
981 } else if (streq(field
, "SupplementaryGroups")) {
984 r
= sd_bus_message_open_container(m
, 'v', "as");
986 return bus_log_create_error(r
);
988 r
= sd_bus_message_open_container(m
, 'a', "s");
990 return bus_log_create_error(r
);
993 _cleanup_free_
char *word
= NULL
;
995 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
997 log_error("Failed to parse %s value %s", field
, eq
);
1003 if (!valid_user_group_name_or_id(word
)) {
1004 log_error("Failed to parse %s value %s", field
, eq
);
1008 r
= sd_bus_message_append_basic(m
, 's', word
);
1010 return bus_log_create_error(r
);
1013 r
= sd_bus_message_close_container(m
);
1015 return bus_log_create_error(r
);
1017 r
= sd_bus_message_close_container(m
);
1019 } else if (STR_IN_SET(field
, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask")) {
1022 r
= parse_mode(eq
, &mode
);
1024 return log_error_errno(r
, "Failed to parse %s value %s", field
, eq
);
1026 r
= sd_bus_message_append(m
, "v", "u", mode
);
1028 } else if (STR_IN_SET(field
, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) {
1031 r
= sd_bus_message_open_container(m
, 'v', "as");
1033 return bus_log_create_error(r
);
1035 r
= sd_bus_message_open_container(m
, 'a', "s");
1037 return bus_log_create_error(r
);
1040 _cleanup_free_
char *word
= NULL
;
1042 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1046 return log_error_errno(r
, "Failed to parse %s value %s", field
, eq
);
1050 r
= sd_bus_message_append_basic(m
, 's', word
);
1052 return bus_log_create_error(r
);
1055 r
= sd_bus_message_close_container(m
);
1057 return bus_log_create_error(r
);
1059 r
= sd_bus_message_close_container(m
);
1061 } else if (streq(field
, "RestrictNamespaces")) {
1062 bool invert
= false;
1063 unsigned long flags
= 0;
1070 r
= parse_boolean(eq
);
1074 flags
= NAMESPACE_FLAGS_ALL
;
1076 r
= namespace_flag_from_string_many(eq
, &flags
);
1078 return log_error_errno(r
, "Failed to parse %s value %s.", field
, eq
);
1082 flags
= (~flags
) & NAMESPACE_FLAGS_ALL
;
1084 r
= sd_bus_message_append(m
, "v", "t", (uint64_t) flags
);
1085 } else if ((dep
= unit_dependency_from_string(field
)) >= 0)
1086 r
= sd_bus_message_append(m
, "v", "as", 1, eq
);
1087 else if (streq(field
, "MountFlags")) {
1090 r
= mount_propagation_flags_from_string(eq
, &f
);
1092 return log_error_errno(r
, "Failed to parse mount propagation flags: %s", eq
);
1094 r
= sd_bus_message_append(m
, "v", "t", (uint64_t) f
);
1095 } else if (STR_IN_SET(field
, "BindPaths", "BindReadOnlyPaths")) {
1098 r
= sd_bus_message_open_container(m
, 'v', "a(ssbt)");
1102 r
= sd_bus_message_open_container(m
, 'a', "(ssbt)");
1107 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
1108 char *s
= NULL
, *d
= NULL
;
1109 bool ignore_enoent
= false;
1110 uint64_t flags
= MS_REC
;
1112 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1114 return log_error_errno(r
, "Failed to parse argument: %m");
1120 ignore_enoent
= true;
1124 if (p
&& p
[-1] == ':') {
1125 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
1127 return log_error_errno(r
, "Failed to parse argument: %m");
1129 log_error("Missing argument after ':': %s", eq
);
1135 if (p
&& p
[-1] == ':') {
1136 _cleanup_free_
char *options
= NULL
;
1138 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
1140 return log_error_errno(r
, "Failed to parse argument: %m");
1142 if (isempty(options
) || streq(options
, "rbind"))
1144 else if (streq(options
, "norbind"))
1147 log_error("Unknown options: %s", eq
);
1155 r
= sd_bus_message_append(m
, "(ssbt)", s
, d
, ignore_enoent
, flags
);
1160 r
= sd_bus_message_close_container(m
);
1164 r
= sd_bus_message_close_container(m
);
1166 log_error("Unknown assignment %s.", assignment
);
1172 return bus_log_create_error(r
);
1174 r
= sd_bus_message_close_container(m
);
1176 return bus_log_create_error(r
);
1181 int bus_append_unit_property_assignment_many(sd_bus_message
*m
, char **l
) {
1187 STRV_FOREACH(i
, l
) {
1188 r
= bus_append_unit_property_assignment(m
, *i
);
1196 typedef struct BusWaitForJobs
{
1203 sd_bus_slot
*slot_job_removed
;
1204 sd_bus_slot
*slot_disconnected
;
1207 static int match_disconnected(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1210 log_error("Warning! D-Bus connection terminated.");
1211 sd_bus_close(sd_bus_message_get_bus(m
));
1216 static int match_job_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1217 const char *path
, *unit
, *result
;
1218 BusWaitForJobs
*d
= userdata
;
1226 r
= sd_bus_message_read(m
, "uoss", &id
, &path
, &unit
, &result
);
1228 bus_log_parse_error(r
);
1232 found
= set_remove(d
->jobs
, (char*) path
);
1238 if (!isempty(result
))
1239 d
->result
= strdup(result
);
1242 d
->name
= strdup(unit
);
1247 void bus_wait_for_jobs_free(BusWaitForJobs
*d
) {
1251 set_free_free(d
->jobs
);
1253 sd_bus_slot_unref(d
->slot_disconnected
);
1254 sd_bus_slot_unref(d
->slot_job_removed
);
1256 sd_bus_unref(d
->bus
);
1264 int bus_wait_for_jobs_new(sd_bus
*bus
, BusWaitForJobs
**ret
) {
1265 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*d
= NULL
;
1271 d
= new0(BusWaitForJobs
, 1);
1275 d
->bus
= sd_bus_ref(bus
);
1277 /* When we are a bus client we match by sender. Direct
1278 * connections OTOH have no initialized sender field, and
1279 * hence we ignore the sender then */
1280 r
= sd_bus_add_match(
1282 &d
->slot_job_removed
,
1285 "sender='org.freedesktop.systemd1',"
1286 "interface='org.freedesktop.systemd1.Manager',"
1287 "member='JobRemoved',"
1288 "path='/org/freedesktop/systemd1'" :
1290 "interface='org.freedesktop.systemd1.Manager',"
1291 "member='JobRemoved',"
1292 "path='/org/freedesktop/systemd1'",
1293 match_job_removed
, d
);
1297 r
= sd_bus_add_match(
1299 &d
->slot_disconnected
,
1301 "sender='org.freedesktop.DBus.Local',"
1302 "interface='org.freedesktop.DBus.Local',"
1303 "member='Disconnected'",
1304 match_disconnected
, d
);
1314 static int bus_process_wait(sd_bus
*bus
) {
1318 r
= sd_bus_process(bus
, NULL
);
1324 r
= sd_bus_wait(bus
, (uint64_t) -1);
1330 static int bus_job_get_service_result(BusWaitForJobs
*d
, char **result
) {
1331 _cleanup_free_
char *dbus_path
= NULL
;
1337 if (!endswith(d
->name
, ".service"))
1340 dbus_path
= unit_dbus_path_from_name(d
->name
);
1344 return sd_bus_get_property_string(d
->bus
,
1345 "org.freedesktop.systemd1",
1347 "org.freedesktop.systemd1.Service",
1353 static const struct {
1354 const char *result
, *explanation
;
1355 } explanations
[] = {
1356 { "resources", "of unavailable resources or another system error" },
1357 { "protocol", "the service did not take the steps required by its unit configuration" },
1358 { "timeout", "a timeout was exceeded" },
1359 { "exit-code", "the control process exited with error code" },
1360 { "signal", "a fatal signal was delivered to the control process" },
1361 { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
1362 { "watchdog", "the service failed to send watchdog ping" },
1363 { "start-limit", "start of the service was attempted too often" }
1366 static void log_job_error_with_service_result(const char* service
, const char *result
, const char* const* extra_args
) {
1367 _cleanup_free_
char *service_shell_quoted
= NULL
;
1368 const char *systemctl
= "systemctl", *journalctl
= "journalctl";
1372 service_shell_quoted
= shell_maybe_quote(service
, ESCAPE_BACKSLASH
);
1374 if (!strv_isempty((char**) extra_args
)) {
1375 _cleanup_free_
char *t
;
1377 t
= strv_join((char**) extra_args
, " ");
1378 systemctl
= strjoina("systemctl ", t
? : "<args>");
1379 journalctl
= strjoina("journalctl ", t
? : "<args>");
1382 if (!isempty(result
)) {
1385 for (i
= 0; i
< ELEMENTSOF(explanations
); ++i
)
1386 if (streq(result
, explanations
[i
].result
))
1389 if (i
< ELEMENTSOF(explanations
)) {
1390 log_error("Job for %s failed because %s.\n"
1391 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1393 explanations
[i
].explanation
,
1395 service_shell_quoted
?: "<service>",
1401 log_error("Job for %s failed.\n"
1402 "See \"%s status %s\" and \"%s -xe\" for details.\n",
1405 service_shell_quoted
?: "<service>",
1409 /* For some results maybe additional explanation is required */
1410 if (streq_ptr(result
, "start-limit"))
1411 log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
1412 "followed by \"%1$s start %2$s\" again.",
1414 service_shell_quoted
?: "<service>");
1417 static int check_wait_response(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1423 if (streq(d
->result
, "canceled"))
1424 log_error("Job for %s canceled.", strna(d
->name
));
1425 else if (streq(d
->result
, "timeout"))
1426 log_error("Job for %s timed out.", strna(d
->name
));
1427 else if (streq(d
->result
, "dependency"))
1428 log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d
->name
));
1429 else if (streq(d
->result
, "invalid"))
1430 log_error("%s is not active, cannot reload.", strna(d
->name
));
1431 else if (streq(d
->result
, "assert"))
1432 log_error("Assertion failed on job for %s.", strna(d
->name
));
1433 else if (streq(d
->result
, "unsupported"))
1434 log_error("Operation on or unit type of %s not supported on this system.", strna(d
->name
));
1435 else if (streq(d
->result
, "collected"))
1436 log_error("Queued job for %s was garbage collected.", strna(d
->name
));
1437 else if (!STR_IN_SET(d
->result
, "done", "skipped")) {
1439 _cleanup_free_
char *result
= NULL
;
1442 q
= bus_job_get_service_result(d
, &result
);
1444 log_debug_errno(q
, "Failed to get Result property of unit %s: %m", d
->name
);
1446 log_job_error_with_service_result(d
->name
, result
, extra_args
);
1448 log_error("Job failed. See \"journalctl -xe\" for details.");
1452 if (STR_IN_SET(d
->result
, "canceled", "collected"))
1454 else if (streq(d
->result
, "timeout"))
1456 else if (streq(d
->result
, "dependency"))
1458 else if (streq(d
->result
, "invalid"))
1460 else if (streq(d
->result
, "assert"))
1462 else if (streq(d
->result
, "unsupported"))
1464 else if (!STR_IN_SET(d
->result
, "done", "skipped"))
1470 int bus_wait_for_jobs(BusWaitForJobs
*d
, bool quiet
, const char* const* extra_args
) {
1475 while (!set_isempty(d
->jobs
)) {
1478 q
= bus_process_wait(d
->bus
);
1480 return log_error_errno(q
, "Failed to wait for response: %m");
1483 q
= check_wait_response(d
, quiet
, extra_args
);
1484 /* Return the first error as it is most likely to be
1486 if (q
< 0 && r
== 0)
1489 log_debug_errno(q
, "Got result %s/%m for job %s", strna(d
->result
), strna(d
->name
));
1492 d
->name
= mfree(d
->name
);
1493 d
->result
= mfree(d
->result
);
1499 int bus_wait_for_jobs_add(BusWaitForJobs
*d
, const char *path
) {
1504 r
= set_ensure_allocated(&d
->jobs
, &string_hash_ops
);
1508 return set_put_strdup(d
->jobs
, path
);
1511 int bus_wait_for_jobs_one(BusWaitForJobs
*d
, const char *path
, bool quiet
) {
1514 r
= bus_wait_for_jobs_add(d
, path
);
1518 return bus_wait_for_jobs(d
, quiet
, NULL
);
1521 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message
*m
, bool quiet
, UnitFileChange
**changes
, unsigned *n_changes
) {
1522 const char *type
, *path
, *source
;
1525 /* changes is dereferenced when calling unit_file_dump_changes() later,
1526 * so we have to make sure this is not NULL. */
1530 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sss)");
1532 return bus_log_parse_error(r
);
1534 while ((r
= sd_bus_message_read(m
, "(sss)", &type
, &path
, &source
)) > 0) {
1535 /* We expect only "success" changes to be sent over the bus.
1536 Hence, reject anything negative. */
1537 UnitFileChangeType ch
= unit_file_change_type_from_string(type
);
1540 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type
, path
);
1544 r
= unit_file_changes_add(changes
, n_changes
, ch
, path
, source
);
1549 return bus_log_parse_error(r
);
1551 r
= sd_bus_message_exit_container(m
);
1553 return bus_log_parse_error(r
);
1555 unit_file_dump_changes(0, NULL
, *changes
, *n_changes
, quiet
);
1561 bool is_const
; /* If false, cgroup_path should be free()'d */
1563 Hashmap
*pids
; /* PID → process name */
1566 struct CGroupInfo
*parent
;
1567 LIST_FIELDS(struct CGroupInfo
, siblings
);
1568 LIST_HEAD(struct CGroupInfo
, children
);
1572 static bool IS_ROOT(const char *p
) {
1573 return isempty(p
) || streq(p
, "/");
1576 static int add_cgroup(Hashmap
*cgroups
, const char *path
, bool is_const
, struct CGroupInfo
**ret
) {
1577 struct CGroupInfo
*parent
= NULL
, *cg
;
1586 cg
= hashmap_get(cgroups
, path
);
1592 if (!IS_ROOT(path
)) {
1595 e
= strrchr(path
, '/');
1599 pp
= strndupa(path
, e
- path
);
1603 r
= add_cgroup(cgroups
, pp
, false, &parent
);
1608 cg
= new0(struct CGroupInfo
, 1);
1613 cg
->cgroup_path
= (char*) path
;
1615 cg
->cgroup_path
= strdup(path
);
1616 if (!cg
->cgroup_path
) {
1622 cg
->is_const
= is_const
;
1623 cg
->parent
= parent
;
1625 r
= hashmap_put(cgroups
, cg
->cgroup_path
, cg
);
1628 free(cg
->cgroup_path
);
1634 LIST_PREPEND(siblings
, parent
->children
, cg
);
1635 parent
->n_children
++;
1642 static int add_process(
1648 struct CGroupInfo
*cg
;
1655 r
= add_cgroup(cgroups
, path
, true, &cg
);
1659 r
= hashmap_ensure_allocated(&cg
->pids
, &trivial_hash_ops
);
1663 return hashmap_put(cg
->pids
, PID_TO_PTR(pid
), (void*) name
);
1666 static void remove_cgroup(Hashmap
*cgroups
, struct CGroupInfo
*cg
) {
1670 while (cg
->children
)
1671 remove_cgroup(cgroups
, cg
->children
);
1673 hashmap_remove(cgroups
, cg
->cgroup_path
);
1676 free(cg
->cgroup_path
);
1678 hashmap_free(cg
->pids
);
1681 LIST_REMOVE(siblings
, cg
->parent
->children
, cg
);
1686 static int cgroup_info_compare_func(const void *a
, const void *b
) {
1687 const struct CGroupInfo
*x
= *(const struct CGroupInfo
* const*) a
, *y
= *(const struct CGroupInfo
* const*) b
;
1692 return strcmp(x
->cgroup_path
, y
->cgroup_path
);
1695 static int dump_processes(
1697 const char *cgroup_path
,
1700 OutputFlags flags
) {
1702 struct CGroupInfo
*cg
;
1707 if (IS_ROOT(cgroup_path
))
1710 cg
= hashmap_get(cgroups
, cgroup_path
);
1714 if (!hashmap_isempty(cg
->pids
)) {
1722 /* Order processes by their PID */
1723 pids
= newa(pid_t
, hashmap_size(cg
->pids
));
1725 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
)
1726 pids
[n
++] = PTR_TO_PID(pidp
);
1728 assert(n
== hashmap_size(cg
->pids
));
1729 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
1731 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
1733 for (i
= 0; i
< n
; i
++) {
1734 _cleanup_free_
char *e
= NULL
;
1735 const char *special
;
1738 name
= hashmap_get(cg
->pids
, PID_TO_PTR(pids
[i
]));
1741 if (n_columns
!= 0) {
1744 k
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
1746 e
= ellipsize(name
, k
, 100);
1751 more
= i
+1 < n
|| cg
->children
;
1752 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
1754 fprintf(stdout
, "%s%s%*"PID_PRI
" %s\n",
1763 struct CGroupInfo
**children
, *child
;
1766 /* Order subcgroups by their name */
1767 children
= newa(struct CGroupInfo
*, cg
->n_children
);
1768 LIST_FOREACH(siblings
, child
, cg
->children
)
1769 children
[n
++] = child
;
1770 assert(n
== cg
->n_children
);
1771 qsort_safe(children
, n
, sizeof(struct CGroupInfo
*), cgroup_info_compare_func
);
1774 n_columns
= MAX(LESS_BY(n_columns
, 2U), 20U);
1776 for (i
= 0; i
< n
; i
++) {
1777 _cleanup_free_
char *pp
= NULL
;
1778 const char *name
, *special
;
1781 child
= children
[i
];
1783 name
= strrchr(child
->cgroup_path
, '/');
1789 special
= special_glyph(more
? TREE_BRANCH
: TREE_RIGHT
);
1791 fputs(prefix
, stdout
);
1792 fputs(special
, stdout
);
1793 fputs(name
, stdout
);
1794 fputc('\n', stdout
);
1796 special
= special_glyph(more
? TREE_VERTICAL
: TREE_SPACE
);
1798 pp
= strappend(prefix
, special
);
1802 r
= dump_processes(cgroups
, child
->cgroup_path
, pp
, n_columns
, flags
);
1812 static int dump_extra_processes(
1816 OutputFlags flags
) {
1818 _cleanup_free_ pid_t
*pids
= NULL
;
1819 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
1820 struct CGroupInfo
*cg
;
1821 size_t n_allocated
= 0, n
= 0, k
;
1825 /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
1826 * combined, sorted, linear list. */
1828 HASHMAP_FOREACH(cg
, cgroups
, i
) {
1836 if (hashmap_isempty(cg
->pids
))
1839 r
= hashmap_ensure_allocated(&names
, &trivial_hash_ops
);
1843 if (!GREEDY_REALLOC(pids
, n_allocated
, n
+ hashmap_size(cg
->pids
)))
1846 HASHMAP_FOREACH_KEY(name
, pidp
, cg
->pids
, j
) {
1847 pids
[n
++] = PTR_TO_PID(pidp
);
1849 r
= hashmap_put(names
, pidp
, (void*) name
);
1858 qsort_safe(pids
, n
, sizeof(pid_t
), pid_compare_func
);
1859 width
= DECIMAL_STR_WIDTH(pids
[n
-1]);
1861 for (k
= 0; k
< n
; k
++) {
1862 _cleanup_free_
char *e
= NULL
;
1865 name
= hashmap_get(names
, PID_TO_PTR(pids
[k
]));
1868 if (n_columns
!= 0) {
1871 z
= MAX(LESS_BY(n_columns
, 2U + width
+ 1U), 20U);
1873 e
= ellipsize(name
, z
, 100);
1878 fprintf(stdout
, "%s%s %*" PID_PRI
" %s\n",
1880 special_glyph(TRIANGULAR_BULLET
),
1888 int unit_show_processes(
1891 const char *cgroup_path
,
1895 sd_bus_error
*error
) {
1897 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1898 Hashmap
*cgroups
= NULL
;
1899 struct CGroupInfo
*cg
;
1905 if (flags
& OUTPUT_FULL_WIDTH
)
1907 else if (n_columns
<= 0)
1908 n_columns
= columns();
1910 prefix
= strempty(prefix
);
1912 r
= sd_bus_call_method(
1914 "org.freedesktop.systemd1",
1915 "/org/freedesktop/systemd1",
1916 "org.freedesktop.systemd1.Manager",
1925 cgroups
= hashmap_new(&string_hash_ops
);
1929 r
= sd_bus_message_enter_container(reply
, 'a', "(sus)");
1934 const char *path
= NULL
, *name
= NULL
;
1937 r
= sd_bus_message_read(reply
, "(sus)", &path
, &pid
, &name
);
1943 r
= add_process(cgroups
, path
, pid
, name
);
1948 r
= sd_bus_message_exit_container(reply
);
1952 r
= dump_processes(cgroups
, cgroup_path
, prefix
, n_columns
, flags
);
1956 r
= dump_extra_processes(cgroups
, prefix
, n_columns
, flags
);
1959 while ((cg
= hashmap_first(cgroups
)))
1960 remove_cgroup(cgroups
, cg
);
1962 hashmap_free(cgroups
);