1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 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/>.
27 #include "alloc-util.h"
28 #include "btrfs-util.h"
29 #include "bus-common-errors.h"
31 #include "cgroup-util.h"
34 #include "format-util.h"
35 #include "hostname-util.h"
36 #include "image-dbus.h"
38 #include "machine-dbus.h"
39 #include "machine-image.h"
40 #include "machine-pool.h"
42 #include "path-util.h"
43 #include "process-util.h"
44 #include "stdio-util.h"
46 #include "unit-name.h"
47 #include "user-util.h"
49 static int property_get_pool_path(
52 const char *interface
,
54 sd_bus_message
*reply
,
56 sd_bus_error
*error
) {
61 return sd_bus_message_append(reply
, "s", "/var/lib/machines");
64 static int property_get_pool_usage(
67 const char *interface
,
69 sd_bus_message
*reply
,
71 sd_bus_error
*error
) {
73 _cleanup_close_
int fd
= -1;
74 uint64_t usage
= (uint64_t) -1;
80 /* We try to read the quota info from /var/lib/machines, as
81 * well as the usage of the loopback file
82 * /var/lib/machines.raw, and pick the larger value. */
84 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
88 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
92 if (stat("/var/lib/machines.raw", &st
) >= 0) {
93 if (usage
== (uint64_t) -1 || st
.st_blocks
* 512ULL > usage
)
94 usage
= st
.st_blocks
* 512ULL;
97 return sd_bus_message_append(reply
, "t", usage
);
100 static int property_get_pool_limit(
103 const char *interface
,
104 const char *property
,
105 sd_bus_message
*reply
,
107 sd_bus_error
*error
) {
109 _cleanup_close_
int fd
= -1;
110 uint64_t size
= (uint64_t) -1;
116 /* We try to read the quota limit from /var/lib/machines, as
117 * well as the size of the loopback file
118 * /var/lib/machines.raw, and pick the smaller value. */
120 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
124 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
125 size
= q
.referenced_max
;
128 if (stat("/var/lib/machines.raw", &st
) >= 0) {
129 if (size
== (uint64_t) -1 || (uint64_t) st
.st_size
< size
)
133 return sd_bus_message_append(reply
, "t", size
);
136 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
137 _cleanup_free_
char *p
= NULL
;
138 Manager
*m
= userdata
;
146 r
= sd_bus_message_read(message
, "s", &name
);
150 machine
= hashmap_get(m
->machines
, name
);
152 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
154 p
= machine_bus_path(machine
);
158 return sd_bus_reply_method_return(message
, "o", p
);
161 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
162 _cleanup_free_
char *p
= NULL
;
163 Manager
*m
= userdata
;
170 r
= sd_bus_message_read(message
, "s", &name
);
174 r
= image_find(name
, NULL
);
176 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
180 p
= image_bus_path(name
);
184 return sd_bus_reply_method_return(message
, "o", p
);
187 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
188 _cleanup_free_
char *p
= NULL
;
189 Manager
*m
= userdata
;
190 Machine
*machine
= NULL
;
197 assert_cc(sizeof(pid_t
) == sizeof(uint32_t));
199 r
= sd_bus_message_read(message
, "u", &pid
);
207 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
209 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
213 r
= sd_bus_creds_get_pid(creds
, &pid
);
218 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
222 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
224 p
= machine_bus_path(machine
);
228 return sd_bus_reply_method_return(message
, "o", p
);
231 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
232 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
233 Manager
*m
= userdata
;
241 r
= sd_bus_message_new_method_return(message
, &reply
);
243 return sd_bus_error_set_errno(error
, r
);
245 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
247 return sd_bus_error_set_errno(error
, r
);
249 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
250 _cleanup_free_
char *p
= NULL
;
252 p
= machine_bus_path(machine
);
256 r
= sd_bus_message_append(reply
, "(ssso)",
258 strempty(machine_class_to_string(machine
->class)),
262 return sd_bus_error_set_errno(error
, r
);
265 r
= sd_bus_message_close_container(reply
);
267 return sd_bus_error_set_errno(error
, r
);
269 return sd_bus_send(NULL
, reply
, NULL
);
272 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
273 const char *name
, *service
, *class, *root_directory
;
274 const int32_t *netif
= NULL
;
280 size_t n
, n_netif
= 0;
287 r
= sd_bus_message_read(message
, "s", &name
);
290 if (!machine_name_is_valid(name
))
291 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
293 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
301 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
303 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
310 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
314 n_netif
/= sizeof(int32_t);
316 for (i
= 0; i
< n_netif
; i
++) {
318 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
323 c
= _MACHINE_CLASS_INVALID
;
325 c
= machine_class_from_string(class);
327 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
331 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
333 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
334 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
337 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
339 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
343 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
345 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
350 if (hashmap_get(manager
->machines
, name
))
351 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
353 r
= manager_add_machine(manager
, name
, &m
);
361 if (!isempty(service
)) {
362 m
->service
= strdup(service
);
369 if (!isempty(root_directory
)) {
370 m
->root_directory
= strdup(root_directory
);
371 if (!m
->root_directory
) {
378 assert_cc(sizeof(int32_t) == sizeof(int));
379 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
385 m
->n_netif
= n_netif
;
393 machine_add_to_gc_queue(m
);
397 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
398 Manager
*manager
= userdata
;
405 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
409 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
413 r
= machine_start(m
, message
, error
);
417 m
->create_message
= sd_bus_message_ref(message
);
421 machine_add_to_gc_queue(m
);
425 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
426 return method_create_machine_internal(message
, true, userdata
, error
);
429 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
430 return method_create_machine_internal(message
, false, userdata
, error
);
433 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
434 Manager
*manager
= userdata
;
435 _cleanup_free_
char *p
= NULL
;
442 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
446 r
= cg_pid_get_unit(m
->leader
, &m
->unit
);
448 r
= sd_bus_error_set_errnof(error
, r
,
449 "Failed to determine unit of process "PID_FMT
" : %m",
454 r
= machine_start(m
, NULL
, error
);
458 p
= machine_bus_path(m
);
464 return sd_bus_reply_method_return(message
, "o", p
);
467 machine_add_to_gc_queue(m
);
471 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
472 return method_register_machine_internal(message
, true, userdata
, error
);
475 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
476 return method_register_machine_internal(message
, false, userdata
, error
);
479 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
480 Manager
*m
= userdata
;
488 r
= sd_bus_message_read(message
, "s", &name
);
490 return sd_bus_error_set_errno(error
, r
);
492 machine
= hashmap_get(m
->machines
, name
);
494 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
496 return bus_machine_method_terminate(message
, machine
, error
);
499 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
500 Manager
*m
= userdata
;
508 r
= sd_bus_message_read(message
, "s", &name
);
510 return sd_bus_error_set_errno(error
, r
);
512 machine
= hashmap_get(m
->machines
, name
);
514 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
516 return bus_machine_method_kill(message
, machine
, error
);
519 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
520 Manager
*m
= userdata
;
528 r
= sd_bus_message_read(message
, "s", &name
);
530 return sd_bus_error_set_errno(error
, r
);
532 machine
= hashmap_get(m
->machines
, name
);
534 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
536 return bus_machine_method_get_addresses(message
, machine
, error
);
539 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
540 Manager
*m
= userdata
;
548 r
= sd_bus_message_read(message
, "s", &name
);
550 return sd_bus_error_set_errno(error
, r
);
552 machine
= hashmap_get(m
->machines
, name
);
554 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
556 return bus_machine_method_get_os_release(message
, machine
, error
);
559 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
560 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
561 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
562 Manager
*m
= userdata
;
570 images
= hashmap_new(&string_hash_ops
);
574 r
= image_discover(images
);
578 r
= sd_bus_message_new_method_return(message
, &reply
);
582 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
586 HASHMAP_FOREACH(image
, images
, i
) {
587 _cleanup_free_
char *p
= NULL
;
589 p
= image_bus_path(image
->name
);
593 r
= sd_bus_message_append(reply
, "(ssbttto)",
595 image_type_to_string(image
->type
),
605 r
= sd_bus_message_close_container(reply
);
609 return sd_bus_send(NULL
, reply
, NULL
);
612 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
613 Manager
*m
= userdata
;
621 r
= sd_bus_message_read(message
, "s", &name
);
623 return sd_bus_error_set_errno(error
, r
);
625 machine
= hashmap_get(m
->machines
, name
);
627 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
629 return bus_machine_method_open_pty(message
, machine
, error
);
632 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
633 Manager
*m
= userdata
;
641 r
= sd_bus_message_read(message
, "s", &name
);
645 machine
= hashmap_get(m
->machines
, name
);
647 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
649 return bus_machine_method_open_login(message
, machine
, error
);
652 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
653 Manager
*m
= userdata
;
662 r
= sd_bus_message_read(message
, "s", &name
);
666 machine
= hashmap_get(m
->machines
, name
);
668 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
670 return bus_machine_method_open_shell(message
, machine
, error
);
673 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
674 Manager
*m
= userdata
;
682 r
= sd_bus_message_read(message
, "s", &name
);
686 machine
= hashmap_get(m
->machines
, name
);
688 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
690 return bus_machine_method_bind_mount(message
, machine
, error
);
693 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
694 Manager
*m
= userdata
;
702 r
= sd_bus_message_read(message
, "s", &name
);
706 machine
= hashmap_get(m
->machines
, name
);
708 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
710 return bus_machine_method_copy(message
, machine
, error
);
713 static int method_open_machine_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
714 Manager
*m
= userdata
;
722 r
= sd_bus_message_read(message
, "s", &name
);
726 machine
= hashmap_get(m
->machines
, name
);
728 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
730 return bus_machine_method_open_root_directory(message
, machine
, error
);
733 static int method_get_machine_uid_shift(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
734 Manager
*m
= userdata
;
742 r
= sd_bus_message_read(message
, "s", &name
);
746 machine
= hashmap_get(m
->machines
, name
);
748 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
750 return bus_machine_method_get_uid_shift(message
, machine
, error
);
753 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
754 _cleanup_(image_unrefp
) Image
* i
= NULL
;
760 r
= sd_bus_message_read(message
, "s", &name
);
764 if (!image_name_is_valid(name
))
765 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
767 r
= image_find(name
, &i
);
771 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
773 i
->userdata
= userdata
;
774 return bus_image_method_remove(message
, i
, error
);
777 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
778 _cleanup_(image_unrefp
) Image
* i
= NULL
;
779 const char *old_name
;
784 r
= sd_bus_message_read(message
, "s", &old_name
);
788 if (!image_name_is_valid(old_name
))
789 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
791 r
= image_find(old_name
, &i
);
795 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
797 i
->userdata
= userdata
;
798 return bus_image_method_rename(message
, i
, error
);
801 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
802 _cleanup_(image_unrefp
) Image
*i
= NULL
;
803 const char *old_name
;
808 r
= sd_bus_message_read(message
, "s", &old_name
);
812 if (!image_name_is_valid(old_name
))
813 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
815 r
= image_find(old_name
, &i
);
819 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
821 i
->userdata
= userdata
;
822 return bus_image_method_clone(message
, i
, error
);
825 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
826 _cleanup_(image_unrefp
) Image
*i
= NULL
;
832 r
= sd_bus_message_read(message
, "s", &name
);
836 if (!image_name_is_valid(name
))
837 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
839 r
= image_find(name
, &i
);
843 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
845 i
->userdata
= userdata
;
846 return bus_image_method_mark_read_only(message
, i
, error
);
849 static int method_get_image_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
850 _cleanup_(image_unrefp
) Image
*i
= NULL
;
856 r
= sd_bus_message_read(message
, "s", &name
);
860 if (!image_name_is_valid(name
))
861 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
863 r
= image_find(name
, &i
);
867 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
869 i
->userdata
= userdata
;
870 return bus_image_method_get_os_release(message
, i
, error
);
873 static int clean_pool_done(Operation
*operation
, int ret
, sd_bus_error
*error
) {
874 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
875 _cleanup_fclose_
FILE *f
= NULL
;
881 assert(operation
->extra_fd
>= 0);
883 if (lseek(operation
->extra_fd
, 0, SEEK_SET
) == (off_t
) -1)
886 f
= fdopen(operation
->extra_fd
, "re");
890 operation
->extra_fd
= -1;
892 /* The resulting temporary file starts with a boolean value that indicates success or not. */
894 n
= fread(&success
, 1, sizeof(success
), f
);
895 if (n
!= sizeof(success
))
896 return ret
< 0 ? ret
: (errno
!= 0 ? -errno
: -EIO
);
899 _cleanup_free_
char *name
= NULL
;
901 /* The clean-up operation failed. In this case the resulting temporary file should contain a boolean
902 * set to false followed by the name of the failed image. Let's try to read this and use it for the
903 * error message. If we can't read it, don't mind, and return the naked error. */
905 if (success
) /* The resulting temporary file could not be updated, ignore it. */
908 r
= read_nul_string(f
, &name
);
909 if (r
< 0 || isempty(name
)) /* Same here... */
912 return sd_bus_error_set_errnof(error
, ret
, "Failed to remove image %s: %m", name
);
917 r
= sd_bus_message_new_method_return(operation
->message
, &reply
);
921 r
= sd_bus_message_open_container(reply
, 'a', "(st)");
925 /* On success the resulting temporary file will contain a list of image names that were removed followed by
926 * their size on disk. Let's read that and turn it into a bus message. */
928 _cleanup_free_
char *name
= NULL
;
931 r
= read_nul_string(f
, &name
);
934 if (isempty(name
)) /* reached the end */
938 n
= fread(&size
, 1, sizeof(size
), f
);
939 if (n
!= sizeof(size
))
940 return errno
!= 0 ? -errno
: -EIO
;
942 r
= sd_bus_message_append(reply
, "(st)", name
, size
);
947 r
= sd_bus_message_close_container(reply
);
951 return sd_bus_send(NULL
, reply
, NULL
);
954 static int method_clean_pool(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
960 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
961 _cleanup_close_
int result_fd
= -1;
962 Manager
*m
= userdata
;
963 Operation
*operation
;
970 if (m
->n_operations
>= OPERATIONS_MAX
)
971 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing operations.");
973 r
= sd_bus_message_read(message
, "s", &mm
);
977 if (streq(mm
, "all"))
979 else if (streq(mm
, "hidden"))
980 mode
= REMOVE_HIDDEN
;
982 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown mode '%s'.", mm
);
984 r
= bus_verify_polkit_async(
987 "org.freedesktop.machine1.manage-machines",
996 return 1; /* Will call us back */
998 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
999 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
1001 /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
1002 * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
1004 result_fd
= open_tmpfile_unlinkable(NULL
, O_RDWR
|O_CLOEXEC
);
1008 /* This might be a slow operation, run it asynchronously in a background process */
1011 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
1014 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
1015 bool success
= true;
1020 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1022 images
= hashmap_new(&string_hash_ops
);
1028 r
= image_discover(images
);
1032 l
= write(result_fd
, &success
, sizeof(success
));
1038 HASHMAP_FOREACH(image
, images
, i
) {
1040 /* We can't remove vendor images (i.e. those in /usr) */
1041 if (IMAGE_IS_VENDOR(image
))
1044 if (IMAGE_IS_HOST(image
))
1047 if (mode
== REMOVE_HIDDEN
&& !IMAGE_IS_HIDDEN(image
))
1050 r
= image_remove(image
);
1051 if (r
== -EBUSY
) /* keep images that are currently being used. */
1054 /* If the operation failed, let's override everything we wrote, and instead write there at which image we failed. */
1056 (void) ftruncate(result_fd
, 0);
1057 (void) lseek(result_fd
, 0, SEEK_SET
);
1058 (void) write(result_fd
, &success
, sizeof(success
));
1059 (void) write(result_fd
, image
->name
, strlen(image
->name
)+1);
1063 l
= write(result_fd
, image
->name
, strlen(image
->name
)+1);
1069 l
= write(result_fd
, &image
->usage_exclusive
, sizeof(image
->usage_exclusive
));
1076 result_fd
= safe_close(result_fd
);
1077 _exit(EXIT_SUCCESS
);
1080 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1081 _exit(EXIT_FAILURE
);
1084 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1086 /* The clean-up might take a while, hence install a watch on the child and return */
1088 r
= operation_new(m
, NULL
, child
, message
, errno_pipe_fd
[0], &operation
);
1090 (void) sigkill_wait(child
);
1094 operation
->extra_fd
= result_fd
;
1095 operation
->done
= clean_pool_done
;
1098 errno_pipe_fd
[0] = -1;
1103 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1104 Manager
*m
= userdata
;
1110 r
= sd_bus_message_read(message
, "t", &limit
);
1113 if (!FILE_SIZE_VALID_OR_INFINITY(limit
))
1114 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "New limit out of range");
1116 r
= bus_verify_polkit_async(
1119 "org.freedesktop.machine1.manage-machines",
1123 &m
->polkit_registry
,
1128 return 1; /* Will call us back */
1130 /* Set up the machine directory if necessary */
1131 r
= setup_machine_directory(limit
, error
);
1135 /* Resize the backing loopback device, if there is one, except if we asked to drop any limit */
1136 if (limit
!= (uint64_t) -1) {
1137 r
= btrfs_resize_loopback("/var/lib/machines", limit
, false);
1139 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
1140 if (r
< 0 && r
!= -ENODEV
) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
1141 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust loopback limit: %m");
1144 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit
);
1146 r
= btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit
);
1148 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
1150 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
1152 return sd_bus_reply_method_return(message
, NULL
);
1155 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1156 _cleanup_(image_unrefp
) Image
*i
= NULL
;
1162 r
= sd_bus_message_read(message
, "s", &name
);
1166 if (!image_name_is_valid(name
))
1167 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
1169 r
= image_find(name
, &i
);
1173 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
1175 i
->userdata
= userdata
;
1176 return bus_image_method_set_limit(message
, i
, error
);
1179 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1180 _cleanup_fclose_
FILE *f
= NULL
;
1181 Manager
*m
= userdata
;
1182 const char *name
, *p
;
1187 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
1191 if (!uid_is_valid(uid
))
1192 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1194 machine
= hashmap_get(m
->machines
, name
);
1196 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1198 if (machine
->class != MACHINE_CONTAINER
)
1199 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1201 p
= procfs_file_alloca(machine
->leader
, "uid_map");
1207 uid_t uid_base
, uid_shift
, uid_range
, converted
;
1211 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
1212 if (k
< 0 && feof(f
))
1215 if (ferror(f
) && errno
> 0)
1221 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
1224 converted
= uid
- uid_base
+ uid_shift
;
1225 if (!uid_is_valid(converted
))
1226 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1228 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1231 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
1234 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1235 Manager
*m
= userdata
;
1241 r
= sd_bus_message_read(message
, "u", &uid
);
1244 if (!uid_is_valid(uid
))
1245 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1247 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
1249 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1250 _cleanup_fclose_
FILE *f
= NULL
;
1251 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1253 if (machine
->class != MACHINE_CONTAINER
)
1256 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
1259 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1264 _cleanup_free_
char *o
= NULL
;
1265 uid_t uid_base
, uid_shift
, uid_range
, converted
;
1269 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
1270 if (k
< 0 && feof(f
))
1273 if (ferror(f
) && errno
> 0)
1279 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
1282 converted
= (uid
- uid_shift
+ uid_base
);
1283 if (!uid_is_valid(converted
))
1284 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1286 o
= machine_bus_path(machine
);
1290 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1294 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
1297 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1298 _cleanup_fclose_
FILE *f
= NULL
;
1299 Manager
*m
= groupdata
;
1300 const char *name
, *p
;
1305 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
1309 if (!gid_is_valid(gid
))
1310 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1312 machine
= hashmap_get(m
->machines
, name
);
1314 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1316 if (machine
->class != MACHINE_CONTAINER
)
1317 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1319 p
= procfs_file_alloca(machine
->leader
, "gid_map");
1325 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1329 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1330 if (k
< 0 && feof(f
))
1333 if (ferror(f
) && errno
> 0)
1339 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
1342 converted
= gid
- gid_base
+ gid_shift
;
1343 if (!gid_is_valid(converted
))
1344 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1346 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1349 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1352 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1353 Manager
*m
= groupdata
;
1359 r
= sd_bus_message_read(message
, "u", &gid
);
1362 if (!gid_is_valid(gid
))
1363 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1365 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1367 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1368 _cleanup_fclose_
FILE *f
= NULL
;
1369 char p
[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1371 if (machine
->class != MACHINE_CONTAINER
)
1374 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1377 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1382 _cleanup_free_
char *o
= NULL
;
1383 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1387 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1388 if (k
< 0 && feof(f
))
1391 if (ferror(f
) && errno
> 0)
1397 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1400 converted
= (gid
- gid_shift
+ gid_base
);
1401 if (!gid_is_valid(converted
))
1402 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1404 o
= machine_bus_path(machine
);
1408 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1412 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1415 const sd_bus_vtable manager_vtable
[] = {
1416 SD_BUS_VTABLE_START(0),
1417 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1418 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1419 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1420 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1421 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1422 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1423 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1424 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1425 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1426 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1427 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1428 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1429 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1430 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1431 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1432 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1433 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1434 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1435 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1436 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1437 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1438 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1439 SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory
, SD_BUS_VTABLE_UNPRIVILEGED
),
1440 SD_BUS_METHOD("GetMachineUIDShift", "s", "u", method_get_machine_uid_shift
, SD_BUS_VTABLE_UNPRIVILEGED
),
1441 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1442 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1443 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1444 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1445 SD_BUS_METHOD("GetImageOSRelease", "s", "a{ss}", method_get_image_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1446 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1447 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1448 SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool
, SD_BUS_VTABLE_UNPRIVILEGED
),
1449 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1450 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1451 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1452 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1453 SD_BUS_SIGNAL("MachineNew", "so", 0),
1454 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1458 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1459 const char *path
, *result
, *unit
;
1460 Manager
*m
= userdata
;
1468 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1470 bus_log_parse_error(r
);
1474 machine
= hashmap_get(m
->machine_units
, unit
);
1478 if (streq_ptr(path
, machine
->scope_job
)) {
1479 machine
->scope_job
= mfree(machine
->scope_job
);
1481 if (machine
->started
) {
1482 if (streq(result
, "done"))
1483 machine_send_create_reply(machine
, NULL
);
1485 _cleanup_(sd_bus_error_free
) sd_bus_error e
= SD_BUS_ERROR_NULL
;
1487 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1489 machine_send_create_reply(machine
, &e
);
1493 machine_save(machine
);
1496 machine_add_to_gc_queue(machine
);
1500 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1501 _cleanup_free_
char *unit
= NULL
;
1503 Manager
*m
= userdata
;
1510 path
= sd_bus_message_get_path(message
);
1514 r
= unit_name_from_dbus_path(path
, &unit
);
1515 if (r
== -EINVAL
) /* not for a unit */
1522 machine
= hashmap_get(m
->machine_units
, unit
);
1526 machine_add_to_gc_queue(machine
);
1530 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1531 const char *path
, *unit
;
1532 Manager
*m
= userdata
;
1539 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1541 bus_log_parse_error(r
);
1545 machine
= hashmap_get(m
->machine_units
, unit
);
1549 machine_add_to_gc_queue(machine
);
1553 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1554 Manager
*m
= userdata
;
1562 r
= sd_bus_message_read(message
, "b", &b
);
1564 bus_log_parse_error(r
);
1570 /* systemd finished reloading, let's recheck all our machines */
1571 log_debug("System manager has been reloaded, rechecking machines...");
1573 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1574 machine_add_to_gc_queue(machine
);
1579 int manager_start_scope(
1584 const char *description
,
1585 sd_bus_message
*more_properties
,
1586 sd_bus_error
*error
,
1589 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1596 r
= sd_bus_message_new_method_call(
1599 "org.freedesktop.systemd1",
1600 "/org/freedesktop/systemd1",
1601 "org.freedesktop.systemd1.Manager",
1602 "StartTransientUnit");
1606 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1610 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1614 if (!isempty(slice
)) {
1615 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1620 if (!isempty(description
)) {
1621 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1626 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, pid
);
1630 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
1634 r
= sd_bus_message_append(m
, "(sv)", "TasksMax", "t", UINT64_C(16384));
1636 return bus_log_create_error(r
);
1638 if (more_properties
) {
1639 r
= sd_bus_message_copy(m
, more_properties
, true);
1644 r
= sd_bus_message_close_container(m
);
1648 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1652 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1660 r
= sd_bus_message_read(reply
, "o", &j
);
1674 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1675 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1681 r
= sd_bus_call_method(
1683 "org.freedesktop.systemd1",
1684 "/org/freedesktop/systemd1",
1685 "org.freedesktop.systemd1.Manager",
1689 "ss", unit
, "fail");
1691 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1692 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1697 sd_bus_error_free(error
);
1708 r
= sd_bus_message_read(reply
, "o", &j
);
1722 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1726 return sd_bus_call_method(
1728 "org.freedesktop.systemd1",
1729 "/org/freedesktop/systemd1",
1730 "org.freedesktop.systemd1.Manager",
1734 "ssi", unit
, "all", signo
);
1737 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1738 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1739 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1740 _cleanup_free_
char *path
= NULL
;
1747 path
= unit_dbus_path_from_name(unit
);
1751 r
= sd_bus_get_property(
1753 "org.freedesktop.systemd1",
1755 "org.freedesktop.systemd1.Unit",
1761 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1762 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1765 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1766 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1772 r
= sd_bus_message_read(reply
, "s", &state
);
1776 return !STR_IN_SET(state
, "inactive", "failed");
1779 int manager_job_is_active(Manager
*manager
, const char *path
) {
1780 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1781 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1787 r
= sd_bus_get_property(
1789 "org.freedesktop.systemd1",
1791 "org.freedesktop.systemd1.Job",
1797 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1798 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1801 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1807 /* We don't actually care about the state really. The fact
1808 * that we could read the job state is enough for us */
1813 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1821 mm
= hashmap_get(m
->machine_leaders
, PID_TO_PTR(pid
));
1823 _cleanup_free_
char *unit
= NULL
;
1825 r
= cg_pid_get_unit(pid
, &unit
);
1827 mm
= hashmap_get(m
->machine_units
, unit
);
1836 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1842 machine
= hashmap_get(m
->machines
, name
);
1844 machine
= machine_new(m
, _MACHINE_CLASS_INVALID
, name
);
1850 *_machine
= machine
;
1855 int bus_reply_pair_array(sd_bus_message
*m
, char **l
) {
1856 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1860 r
= sd_bus_message_new_method_return(m
, &reply
);
1864 r
= sd_bus_message_open_container(reply
, 'a', "{ss}");
1868 STRV_FOREACH_PAIR(k
, v
, l
) {
1869 r
= sd_bus_message_append(reply
, "{ss}", *k
, *v
);
1874 r
= sd_bus_message_close_container(reply
);
1878 return sd_bus_send(NULL
, reply
, NULL
);