1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
9 #include "btrfs-util.h"
10 #include "bus-common-errors.h"
11 #include "bus-get-properties.h"
12 #include "bus-locator.h"
13 #include "bus-polkit.h"
14 #include "cgroup-util.h"
15 #include "discover-image.h"
16 #include "errno-util.h"
19 #include "format-util.h"
20 #include "hostname-util.h"
21 #include "image-dbus.h"
23 #include "machine-dbus.h"
24 #include "machine-pool.h"
26 #include "missing_capability.h"
28 #include "path-util.h"
29 #include "process-util.h"
30 #include "stdio-util.h"
32 #include "tmpfile-util.h"
33 #include "unit-name.h"
34 #include "user-util.h"
36 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_pool_path
, "s", "/var/lib/machines");
38 static int property_get_pool_usage(
41 const char *interface
,
43 sd_bus_message
*reply
,
45 sd_bus_error
*error
) {
47 _cleanup_close_
int fd
= -EBADF
;
48 uint64_t usage
= UINT64_MAX
;
53 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
57 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
61 return sd_bus_message_append(reply
, "t", usage
);
64 static int property_get_pool_limit(
67 const char *interface
,
69 sd_bus_message
*reply
,
71 sd_bus_error
*error
) {
73 _cleanup_close_
int fd
= -EBADF
;
74 uint64_t size
= UINT64_MAX
;
79 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
83 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
84 size
= q
.referenced_max
;
87 return sd_bus_message_append(reply
, "t", size
);
90 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
91 _cleanup_free_
char *p
= NULL
;
92 Manager
*m
= ASSERT_PTR(userdata
);
99 r
= sd_bus_message_read(message
, "s", &name
);
103 machine
= hashmap_get(m
->machines
, name
);
105 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
107 p
= machine_bus_path(machine
);
111 return sd_bus_reply_method_return(message
, "o", p
);
114 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
115 _cleanup_free_
char *p
= NULL
;
116 _unused_ Manager
*m
= ASSERT_PTR(userdata
);
122 r
= sd_bus_message_read(message
, "s", &name
);
126 r
= image_find(IMAGE_MACHINE
, name
, NULL
, NULL
);
128 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
132 p
= image_bus_path(name
);
136 return sd_bus_reply_method_return(message
, "o", p
);
139 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
140 _cleanup_free_
char *p
= NULL
;
141 Manager
*m
= ASSERT_PTR(userdata
);
142 Machine
*machine
= NULL
;
148 assert_cc(sizeof(pid_t
) == sizeof(uint32_t));
150 r
= sd_bus_message_read(message
, "u", &pid
);
158 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
160 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
164 r
= sd_bus_creds_get_pid(creds
, &pid
);
169 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
173 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
175 p
= machine_bus_path(machine
);
179 return sd_bus_reply_method_return(message
, "o", p
);
182 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
183 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
184 Manager
*m
= ASSERT_PTR(userdata
);
190 r
= sd_bus_message_new_method_return(message
, &reply
);
192 return sd_bus_error_set_errno(error
, r
);
194 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
196 return sd_bus_error_set_errno(error
, r
);
198 HASHMAP_FOREACH(machine
, m
->machines
) {
199 _cleanup_free_
char *p
= NULL
;
201 p
= machine_bus_path(machine
);
205 r
= sd_bus_message_append(reply
, "(ssso)",
207 strempty(machine_class_to_string(machine
->class)),
211 return sd_bus_error_set_errno(error
, r
);
214 r
= sd_bus_message_close_container(reply
);
216 return sd_bus_error_set_errno(error
, r
);
218 return sd_bus_send(NULL
, reply
, NULL
);
221 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
222 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
223 const char *name
, *service
, *class, *root_directory
;
224 const int32_t *netif
= NULL
;
230 size_t n
, n_netif
= 0;
237 r
= sd_bus_message_read(message
, "s", &name
);
240 if (!hostname_is_valid(name
, 0))
241 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
243 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
251 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
253 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
258 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
262 n_netif
/= sizeof(int32_t);
264 for (size_t i
= 0; i
< n_netif
; i
++) {
266 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
271 c
= _MACHINE_CLASS_INVALID
;
273 c
= machine_class_from_string(class);
275 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
279 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
281 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
282 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
285 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
287 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
291 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
293 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
298 r
= pidref_set_pid(&pidref
, leader
);
300 return sd_bus_error_set_errnof(error
, r
, "Failed to pin process " PID_FMT
": %m", pidref
.pid
);
302 if (hashmap_get(manager
->machines
, name
))
303 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
305 r
= manager_add_machine(manager
, name
, &m
);
309 m
->leader
= TAKE_PIDREF(pidref
);
313 if (!isempty(service
)) {
314 m
->service
= strdup(service
);
321 if (!isempty(root_directory
)) {
322 m
->root_directory
= strdup(root_directory
);
323 if (!m
->root_directory
) {
330 assert_cc(sizeof(int32_t) == sizeof(int));
331 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
337 m
->n_netif
= n_netif
;
345 machine_add_to_gc_queue(m
);
349 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
350 Manager
*manager
= ASSERT_PTR(userdata
);
356 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
360 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
364 r
= machine_start(m
, message
, error
);
368 m
->create_message
= sd_bus_message_ref(message
);
372 machine_add_to_gc_queue(m
);
376 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
377 return method_create_machine_internal(message
, true, userdata
, error
);
380 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
381 return method_create_machine_internal(message
, false, userdata
, error
);
384 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
385 Manager
*manager
= ASSERT_PTR(userdata
);
386 _cleanup_free_
char *p
= NULL
;
392 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
396 r
= cg_pid_get_unit(m
->leader
.pid
, &m
->unit
);
398 r
= sd_bus_error_set_errnof(error
, r
,
399 "Failed to determine unit of process "PID_FMT
" : %m",
404 r
= machine_start(m
, NULL
, error
);
408 p
= machine_bus_path(m
);
414 return sd_bus_reply_method_return(message
, "o", p
);
417 machine_add_to_gc_queue(m
);
421 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
422 return method_register_machine_internal(message
, true, userdata
, error
);
425 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
426 return method_register_machine_internal(message
, false, userdata
, error
);
429 static int redirect_method_to_machine(sd_bus_message
*message
, Manager
*m
, sd_bus_error
*error
, sd_bus_message_handler_t method
) {
438 r
= sd_bus_message_read(message
, "s", &name
);
440 return sd_bus_error_set_errno(error
, r
);
442 machine
= hashmap_get(m
->machines
, name
);
444 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
446 return method(message
, machine
, error
);
449 static int method_unregister_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
450 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_unregister
);
453 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
454 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_terminate
);
457 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
458 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_kill
);
461 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
462 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_addresses
);
465 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
466 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_os_release
);
469 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
470 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
471 _cleanup_hashmap_free_ Hashmap
*images
= NULL
;
472 _unused_ Manager
*m
= ASSERT_PTR(userdata
);
478 images
= hashmap_new(&image_hash_ops
);
482 r
= image_discover(IMAGE_MACHINE
, NULL
, images
);
486 r
= sd_bus_message_new_method_return(message
, &reply
);
490 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
494 HASHMAP_FOREACH(image
, images
) {
495 _cleanup_free_
char *p
= NULL
;
497 p
= image_bus_path(image
->name
);
501 r
= sd_bus_message_append(reply
, "(ssbttto)",
503 image_type_to_string(image
->type
),
513 r
= sd_bus_message_close_container(reply
);
517 return sd_bus_send(NULL
, reply
, NULL
);
520 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
521 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_pty
);
524 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
525 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_login
);
528 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
529 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_shell
);
532 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
533 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_bind_mount
);
536 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
537 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_copy
);
540 static int method_open_machine_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
541 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_root_directory
);
544 static int method_get_machine_uid_shift(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
545 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_uid_shift
);
548 static int redirect_method_to_image(sd_bus_message
*message
, Manager
*m
, sd_bus_error
*error
, sd_bus_message_handler_t method
) {
549 _cleanup_(image_unrefp
) Image
* i
= NULL
;
557 r
= sd_bus_message_read(message
, "s", &name
);
561 if (!image_name_is_valid(name
))
562 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
564 r
= image_find(IMAGE_MACHINE
, name
, NULL
, &i
);
566 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
571 return method(message
, i
, error
);
574 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
575 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_remove
);
578 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
579 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_rename
);
582 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
583 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_clone
);
586 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
587 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_mark_read_only
);
590 static int method_get_image_hostname(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
591 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_hostname
);
594 static int method_get_image_machine_id(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
595 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_machine_id
);
598 static int method_get_image_machine_info(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
599 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_machine_info
);
602 static int method_get_image_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
603 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_os_release
);
606 static int clean_pool_done(Operation
*operation
, int ret
, sd_bus_error
*error
) {
607 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
608 _cleanup_fclose_
FILE *f
= NULL
;
614 assert(operation
->extra_fd
>= 0);
616 if (lseek(operation
->extra_fd
, 0, SEEK_SET
) < 0)
619 f
= take_fdopen(&operation
->extra_fd
, "r");
623 /* The resulting temporary file starts with a boolean value that indicates success or not. */
625 n
= fread(&success
, 1, sizeof(success
), f
);
626 if (n
!= sizeof(success
))
627 return ret
< 0 ? ret
: errno_or_else(EIO
);
630 _cleanup_free_
char *name
= NULL
;
632 /* The clean-up operation failed. In this case the resulting temporary file should contain a boolean
633 * set to false followed by the name of the failed image. Let's try to read this and use it for the
634 * error message. If we can't read it, don't mind, and return the naked error. */
636 if (success
) /* The resulting temporary file could not be updated, ignore it. */
639 r
= read_nul_string(f
, LONG_LINE_MAX
, &name
);
640 if (r
<= 0) /* Same here... */
643 return sd_bus_error_set_errnof(error
, ret
, "Failed to remove image %s: %m", name
);
648 r
= sd_bus_message_new_method_return(operation
->message
, &reply
);
652 r
= sd_bus_message_open_container(reply
, 'a', "(st)");
656 /* On success the resulting temporary file will contain a list of image names that were removed followed by
657 * their size on disk. Let's read that and turn it into a bus message. */
659 _cleanup_free_
char *name
= NULL
;
662 r
= read_nul_string(f
, LONG_LINE_MAX
, &name
);
665 if (r
== 0) /* reached the end */
669 n
= fread(&size
, 1, sizeof(size
), f
);
670 if (n
!= sizeof(size
))
671 return errno_or_else(EIO
);
673 r
= sd_bus_message_append(reply
, "(st)", name
, size
);
678 r
= sd_bus_message_close_container(reply
);
682 return sd_bus_send(NULL
, reply
, NULL
);
685 static int method_clean_pool(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
691 _cleanup_close_pair_
int errno_pipe_fd
[2] = EBADF_PAIR
;
692 _cleanup_close_
int result_fd
= -EBADF
;
693 Manager
*m
= userdata
;
694 Operation
*operation
;
701 if (m
->n_operations
>= OPERATIONS_MAX
)
702 return sd_bus_error_set(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing operations.");
704 r
= sd_bus_message_read(message
, "s", &mm
);
708 if (streq(mm
, "all"))
710 else if (streq(mm
, "hidden"))
711 mode
= REMOVE_HIDDEN
;
713 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown mode '%s'.", mm
);
715 const char *details
[] = {
716 "verb", "clean_pool",
721 r
= bus_verify_polkit_async(
723 "org.freedesktop.machine1.manage-machines",
730 return 1; /* Will call us back */
732 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
733 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
735 /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
736 * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
738 result_fd
= open_tmpfile_unlinkable(NULL
, O_RDWR
|O_CLOEXEC
);
742 /* This might be a slow operation, run it asynchronously in a background process */
743 r
= safe_fork("(sd-clean)", FORK_RESET_SIGNALS
, &child
);
745 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
747 _cleanup_hashmap_free_ Hashmap
*images
= NULL
;
752 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
754 images
= hashmap_new(&image_hash_ops
);
760 r
= image_discover(IMAGE_MACHINE
, NULL
, images
);
764 l
= write(result_fd
, &success
, sizeof(success
));
770 HASHMAP_FOREACH(image
, images
) {
772 /* We can't remove vendor images (i.e. those in /usr) */
773 if (IMAGE_IS_VENDOR(image
))
776 if (IMAGE_IS_HOST(image
))
779 if (mode
== REMOVE_HIDDEN
&& !IMAGE_IS_HIDDEN(image
))
782 r
= image_remove(image
);
783 if (r
== -EBUSY
) /* keep images that are currently being used. */
786 /* If the operation failed, let's override everything we wrote, and instead write there at which image we failed. */
788 (void) ftruncate(result_fd
, 0);
789 (void) lseek(result_fd
, 0, SEEK_SET
);
790 (void) write(result_fd
, &success
, sizeof(success
));
791 (void) write(result_fd
, image
->name
, strlen(image
->name
)+1);
795 l
= write(result_fd
, image
->name
, strlen(image
->name
)+1);
801 l
= write(result_fd
, &image
->usage_exclusive
, sizeof(image
->usage_exclusive
));
808 result_fd
= safe_close(result_fd
);
812 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
816 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
818 /* The clean-up might take a while, hence install a watch on the child and return */
820 r
= operation_new(m
, NULL
, child
, message
, errno_pipe_fd
[0], &operation
);
822 (void) sigkill_wait(child
);
826 operation
->extra_fd
= result_fd
;
827 operation
->done
= clean_pool_done
;
830 errno_pipe_fd
[0] = -EBADF
;
835 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
836 Manager
*m
= userdata
;
842 r
= sd_bus_message_read(message
, "t", &limit
);
845 if (!FILE_SIZE_VALID_OR_INFINITY(limit
))
846 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "New limit out of range");
848 const char *details
[] = {
849 "verb", "set_pool_limit",
853 r
= bus_verify_polkit_async(
855 "org.freedesktop.machine1.manage-machines",
862 return 1; /* Will call us back */
864 /* Set up the machine directory if necessary */
865 r
= setup_machine_directory(error
, /* use_btrfs_subvol= */ true, /* use_btrfs_quota= */ true);
869 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit
);
871 r
= btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit
);
873 return sd_bus_error_set(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
875 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
877 return sd_bus_reply_method_return(message
, NULL
);
880 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
881 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_set_limit
);
884 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
885 Manager
*m
= userdata
;
892 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
896 if (!uid_is_valid(uid
))
897 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
899 machine
= hashmap_get(m
->machines
, name
);
901 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
903 if (machine
->class != MACHINE_CONTAINER
)
904 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
906 r
= machine_translate_uid(machine
, uid
, &converted
);
908 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
912 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
915 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
916 _cleanup_free_
char *o
= NULL
;
917 Manager
*m
= userdata
;
919 uid_t uid
, converted
;
922 r
= sd_bus_message_read(message
, "u", &uid
);
925 if (!uid_is_valid(uid
))
926 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
928 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
930 r
= manager_find_machine_for_uid(m
, uid
, &machine
, &converted
);
934 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
936 o
= machine_bus_path(machine
);
940 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
943 static int method_map_from_machine_group(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
944 Manager
*m
= userdata
;
951 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
955 if (!gid_is_valid(gid
))
956 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
958 machine
= hashmap_get(m
->machines
, name
);
960 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
962 if (machine
->class != MACHINE_CONTAINER
)
963 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
965 r
= machine_translate_gid(machine
, gid
, &converted
);
967 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
971 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
974 static int method_map_to_machine_group(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
975 _cleanup_free_
char *o
= NULL
;
976 Manager
*m
= userdata
;
978 gid_t gid
, converted
;
981 r
= sd_bus_message_read(message
, "u", &gid
);
984 if (!gid_is_valid(gid
))
985 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
987 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
989 r
= manager_find_machine_for_gid(m
, gid
, &machine
, &converted
);
993 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
995 o
= machine_bus_path(machine
);
999 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1002 const sd_bus_vtable manager_vtable
[] = {
1003 SD_BUS_VTABLE_START(0),
1005 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1006 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1007 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1009 SD_BUS_METHOD_WITH_ARGS("GetMachine",
1010 SD_BUS_ARGS("s", name
),
1011 SD_BUS_RESULT("o", machine
),
1013 SD_BUS_VTABLE_UNPRIVILEGED
),
1014 SD_BUS_METHOD_WITH_ARGS("GetImage",
1015 SD_BUS_ARGS("s", name
),
1016 SD_BUS_RESULT("o", image
),
1018 SD_BUS_VTABLE_UNPRIVILEGED
),
1019 SD_BUS_METHOD_WITH_ARGS("GetMachineByPID",
1020 SD_BUS_ARGS("u", pid
),
1021 SD_BUS_RESULT("o", machine
),
1022 method_get_machine_by_pid
,
1023 SD_BUS_VTABLE_UNPRIVILEGED
),
1024 SD_BUS_METHOD_WITH_ARGS("ListMachines",
1026 SD_BUS_RESULT("a(ssso)", machines
),
1027 method_list_machines
,
1028 SD_BUS_VTABLE_UNPRIVILEGED
),
1029 SD_BUS_METHOD_WITH_ARGS("ListImages",
1031 SD_BUS_RESULT("a(ssbttto)", images
),
1033 SD_BUS_VTABLE_UNPRIVILEGED
),
1034 SD_BUS_METHOD_WITH_ARGS("CreateMachine",
1035 SD_BUS_ARGS("s", name
, "ay", id
, "s", service
, "s", class, "u", leader
, "s", root_directory
, "a(sv)", scope_properties
),
1036 SD_BUS_RESULT("o", path
),
1037 method_create_machine
, 0),
1038 SD_BUS_METHOD_WITH_ARGS("CreateMachineWithNetwork",
1039 SD_BUS_ARGS("s", name
, "ay", id
, "s", service
, "s", class, "u", leader
, "s", root_directory
, "ai", ifindices
, "a(sv)", scope_properties
),
1040 SD_BUS_RESULT("o", path
),
1041 method_create_machine_with_network
, 0),
1042 SD_BUS_METHOD_WITH_ARGS("RegisterMachine",
1043 SD_BUS_ARGS("s", name
, "ay", id
, "s", service
, "s", class, "u", leader
, "s", root_directory
),
1044 SD_BUS_RESULT("o", path
),
1045 method_register_machine
, 0),
1046 SD_BUS_METHOD_WITH_ARGS("RegisterMachineWithNetwork",
1047 SD_BUS_ARGS("s", name
, "ay", id
, "s", service
, "s", class, "u", leader
, "s", root_directory
, "ai", ifindices
),
1048 SD_BUS_RESULT("o", path
),
1049 method_register_machine_with_network
, 0),
1050 SD_BUS_METHOD_WITH_ARGS("UnregisterMachine",
1051 SD_BUS_ARGS("s", name
),
1053 method_unregister_machine
,
1054 SD_BUS_VTABLE_UNPRIVILEGED
),
1055 SD_BUS_METHOD_WITH_ARGS("TerminateMachine",
1056 SD_BUS_ARGS("s", id
),
1058 method_terminate_machine
,
1059 SD_BUS_VTABLE_UNPRIVILEGED
),
1060 SD_BUS_METHOD_WITH_ARGS("KillMachine",
1061 SD_BUS_ARGS("s", name
, "s", who
, "i", signal
),
1063 method_kill_machine
,
1064 SD_BUS_VTABLE_UNPRIVILEGED
),
1065 SD_BUS_METHOD_WITH_ARGS("GetMachineAddresses",
1066 SD_BUS_ARGS("s", name
),
1067 SD_BUS_RESULT("a(iay)", addresses
),
1068 method_get_machine_addresses
,
1069 SD_BUS_VTABLE_UNPRIVILEGED
),
1070 SD_BUS_METHOD_WITH_ARGS("GetMachineOSRelease",
1071 SD_BUS_ARGS("s", name
),
1072 SD_BUS_RESULT("a{ss}", fields
),
1073 method_get_machine_os_release
,
1074 SD_BUS_VTABLE_UNPRIVILEGED
),
1075 SD_BUS_METHOD_WITH_ARGS("OpenMachinePTY",
1076 SD_BUS_ARGS("s", name
),
1077 SD_BUS_RESULT("h", pty
, "s", pty_path
),
1078 method_open_machine_pty
,
1080 SD_BUS_METHOD_WITH_ARGS("OpenMachineLogin",
1081 SD_BUS_ARGS("s", name
),
1082 SD_BUS_RESULT("h", pty
, "s", pty_path
),
1083 method_open_machine_login
,
1084 SD_BUS_VTABLE_UNPRIVILEGED
),
1085 SD_BUS_METHOD_WITH_ARGS("OpenMachineShell",
1086 SD_BUS_ARGS("s", name
, "s", user
, "s", path
, "as", args
, "as", environment
),
1087 SD_BUS_RESULT("h", pty
, "s", pty_path
),
1088 method_open_machine_shell
,
1089 SD_BUS_VTABLE_UNPRIVILEGED
),
1090 SD_BUS_METHOD_WITH_ARGS("BindMountMachine",
1091 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
, "b", read_only
, "b", mkdir
),
1093 method_bind_mount_machine
,
1094 SD_BUS_VTABLE_UNPRIVILEGED
),
1095 SD_BUS_METHOD_WITH_ARGS("CopyFromMachine",
1096 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
),
1098 method_copy_machine
,
1099 SD_BUS_VTABLE_UNPRIVILEGED
),
1100 SD_BUS_METHOD_WITH_ARGS("CopyToMachine",
1101 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
),
1103 method_copy_machine
,
1104 SD_BUS_VTABLE_UNPRIVILEGED
),
1105 SD_BUS_METHOD_WITH_ARGS("CopyFromMachineWithFlags",
1106 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
, "t", flags
),
1108 method_copy_machine
,
1109 SD_BUS_VTABLE_UNPRIVILEGED
),
1110 SD_BUS_METHOD_WITH_ARGS("CopyToMachineWithFlags",
1111 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
, "t", flags
),
1113 method_copy_machine
,
1114 SD_BUS_VTABLE_UNPRIVILEGED
),
1115 SD_BUS_METHOD_WITH_ARGS("OpenMachineRootDirectory",
1116 SD_BUS_ARGS("s", name
),
1117 SD_BUS_RESULT("h", fd
),
1118 method_open_machine_root_directory
,
1119 SD_BUS_VTABLE_UNPRIVILEGED
),
1120 SD_BUS_METHOD_WITH_ARGS("GetMachineUIDShift",
1121 SD_BUS_ARGS("s", name
),
1122 SD_BUS_RESULT("u", shift
),
1123 method_get_machine_uid_shift
,
1124 SD_BUS_VTABLE_UNPRIVILEGED
),
1125 SD_BUS_METHOD_WITH_ARGS("RemoveImage",
1126 SD_BUS_ARGS("s", name
),
1128 method_remove_image
,
1129 SD_BUS_VTABLE_UNPRIVILEGED
),
1130 SD_BUS_METHOD_WITH_ARGS("RenameImage",
1131 SD_BUS_ARGS("s", name
, "s", new_name
),
1133 method_rename_image
,
1134 SD_BUS_VTABLE_UNPRIVILEGED
),
1135 SD_BUS_METHOD_WITH_ARGS("CloneImage",
1136 SD_BUS_ARGS("s", name
, "s", new_name
, "b", read_only
),
1139 SD_BUS_VTABLE_UNPRIVILEGED
),
1140 SD_BUS_METHOD_WITH_ARGS("MarkImageReadOnly",
1141 SD_BUS_ARGS("s", name
, "b", read_only
),
1143 method_mark_image_read_only
,
1144 SD_BUS_VTABLE_UNPRIVILEGED
),
1145 SD_BUS_METHOD_WITH_ARGS("GetImageHostname",
1146 SD_BUS_ARGS("s", name
),
1147 SD_BUS_RESULT("s", hostname
),
1148 method_get_image_hostname
,
1149 SD_BUS_VTABLE_UNPRIVILEGED
),
1150 SD_BUS_METHOD_WITH_ARGS("GetImageMachineID",
1151 SD_BUS_ARGS("s", name
),
1152 SD_BUS_RESULT("ay", id
),
1153 method_get_image_machine_id
,
1154 SD_BUS_VTABLE_UNPRIVILEGED
),
1155 SD_BUS_METHOD_WITH_ARGS("GetImageMachineInfo",
1156 SD_BUS_ARGS("s", name
),
1157 SD_BUS_RESULT("a{ss}", machine_info
),
1158 method_get_image_machine_info
,
1159 SD_BUS_VTABLE_UNPRIVILEGED
),
1160 SD_BUS_METHOD_WITH_ARGS("GetImageOSRelease",
1161 SD_BUS_ARGS("s", name
),
1162 SD_BUS_RESULT("a{ss}", os_release
),
1163 method_get_image_os_release
,
1164 SD_BUS_VTABLE_UNPRIVILEGED
),
1165 SD_BUS_METHOD_WITH_ARGS("SetPoolLimit",
1166 SD_BUS_ARGS("t", size
),
1168 method_set_pool_limit
,
1169 SD_BUS_VTABLE_UNPRIVILEGED
),
1170 SD_BUS_METHOD_WITH_ARGS("SetImageLimit",
1171 SD_BUS_ARGS("s", name
, "t", size
),
1173 method_set_image_limit
,
1174 SD_BUS_VTABLE_UNPRIVILEGED
),
1175 SD_BUS_METHOD_WITH_ARGS("CleanPool",
1176 SD_BUS_ARGS("s", mode
),
1177 SD_BUS_RESULT("a(st)",images
),
1179 SD_BUS_VTABLE_UNPRIVILEGED
),
1180 SD_BUS_METHOD_WITH_ARGS("MapFromMachineUser",
1181 SD_BUS_ARGS("s", name
, "u", uid_inner
),
1182 SD_BUS_RESULT("u", uid_outer
),
1183 method_map_from_machine_user
,
1184 SD_BUS_VTABLE_UNPRIVILEGED
),
1185 SD_BUS_METHOD_WITH_ARGS("MapToMachineUser",
1186 SD_BUS_ARGS("u", uid_outer
),
1187 SD_BUS_RESULT("s", machine_name
, "o", machine_path
, "u", uid_inner
),
1188 method_map_to_machine_user
,
1189 SD_BUS_VTABLE_UNPRIVILEGED
),
1190 SD_BUS_METHOD_WITH_ARGS("MapFromMachineGroup",
1191 SD_BUS_ARGS("s", name
, "u", gid_inner
),
1192 SD_BUS_RESULT("u", gid_outer
),
1193 method_map_from_machine_group
,
1194 SD_BUS_VTABLE_UNPRIVILEGED
),
1195 SD_BUS_METHOD_WITH_ARGS("MapToMachineGroup",
1196 SD_BUS_ARGS("u", gid_outer
),
1197 SD_BUS_RESULT("s", machine_name
, "o", machine_path
, "u", gid_inner
),
1198 method_map_to_machine_group
,
1199 SD_BUS_VTABLE_UNPRIVILEGED
),
1201 SD_BUS_SIGNAL_WITH_ARGS("MachineNew",
1202 SD_BUS_ARGS("s", machine
, "o", path
),
1204 SD_BUS_SIGNAL_WITH_ARGS("MachineRemoved",
1205 SD_BUS_ARGS("s", machine
, "o", path
),
1211 const BusObjectImplementation manager_object
= {
1212 "/org/freedesktop/machine1",
1213 "org.freedesktop.machine1.Manager",
1214 .vtables
= BUS_VTABLES(manager_vtable
),
1215 .children
= BUS_IMPLEMENTATIONS( &machine_object
,
1219 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1220 const char *path
, *result
, *unit
;
1221 Manager
*m
= ASSERT_PTR(userdata
);
1228 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1230 bus_log_parse_error(r
);
1234 machine
= hashmap_get(m
->machine_units
, unit
);
1238 if (streq_ptr(path
, machine
->scope_job
)) {
1239 machine
->scope_job
= mfree(machine
->scope_job
);
1241 if (machine
->started
) {
1242 if (streq(result
, "done"))
1243 machine_send_create_reply(machine
, NULL
);
1245 _cleanup_(sd_bus_error_free
) sd_bus_error e
= SD_BUS_ERROR_NULL
;
1247 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1249 machine_send_create_reply(machine
, &e
);
1253 machine_save(machine
);
1256 machine_add_to_gc_queue(machine
);
1260 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1261 _cleanup_free_
char *unit
= NULL
;
1263 Manager
*m
= ASSERT_PTR(userdata
);
1269 path
= sd_bus_message_get_path(message
);
1273 r
= unit_name_from_dbus_path(path
, &unit
);
1274 if (r
== -EINVAL
) /* not for a unit */
1281 machine
= hashmap_get(m
->machine_units
, unit
);
1285 machine_add_to_gc_queue(machine
);
1289 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1290 const char *path
, *unit
;
1291 Manager
*m
= ASSERT_PTR(userdata
);
1297 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1299 bus_log_parse_error(r
);
1303 machine
= hashmap_get(m
->machine_units
, unit
);
1307 machine_add_to_gc_queue(machine
);
1311 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1312 Manager
*m
= ASSERT_PTR(userdata
);
1318 r
= sd_bus_message_read(message
, "b", &b
);
1320 bus_log_parse_error(r
);
1326 /* systemd finished reloading, let's recheck all our machines */
1327 log_debug("System manager has been reloaded, rechecking machines...");
1329 HASHMAP_FOREACH(machine
, m
->machines
)
1330 machine_add_to_gc_queue(machine
);
1335 int manager_unref_unit(
1338 sd_bus_error
*error
) {
1343 return bus_call_method(m
->bus
, bus_systemd_mgr
, "UnrefUnit", error
, NULL
, "s", unit
);
1346 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1347 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1353 r
= bus_call_method(manager
->bus
, bus_systemd_mgr
, "StopUnit", error
, &reply
, "ss", unit
, "fail");
1355 if (sd_bus_error_has_names(error
, BUS_ERROR_NO_SUCH_UNIT
,
1356 BUS_ERROR_LOAD_FAILED
)) {
1361 sd_bus_error_free(error
);
1372 r
= sd_bus_message_read(reply
, "o", &j
);
1386 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1390 return bus_call_method(manager
->bus
, bus_systemd_mgr
, "KillUnit", error
, NULL
, "ssi", unit
, "all", signo
);
1393 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1394 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1395 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1396 _cleanup_free_
char *path
= NULL
;
1403 path
= unit_dbus_path_from_name(unit
);
1407 r
= sd_bus_get_property(
1409 "org.freedesktop.systemd1",
1411 "org.freedesktop.systemd1.Unit",
1417 if (sd_bus_error_has_names(&error
, SD_BUS_ERROR_NO_REPLY
,
1418 SD_BUS_ERROR_DISCONNECTED
))
1421 if (sd_bus_error_has_names(&error
, BUS_ERROR_NO_SUCH_UNIT
,
1422 BUS_ERROR_LOAD_FAILED
))
1428 r
= sd_bus_message_read(reply
, "s", &state
);
1432 return !STR_IN_SET(state
, "inactive", "failed");
1435 int manager_job_is_active(Manager
*manager
, const char *path
) {
1436 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1437 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1443 r
= sd_bus_get_property(
1445 "org.freedesktop.systemd1",
1447 "org.freedesktop.systemd1.Job",
1453 if (sd_bus_error_has_names(&error
, SD_BUS_ERROR_NO_REPLY
,
1454 SD_BUS_ERROR_DISCONNECTED
))
1457 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1463 /* We don't actually care about the state really. The fact
1464 * that we could read the job state is enough for us */
1469 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1477 mm
= hashmap_get(m
->machine_leaders
, PID_TO_PTR(pid
));
1479 _cleanup_free_
char *unit
= NULL
;
1481 r
= cg_pid_get_unit(pid
, &unit
);
1483 mm
= hashmap_get(m
->machine_units
, unit
);
1492 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1499 machine
= hashmap_get(m
->machines
, name
);
1501 r
= machine_new(m
, _MACHINE_CLASS_INVALID
, name
, &machine
);
1507 *_machine
= machine
;