2 This file is part of systemd.
4 Copyright 2011 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/>.
26 #include "alloc-util.h"
27 #include "btrfs-util.h"
28 #include "bus-common-errors.h"
30 #include "cgroup-util.h"
33 #include "format-util.h"
34 #include "hostname-util.h"
35 #include "image-dbus.h"
37 #include "machine-dbus.h"
38 #include "machine-image.h"
39 #include "machine-pool.h"
41 #include "path-util.h"
42 #include "process-util.h"
43 #include "stdio-util.h"
45 #include "unit-name.h"
46 #include "user-util.h"
48 static int property_get_pool_path(
51 const char *interface
,
53 sd_bus_message
*reply
,
55 sd_bus_error
*error
) {
60 return sd_bus_message_append(reply
, "s", "/var/lib/machines");
63 static int property_get_pool_usage(
66 const char *interface
,
68 sd_bus_message
*reply
,
70 sd_bus_error
*error
) {
72 _cleanup_close_
int fd
= -1;
73 uint64_t usage
= (uint64_t) -1;
79 /* We try to read the quota info from /var/lib/machines, as
80 * well as the usage of the loopback file
81 * /var/lib/machines.raw, and pick the larger value. */
83 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
87 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
91 if (stat("/var/lib/machines.raw", &st
) >= 0) {
92 if (usage
== (uint64_t) -1 || st
.st_blocks
* 512ULL > usage
)
93 usage
= st
.st_blocks
* 512ULL;
96 return sd_bus_message_append(reply
, "t", usage
);
99 static int property_get_pool_limit(
102 const char *interface
,
103 const char *property
,
104 sd_bus_message
*reply
,
106 sd_bus_error
*error
) {
108 _cleanup_close_
int fd
= -1;
109 uint64_t size
= (uint64_t) -1;
115 /* We try to read the quota limit from /var/lib/machines, as
116 * well as the size of the loopback file
117 * /var/lib/machines.raw, and pick the smaller value. */
119 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
123 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
124 size
= q
.referenced_max
;
127 if (stat("/var/lib/machines.raw", &st
) >= 0) {
128 if (size
== (uint64_t) -1 || (uint64_t) st
.st_size
< size
)
132 return sd_bus_message_append(reply
, "t", size
);
135 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
136 _cleanup_free_
char *p
= NULL
;
137 Manager
*m
= userdata
;
145 r
= sd_bus_message_read(message
, "s", &name
);
149 machine
= hashmap_get(m
->machines
, name
);
151 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
153 p
= machine_bus_path(machine
);
157 return sd_bus_reply_method_return(message
, "o", p
);
160 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
161 _cleanup_free_
char *p
= NULL
;
162 Manager
*m
= userdata
;
169 r
= sd_bus_message_read(message
, "s", &name
);
173 r
= image_find(name
, NULL
);
175 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
179 p
= image_bus_path(name
);
183 return sd_bus_reply_method_return(message
, "o", p
);
186 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
187 _cleanup_free_
char *p
= NULL
;
188 Manager
*m
= userdata
;
189 Machine
*machine
= NULL
;
196 assert_cc(sizeof(pid_t
) == sizeof(uint32_t));
198 r
= sd_bus_message_read(message
, "u", &pid
);
206 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
208 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
212 r
= sd_bus_creds_get_pid(creds
, &pid
);
217 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
221 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
223 p
= machine_bus_path(machine
);
227 return sd_bus_reply_method_return(message
, "o", p
);
230 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
231 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
232 Manager
*m
= userdata
;
240 r
= sd_bus_message_new_method_return(message
, &reply
);
242 return sd_bus_error_set_errno(error
, r
);
244 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
246 return sd_bus_error_set_errno(error
, r
);
248 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
249 _cleanup_free_
char *p
= NULL
;
251 p
= machine_bus_path(machine
);
255 r
= sd_bus_message_append(reply
, "(ssso)",
257 strempty(machine_class_to_string(machine
->class)),
261 return sd_bus_error_set_errno(error
, r
);
264 r
= sd_bus_message_close_container(reply
);
266 return sd_bus_error_set_errno(error
, r
);
268 return sd_bus_send(NULL
, reply
, NULL
);
271 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
272 const char *name
, *service
, *class, *root_directory
;
273 const int32_t *netif
= NULL
;
279 size_t n
, n_netif
= 0;
286 r
= sd_bus_message_read(message
, "s", &name
);
289 if (!machine_name_is_valid(name
))
290 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
292 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
300 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
302 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
309 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
313 n_netif
/= sizeof(int32_t);
315 for (i
= 0; i
< n_netif
; i
++) {
317 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
322 c
= _MACHINE_CLASS_INVALID
;
324 c
= machine_class_from_string(class);
326 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
330 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
332 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
333 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
336 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
338 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
342 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
344 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
349 if (hashmap_get(manager
->machines
, name
))
350 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
352 r
= manager_add_machine(manager
, name
, &m
);
360 if (!isempty(service
)) {
361 m
->service
= strdup(service
);
368 if (!isempty(root_directory
)) {
369 m
->root_directory
= strdup(root_directory
);
370 if (!m
->root_directory
) {
377 assert_cc(sizeof(int32_t) == sizeof(int));
378 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
384 m
->n_netif
= n_netif
;
392 machine_add_to_gc_queue(m
);
396 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
397 Manager
*manager
= userdata
;
404 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
408 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
412 r
= machine_start(m
, message
, error
);
416 m
->create_message
= sd_bus_message_ref(message
);
420 machine_add_to_gc_queue(m
);
424 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
425 return method_create_machine_internal(message
, true, userdata
, error
);
428 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
429 return method_create_machine_internal(message
, false, userdata
, error
);
432 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
433 Manager
*manager
= userdata
;
434 _cleanup_free_
char *p
= NULL
;
441 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
445 r
= cg_pid_get_unit(m
->leader
, &m
->unit
);
447 r
= sd_bus_error_set_errnof(error
, r
,
448 "Failed to determine unit of process "PID_FMT
" : %m",
453 r
= machine_start(m
, NULL
, error
);
457 p
= machine_bus_path(m
);
463 return sd_bus_reply_method_return(message
, "o", p
);
466 machine_add_to_gc_queue(m
);
470 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
471 return method_register_machine_internal(message
, true, userdata
, error
);
474 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
475 return method_register_machine_internal(message
, false, userdata
, error
);
478 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
479 Manager
*m
= userdata
;
487 r
= sd_bus_message_read(message
, "s", &name
);
489 return sd_bus_error_set_errno(error
, r
);
491 machine
= hashmap_get(m
->machines
, name
);
493 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
495 return bus_machine_method_terminate(message
, machine
, error
);
498 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
499 Manager
*m
= userdata
;
507 r
= sd_bus_message_read(message
, "s", &name
);
509 return sd_bus_error_set_errno(error
, r
);
511 machine
= hashmap_get(m
->machines
, name
);
513 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
515 return bus_machine_method_kill(message
, machine
, error
);
518 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
519 Manager
*m
= userdata
;
527 r
= sd_bus_message_read(message
, "s", &name
);
529 return sd_bus_error_set_errno(error
, r
);
531 machine
= hashmap_get(m
->machines
, name
);
533 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
535 return bus_machine_method_get_addresses(message
, machine
, error
);
538 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
539 Manager
*m
= userdata
;
547 r
= sd_bus_message_read(message
, "s", &name
);
549 return sd_bus_error_set_errno(error
, r
);
551 machine
= hashmap_get(m
->machines
, name
);
553 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
555 return bus_machine_method_get_os_release(message
, machine
, error
);
558 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
559 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
560 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
561 Manager
*m
= userdata
;
569 images
= hashmap_new(&string_hash_ops
);
573 r
= image_discover(images
);
577 r
= sd_bus_message_new_method_return(message
, &reply
);
581 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
585 HASHMAP_FOREACH(image
, images
, i
) {
586 _cleanup_free_
char *p
= NULL
;
588 p
= image_bus_path(image
->name
);
592 r
= sd_bus_message_append(reply
, "(ssbttto)",
594 image_type_to_string(image
->type
),
604 r
= sd_bus_message_close_container(reply
);
608 return sd_bus_send(NULL
, reply
, NULL
);
611 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
612 Manager
*m
= userdata
;
620 r
= sd_bus_message_read(message
, "s", &name
);
622 return sd_bus_error_set_errno(error
, r
);
624 machine
= hashmap_get(m
->machines
, name
);
626 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
628 return bus_machine_method_open_pty(message
, machine
, error
);
631 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
632 Manager
*m
= userdata
;
640 r
= sd_bus_message_read(message
, "s", &name
);
644 machine
= hashmap_get(m
->machines
, name
);
646 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
648 return bus_machine_method_open_login(message
, machine
, error
);
651 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
652 Manager
*m
= userdata
;
661 r
= sd_bus_message_read(message
, "s", &name
);
665 machine
= hashmap_get(m
->machines
, name
);
667 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
669 return bus_machine_method_open_shell(message
, machine
, error
);
672 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
673 Manager
*m
= userdata
;
681 r
= sd_bus_message_read(message
, "s", &name
);
685 machine
= hashmap_get(m
->machines
, name
);
687 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
689 return bus_machine_method_bind_mount(message
, machine
, error
);
692 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
693 Manager
*m
= userdata
;
701 r
= sd_bus_message_read(message
, "s", &name
);
705 machine
= hashmap_get(m
->machines
, name
);
707 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
709 return bus_machine_method_copy(message
, machine
, error
);
712 static int method_open_machine_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
713 Manager
*m
= userdata
;
721 r
= sd_bus_message_read(message
, "s", &name
);
725 machine
= hashmap_get(m
->machines
, name
);
727 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
729 return bus_machine_method_open_root_directory(message
, machine
, error
);
732 static int method_get_machine_uid_shift(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
733 Manager
*m
= userdata
;
741 r
= sd_bus_message_read(message
, "s", &name
);
745 machine
= hashmap_get(m
->machines
, name
);
747 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
749 return bus_machine_method_get_uid_shift(message
, machine
, error
);
752 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
753 _cleanup_(image_unrefp
) Image
* i
= NULL
;
759 r
= sd_bus_message_read(message
, "s", &name
);
763 if (!image_name_is_valid(name
))
764 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
766 r
= image_find(name
, &i
);
770 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
772 i
->userdata
= userdata
;
773 return bus_image_method_remove(message
, i
, error
);
776 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
777 _cleanup_(image_unrefp
) Image
* i
= NULL
;
778 const char *old_name
;
783 r
= sd_bus_message_read(message
, "s", &old_name
);
787 if (!image_name_is_valid(old_name
))
788 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
790 r
= image_find(old_name
, &i
);
794 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
796 i
->userdata
= userdata
;
797 return bus_image_method_rename(message
, i
, error
);
800 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
801 _cleanup_(image_unrefp
) Image
*i
= NULL
;
802 const char *old_name
;
807 r
= sd_bus_message_read(message
, "s", &old_name
);
811 if (!image_name_is_valid(old_name
))
812 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
814 r
= image_find(old_name
, &i
);
818 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
820 i
->userdata
= userdata
;
821 return bus_image_method_clone(message
, i
, error
);
824 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
825 _cleanup_(image_unrefp
) Image
*i
= NULL
;
831 r
= sd_bus_message_read(message
, "s", &name
);
835 if (!image_name_is_valid(name
))
836 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
838 r
= image_find(name
, &i
);
842 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
844 i
->userdata
= userdata
;
845 return bus_image_method_mark_read_only(message
, i
, error
);
848 static int method_get_image_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
849 _cleanup_(image_unrefp
) Image
*i
= NULL
;
855 r
= sd_bus_message_read(message
, "s", &name
);
859 if (!image_name_is_valid(name
))
860 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
862 r
= image_find(name
, &i
);
866 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
868 i
->userdata
= userdata
;
869 return bus_image_method_get_os_release(message
, i
, error
);
872 static int clean_pool_done(Operation
*operation
, int ret
, sd_bus_error
*error
) {
873 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
874 _cleanup_fclose_
FILE *f
= NULL
;
880 assert(operation
->extra_fd
>= 0);
882 if (lseek(operation
->extra_fd
, 0, SEEK_SET
) == (off_t
) -1)
885 f
= fdopen(operation
->extra_fd
, "re");
889 operation
->extra_fd
= -1;
891 /* The resulting temporary file starts with a boolean value that indicates success or not. */
893 n
= fread(&success
, 1, sizeof(success
), f
);
894 if (n
!= sizeof(success
))
895 return ret
< 0 ? ret
: (errno
!= 0 ? -errno
: -EIO
);
898 _cleanup_free_
char *name
= NULL
;
900 /* The clean-up operation failed. In this case the resulting temporary file should contain a boolean
901 * set to false followed by the name of the failed image. Let's try to read this and use it for the
902 * error message. If we can't read it, don't mind, and return the naked error. */
904 if (success
) /* The resulting temporary file could not be updated, ignore it. */
907 r
= read_nul_string(f
, &name
);
908 if (r
< 0 || isempty(name
)) /* Same here... */
911 return sd_bus_error_set_errnof(error
, ret
, "Failed to remove image %s: %m", name
);
916 r
= sd_bus_message_new_method_return(operation
->message
, &reply
);
920 r
= sd_bus_message_open_container(reply
, 'a', "(st)");
924 /* On success the resulting temporary file will contain a list of image names that were removed followed by
925 * their size on disk. Let's read that and turn it into a bus message. */
927 _cleanup_free_
char *name
= NULL
;
930 r
= read_nul_string(f
, &name
);
933 if (isempty(name
)) /* reached the end */
937 n
= fread(&size
, 1, sizeof(size
), f
);
938 if (n
!= sizeof(size
))
939 return errno
!= 0 ? -errno
: -EIO
;
941 r
= sd_bus_message_append(reply
, "(st)", name
, size
);
946 r
= sd_bus_message_close_container(reply
);
950 return sd_bus_send(NULL
, reply
, NULL
);
953 static int method_clean_pool(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
959 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
960 _cleanup_close_
int result_fd
= -1;
961 Manager
*m
= userdata
;
962 Operation
*operation
;
969 if (m
->n_operations
>= OPERATIONS_MAX
)
970 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing operations.");
972 r
= sd_bus_message_read(message
, "s", &mm
);
976 if (streq(mm
, "all"))
978 else if (streq(mm
, "hidden"))
979 mode
= REMOVE_HIDDEN
;
981 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown mode '%s'.", mm
);
983 r
= bus_verify_polkit_async(
986 "org.freedesktop.machine1.manage-machines",
995 return 1; /* Will call us back */
997 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
998 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
1000 /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
1001 * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
1003 result_fd
= open_tmpfile_unlinkable(NULL
, O_RDWR
|O_CLOEXEC
);
1007 /* This might be a slow operation, run it asynchronously in a background process */
1010 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
1013 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
1014 bool success
= true;
1019 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1021 images
= hashmap_new(&string_hash_ops
);
1027 r
= image_discover(images
);
1031 l
= write(result_fd
, &success
, sizeof(success
));
1037 HASHMAP_FOREACH(image
, images
, i
) {
1039 /* We can't remove vendor images (i.e. those in /usr) */
1040 if (IMAGE_IS_VENDOR(image
))
1043 if (IMAGE_IS_HOST(image
))
1046 if (mode
== REMOVE_HIDDEN
&& !IMAGE_IS_HIDDEN(image
))
1049 r
= image_remove(image
);
1050 if (r
== -EBUSY
) /* keep images that are currently being used. */
1053 /* If the operation failed, let's override everything we wrote, and instead write there at which image we failed. */
1055 (void) ftruncate(result_fd
, 0);
1056 (void) lseek(result_fd
, 0, SEEK_SET
);
1057 (void) write(result_fd
, &success
, sizeof(success
));
1058 (void) write(result_fd
, image
->name
, strlen(image
->name
)+1);
1062 l
= write(result_fd
, image
->name
, strlen(image
->name
)+1);
1068 l
= write(result_fd
, &image
->usage_exclusive
, sizeof(image
->usage_exclusive
));
1075 result_fd
= safe_close(result_fd
);
1076 _exit(EXIT_SUCCESS
);
1079 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1080 _exit(EXIT_FAILURE
);
1083 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1085 /* The clean-up might take a while, hence install a watch on the child and return */
1087 r
= operation_new(m
, NULL
, child
, message
, errno_pipe_fd
[0], &operation
);
1089 (void) sigkill_wait(child
);
1093 operation
->extra_fd
= result_fd
;
1094 operation
->done
= clean_pool_done
;
1097 errno_pipe_fd
[0] = -1;
1102 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1103 Manager
*m
= userdata
;
1109 r
= sd_bus_message_read(message
, "t", &limit
);
1112 if (!FILE_SIZE_VALID_OR_INFINITY(limit
))
1113 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "New limit out of range");
1115 r
= bus_verify_polkit_async(
1118 "org.freedesktop.machine1.manage-machines",
1122 &m
->polkit_registry
,
1127 return 1; /* Will call us back */
1129 /* Set up the machine directory if necessary */
1130 r
= setup_machine_directory(limit
, error
);
1134 /* Resize the backing loopback device, if there is one, except if we asked to drop any limit */
1135 if (limit
!= (uint64_t) -1) {
1136 r
= btrfs_resize_loopback("/var/lib/machines", limit
, false);
1138 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
1139 if (r
< 0 && r
!= -ENODEV
) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
1140 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust loopback limit: %m");
1143 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit
);
1145 r
= btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit
);
1147 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
1149 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
1151 return sd_bus_reply_method_return(message
, NULL
);
1154 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1155 _cleanup_(image_unrefp
) Image
*i
= NULL
;
1161 r
= sd_bus_message_read(message
, "s", &name
);
1165 if (!image_name_is_valid(name
))
1166 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
1168 r
= image_find(name
, &i
);
1172 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
1174 i
->userdata
= userdata
;
1175 return bus_image_method_set_limit(message
, i
, error
);
1178 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1179 _cleanup_fclose_
FILE *f
= NULL
;
1180 Manager
*m
= userdata
;
1181 const char *name
, *p
;
1186 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
1190 if (!uid_is_valid(uid
))
1191 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1193 machine
= hashmap_get(m
->machines
, name
);
1195 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1197 if (machine
->class != MACHINE_CONTAINER
)
1198 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1200 p
= procfs_file_alloca(machine
->leader
, "uid_map");
1206 uid_t uid_base
, uid_shift
, uid_range
, converted
;
1210 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
1211 if (k
< 0 && feof(f
))
1214 if (ferror(f
) && errno
> 0)
1220 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
1223 converted
= uid
- uid_base
+ uid_shift
;
1224 if (!uid_is_valid(converted
))
1225 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1227 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1230 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
1233 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1234 Manager
*m
= userdata
;
1240 r
= sd_bus_message_read(message
, "u", &uid
);
1243 if (!uid_is_valid(uid
))
1244 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1246 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
1248 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1249 _cleanup_fclose_
FILE *f
= NULL
;
1250 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1252 if (machine
->class != MACHINE_CONTAINER
)
1255 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
1258 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1263 _cleanup_free_
char *o
= NULL
;
1264 uid_t uid_base
, uid_shift
, uid_range
, converted
;
1268 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
1269 if (k
< 0 && feof(f
))
1272 if (ferror(f
) && errno
> 0)
1278 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
1281 converted
= (uid
- uid_shift
+ uid_base
);
1282 if (!uid_is_valid(converted
))
1283 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1285 o
= machine_bus_path(machine
);
1289 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1293 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
1296 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1297 _cleanup_fclose_
FILE *f
= NULL
;
1298 Manager
*m
= groupdata
;
1299 const char *name
, *p
;
1304 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
1308 if (!gid_is_valid(gid
))
1309 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1311 machine
= hashmap_get(m
->machines
, name
);
1313 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1315 if (machine
->class != MACHINE_CONTAINER
)
1316 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1318 p
= procfs_file_alloca(machine
->leader
, "gid_map");
1324 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1328 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1329 if (k
< 0 && feof(f
))
1332 if (ferror(f
) && errno
> 0)
1338 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
1341 converted
= gid
- gid_base
+ gid_shift
;
1342 if (!gid_is_valid(converted
))
1343 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1345 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1348 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1351 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1352 Manager
*m
= groupdata
;
1358 r
= sd_bus_message_read(message
, "u", &gid
);
1361 if (!gid_is_valid(gid
))
1362 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1364 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1366 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1367 _cleanup_fclose_
FILE *f
= NULL
;
1368 char p
[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1370 if (machine
->class != MACHINE_CONTAINER
)
1373 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1376 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1381 _cleanup_free_
char *o
= NULL
;
1382 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1386 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1387 if (k
< 0 && feof(f
))
1390 if (ferror(f
) && errno
> 0)
1396 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1399 converted
= (gid
- gid_shift
+ gid_base
);
1400 if (!gid_is_valid(converted
))
1401 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1403 o
= machine_bus_path(machine
);
1407 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1411 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1414 const sd_bus_vtable manager_vtable
[] = {
1415 SD_BUS_VTABLE_START(0),
1416 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1417 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1418 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1419 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1420 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1421 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1422 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1423 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1424 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1425 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1426 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1427 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1428 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1429 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1430 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1431 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1432 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1433 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1434 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1435 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1436 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1437 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1438 SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory
, SD_BUS_VTABLE_UNPRIVILEGED
),
1439 SD_BUS_METHOD("GetMachineUIDShift", "s", "u", method_get_machine_uid_shift
, SD_BUS_VTABLE_UNPRIVILEGED
),
1440 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1441 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1442 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1443 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1444 SD_BUS_METHOD("GetImageOSRelease", "s", "a{ss}", method_get_image_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1445 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1446 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1447 SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool
, SD_BUS_VTABLE_UNPRIVILEGED
),
1448 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1449 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1450 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1451 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1452 SD_BUS_SIGNAL("MachineNew", "so", 0),
1453 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1457 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1458 const char *path
, *result
, *unit
;
1459 Manager
*m
= userdata
;
1467 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1469 bus_log_parse_error(r
);
1473 machine
= hashmap_get(m
->machine_units
, unit
);
1477 if (streq_ptr(path
, machine
->scope_job
)) {
1478 machine
->scope_job
= mfree(machine
->scope_job
);
1480 if (machine
->started
) {
1481 if (streq(result
, "done"))
1482 machine_send_create_reply(machine
, NULL
);
1484 _cleanup_(sd_bus_error_free
) sd_bus_error e
= SD_BUS_ERROR_NULL
;
1486 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1488 machine_send_create_reply(machine
, &e
);
1492 machine_save(machine
);
1495 machine_add_to_gc_queue(machine
);
1499 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1500 _cleanup_free_
char *unit
= NULL
;
1502 Manager
*m
= userdata
;
1509 path
= sd_bus_message_get_path(message
);
1513 r
= unit_name_from_dbus_path(path
, &unit
);
1514 if (r
== -EINVAL
) /* not for a unit */
1521 machine
= hashmap_get(m
->machine_units
, unit
);
1525 machine_add_to_gc_queue(machine
);
1529 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1530 const char *path
, *unit
;
1531 Manager
*m
= userdata
;
1538 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1540 bus_log_parse_error(r
);
1544 machine
= hashmap_get(m
->machine_units
, unit
);
1548 machine_add_to_gc_queue(machine
);
1552 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1553 Manager
*m
= userdata
;
1561 r
= sd_bus_message_read(message
, "b", &b
);
1563 bus_log_parse_error(r
);
1569 /* systemd finished reloading, let's recheck all our machines */
1570 log_debug("System manager has been reloaded, rechecking machines...");
1572 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1573 machine_add_to_gc_queue(machine
);
1578 int manager_start_scope(
1583 const char *description
,
1584 sd_bus_message
*more_properties
,
1585 sd_bus_error
*error
,
1588 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1595 r
= sd_bus_message_new_method_call(
1598 "org.freedesktop.systemd1",
1599 "/org/freedesktop/systemd1",
1600 "org.freedesktop.systemd1.Manager",
1601 "StartTransientUnit");
1605 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1609 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1613 if (!isempty(slice
)) {
1614 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1619 if (!isempty(description
)) {
1620 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1625 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, pid
);
1629 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
1633 r
= sd_bus_message_append(m
, "(sv)", "TasksMax", "t", UINT64_C(16384));
1635 return bus_log_create_error(r
);
1637 if (more_properties
) {
1638 r
= sd_bus_message_copy(m
, more_properties
, true);
1643 r
= sd_bus_message_close_container(m
);
1647 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1651 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1659 r
= sd_bus_message_read(reply
, "o", &j
);
1673 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1674 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1680 r
= sd_bus_call_method(
1682 "org.freedesktop.systemd1",
1683 "/org/freedesktop/systemd1",
1684 "org.freedesktop.systemd1.Manager",
1688 "ss", unit
, "fail");
1690 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1691 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1696 sd_bus_error_free(error
);
1707 r
= sd_bus_message_read(reply
, "o", &j
);
1721 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1725 return sd_bus_call_method(
1727 "org.freedesktop.systemd1",
1728 "/org/freedesktop/systemd1",
1729 "org.freedesktop.systemd1.Manager",
1733 "ssi", unit
, "all", signo
);
1736 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1737 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1738 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1739 _cleanup_free_
char *path
= NULL
;
1746 path
= unit_dbus_path_from_name(unit
);
1750 r
= sd_bus_get_property(
1752 "org.freedesktop.systemd1",
1754 "org.freedesktop.systemd1.Unit",
1760 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1761 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1764 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1765 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1771 r
= sd_bus_message_read(reply
, "s", &state
);
1775 return !STR_IN_SET(state
, "inactive", "failed");
1778 int manager_job_is_active(Manager
*manager
, const char *path
) {
1779 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1780 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1786 r
= sd_bus_get_property(
1788 "org.freedesktop.systemd1",
1790 "org.freedesktop.systemd1.Job",
1796 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1797 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1800 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1806 /* We don't actually care about the state really. The fact
1807 * that we could read the job state is enough for us */
1812 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1820 mm
= hashmap_get(m
->machine_leaders
, PID_TO_PTR(pid
));
1822 _cleanup_free_
char *unit
= NULL
;
1824 r
= cg_pid_get_unit(pid
, &unit
);
1826 mm
= hashmap_get(m
->machine_units
, unit
);
1835 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1841 machine
= hashmap_get(m
->machines
, name
);
1843 machine
= machine_new(m
, _MACHINE_CLASS_INVALID
, name
);
1849 *_machine
= machine
;
1854 int bus_reply_pair_array(sd_bus_message
*m
, char **l
) {
1855 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1859 r
= sd_bus_message_new_method_return(m
, &reply
);
1863 r
= sd_bus_message_open_container(reply
, 'a', "{ss}");
1867 STRV_FOREACH_PAIR(k
, v
, l
) {
1868 r
= sd_bus_message_append(reply
, "{ss}", *k
, *v
);
1873 r
= sd_bus_message_close_container(reply
);
1877 return sd_bus_send(NULL
, reply
, NULL
);