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-message-util.h"
14 #include "bus-object.h"
15 #include "bus-polkit.h"
17 #include "cgroup-util.h"
18 #include "discover-image.h"
19 #include "errno-util.h"
22 #include "format-util.h"
24 #include "hostname-util.h"
26 #include "image-dbus.h"
29 #include "machine-dbus.h"
30 #include "machine-pool.h"
32 #include "operation.h"
34 #include "path-util.h"
35 #include "string-util.h"
38 #include "user-util.h"
40 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_pool_path
, "s", "/var/lib/machines");
42 static int property_get_pool_usage(
45 const char *interface
,
47 sd_bus_message
*reply
,
49 sd_bus_error
*error
) {
51 _cleanup_close_
int fd
= -EBADF
;
52 uint64_t usage
= UINT64_MAX
;
57 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
61 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
65 return sd_bus_message_append(reply
, "t", usage
);
68 static int property_get_pool_limit(
71 const char *interface
,
73 sd_bus_message
*reply
,
75 sd_bus_error
*error
) {
77 _cleanup_close_
int fd
= -EBADF
;
78 uint64_t size
= UINT64_MAX
;
83 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
87 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
88 size
= q
.referenced_max
;
91 return sd_bus_message_append(reply
, "t", size
);
94 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
95 _cleanup_free_
char *p
= NULL
;
96 Manager
*m
= ASSERT_PTR(userdata
);
103 r
= sd_bus_message_read(message
, "s", &name
);
107 machine
= hashmap_get(m
->machines
, name
);
109 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
111 p
= machine_bus_path(machine
);
115 return sd_bus_reply_method_return(message
, "o", p
);
118 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
119 _cleanup_free_
char *p
= NULL
;
120 _unused_ Manager
*m
= ASSERT_PTR(userdata
);
126 r
= sd_bus_message_read(message
, "s", &name
);
130 r
= image_find(m
->runtime_scope
, IMAGE_MACHINE
, name
, NULL
, NULL
);
132 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
136 p
= image_bus_path(name
);
140 return sd_bus_reply_method_return(message
, "o", p
);
143 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
144 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
145 _cleanup_free_
char *p
= NULL
;
146 Manager
*m
= ASSERT_PTR(userdata
);
147 Machine
*machine
= NULL
;
153 assert_cc(sizeof(pid_t
) == sizeof(uint32_t));
155 r
= sd_bus_message_read(message
, "u", &pid
);
162 pidref
= PIDREF_MAKE_FROM_PID(pid
);
165 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
167 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
|SD_BUS_CREDS_PIDFD
, &creds
);
171 r
= bus_creds_get_pidref(creds
, &pidref
);
176 r
= manager_get_machine_by_pidref(m
, &pidref
, &machine
);
180 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
182 p
= machine_bus_path(machine
);
186 return sd_bus_reply_method_return(message
, "o", p
);
189 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
190 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
191 Manager
*m
= ASSERT_PTR(userdata
);
197 r
= sd_bus_message_new_method_return(message
, &reply
);
199 return sd_bus_error_set_errno(error
, r
);
201 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
203 return sd_bus_error_set_errno(error
, r
);
205 HASHMAP_FOREACH(machine
, m
->machines
) {
206 _cleanup_free_
char *p
= NULL
;
208 p
= machine_bus_path(machine
);
212 r
= sd_bus_message_append(reply
, "(ssso)",
214 strempty(machine_class_to_string(machine
->class)),
218 return sd_bus_error_set_errno(error
, r
);
221 r
= sd_bus_message_close_container(reply
);
223 return sd_bus_error_set_errno(error
, r
);
225 return sd_bus_message_send(reply
);
228 static int method_create_or_register_machine(
230 sd_bus_message
*message
,
233 sd_bus_error
*error
) {
235 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
236 const char *name
, *service
, *class, *root_directory
;
237 const int32_t *netif
= NULL
;
249 r
= sd_bus_message_read(message
, "s", &name
);
252 if (!hostname_is_valid(name
, 0))
253 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
255 r
= bus_message_read_id128(message
, &id
);
257 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
259 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
264 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
268 n_netif
/= sizeof(int32_t);
270 for (size_t i
= 0; i
< n_netif
; i
++) {
272 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
277 c
= _MACHINE_CLASS_INVALID
;
279 c
= machine_class_from_string(class);
281 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
285 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
287 if (!isempty(root_directory
) && (!path_is_absolute(root_directory
) || !path_is_valid(root_directory
)))
288 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
291 r
= bus_query_sender_pidref(message
, &pidref
);
293 return sd_bus_error_set_errnof(error
, r
, "Failed to pin client process: %m");
295 r
= pidref_set_pid(&pidref
, leader
);
297 return sd_bus_error_set_errnof(error
, r
, "Failed to pin process " PID_FMT
": %m", (pid_t
) leader
);
300 if (hashmap_get(manager
->machines
, name
))
301 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
303 const char *details
[] = {
305 "class", machine_class_to_string(c
),
309 r
= bus_verify_polkit_async(
311 "org.freedesktop.machine1.create-machine",
313 &manager
->polkit_registry
,
318 return 0; /* Will call us back */
320 r
= manager_add_machine(manager
, name
, &m
);
324 m
->leader
= TAKE_PIDREF(pidref
);
328 if (!isempty(service
)) {
329 m
->service
= strdup(service
);
336 if (!isempty(root_directory
)) {
337 m
->root_directory
= strdup(root_directory
);
338 if (!m
->root_directory
) {
345 assert_cc(sizeof(int32_t) == sizeof(int));
346 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
352 m
->n_netif
= n_netif
;
359 machine_add_to_gc_queue(m
);
363 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
364 Manager
*manager
= ASSERT_PTR(userdata
);
370 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
374 return 1; /* Will call us back */
376 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
380 r
= machine_start(m
, message
, error
);
384 m
->create_message
= sd_bus_message_ref(message
);
388 machine_add_to_gc_queue(m
);
392 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
393 return method_create_machine_internal(message
, true, userdata
, error
);
396 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
397 return method_create_machine_internal(message
, false, userdata
, error
);
400 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
401 Manager
*manager
= ASSERT_PTR(userdata
);
402 _cleanup_free_
char *p
= NULL
;
408 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
412 return 1; /* Will call us back */
414 r
= cg_pidref_get_unit(&m
->leader
, &m
->unit
);
416 r
= sd_bus_error_set_errnof(error
, r
,
417 "Failed to determine unit of process "PID_FMT
" : %m",
422 r
= machine_start(m
, NULL
, error
);
426 p
= machine_bus_path(m
);
432 return sd_bus_reply_method_return(message
, "o", p
);
435 machine_add_to_gc_queue(m
);
439 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
440 return method_register_machine_internal(message
, true, userdata
, error
);
443 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
444 return method_register_machine_internal(message
, false, userdata
, error
);
447 static int redirect_method_to_machine(sd_bus_message
*message
, Manager
*m
, sd_bus_error
*error
, sd_bus_message_handler_t method
) {
456 r
= sd_bus_message_read(message
, "s", &name
);
458 return sd_bus_error_set_errno(error
, r
);
460 machine
= hashmap_get(m
->machines
, name
);
462 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
464 return method(message
, machine
, error
);
467 static int method_unregister_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
468 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_unregister
);
471 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
472 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_terminate
);
475 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
476 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_kill
);
479 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
480 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_addresses
);
483 static int method_get_machine_ssh_info(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
484 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_ssh_info
);
487 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
488 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_os_release
);
491 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
492 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
493 Manager
*m
= ASSERT_PTR(userdata
);
498 _cleanup_hashmap_free_ Hashmap
*images
= NULL
;
499 r
= image_discover(m
->runtime_scope
, IMAGE_MACHINE
, NULL
, &images
);
503 r
= sd_bus_message_new_method_return(message
, &reply
);
507 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
512 HASHMAP_FOREACH(image
, images
) {
513 _cleanup_free_
char *p
= NULL
;
515 p
= image_bus_path(image
->name
);
519 r
= sd_bus_message_append(reply
, "(ssbttto)",
521 image_type_to_string(image
->type
),
531 r
= sd_bus_message_close_container(reply
);
535 return sd_bus_message_send(reply
);
538 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
539 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_pty
);
542 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
543 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_login
);
546 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
547 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_shell
);
550 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
551 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_bind_mount
);
554 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
555 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_copy
);
558 static int method_open_machine_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
559 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_root_directory
);
562 static int method_get_machine_uid_shift(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
563 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_uid_shift
);
566 static int redirect_method_to_image(sd_bus_message
*message
, Manager
*m
, sd_bus_error
*error
, sd_bus_message_handler_t method
) {
575 r
= sd_bus_message_read(message
, "s", &name
);
579 if (!image_name_is_valid(name
))
580 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
582 r
= manager_acquire_image(m
, name
, &i
);
584 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
588 return method(message
, i
, error
);
591 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
592 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_remove
);
595 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
596 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_rename
);
599 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
600 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_clone
);
603 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
604 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_mark_read_only
);
607 static int method_get_image_hostname(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
608 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_hostname
);
611 static int method_get_image_machine_id(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
612 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_machine_id
);
615 static int method_get_image_machine_info(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
616 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_machine_info
);
619 static int method_get_image_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
620 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_os_release
);
623 static int clean_pool_done(Operation
*operation
, int child_error
, sd_bus_error
*error
) {
624 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
625 _cleanup_fclose_
FILE *file
= NULL
;
629 assert(operation
->message
);
630 assert(operation
->extra_fd
>= 0);
632 file
= take_fdopen(&operation
->extra_fd
, "r");
634 return log_debug_errno(errno
, "Failed to take opened tmp file's fd: %m");
636 r
= clean_pool_read_first_entry(file
, child_error
, error
);
640 r
= sd_bus_message_new_method_return(operation
->message
, &reply
);
644 r
= sd_bus_message_open_container(reply
, 'a', "(st)");
648 /* On success the resulting temporary file will contain a list of image names that were removed followed by
649 * their size on disk. Let's read that and turn it into a bus message. */
651 _cleanup_free_
char *name
= NULL
;
654 r
= clean_pool_read_next_entry(file
, &name
, &usage
);
660 r
= sd_bus_message_append(reply
, "(st)", name
, usage
);
665 r
= sd_bus_message_close_container(reply
);
669 return sd_bus_message_send(reply
);
672 static int method_clean_pool(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
673 ImageCleanPoolMode mode
;
674 Manager
*m
= userdata
;
675 Operation
*operation
;
681 if (m
->n_operations
>= OPERATIONS_MAX
)
682 return sd_bus_error_set(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing operations.");
684 r
= sd_bus_message_read(message
, "s", &mm
);
688 if (streq(mm
, "all"))
689 mode
= IMAGE_CLEAN_POOL_REMOVE_ALL
;
690 else if (streq(mm
, "hidden"))
691 mode
= IMAGE_CLEAN_POOL_REMOVE_HIDDEN
;
693 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown mode '%s'.", mm
);
695 const char *details
[] = {
696 "verb", "clean_pool",
701 r
= bus_verify_polkit_async(
703 "org.freedesktop.machine1.manage-machines",
710 return 1; /* Will call us back */
712 r
= image_clean_pool_operation(m
, mode
, &operation
);
714 return log_debug_errno(r
, "Failed to clean pool of images: %m");
716 operation_attach_bus_reply(operation
, message
);
717 operation
->done
= clean_pool_done
;
721 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
722 Manager
*m
= userdata
;
728 r
= sd_bus_message_read(message
, "t", &limit
);
731 if (!FILE_SIZE_VALID_OR_INFINITY(limit
))
732 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "New limit out of range");
734 const char *details
[] = {
735 "verb", "set_pool_limit",
739 r
= bus_verify_polkit_async(
741 "org.freedesktop.machine1.manage-machines",
748 return 1; /* Will call us back */
750 /* Set up the machine directory if necessary */
751 r
= setup_machine_directory(error
, /* use_btrfs_subvol= */ true, /* use_btrfs_quota= */ true);
755 r
= image_set_pool_limit(IMAGE_MACHINE
, limit
);
756 if (ERRNO_IS_NEG_NOT_SUPPORTED(r
))
757 return sd_bus_error_set(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
759 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
761 return sd_bus_reply_method_return(message
, NULL
);
764 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
765 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_set_limit
);
768 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
769 Manager
*m
= userdata
;
776 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
780 if (!uid_is_valid(uid
))
781 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
783 machine
= hashmap_get(m
->machines
, name
);
785 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
787 if (machine
->class != MACHINE_CONTAINER
)
788 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
790 r
= machine_translate_uid(machine
, uid
, &converted
);
792 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
796 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
799 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
800 _cleanup_free_
char *o
= NULL
;
801 Manager
*m
= userdata
;
803 uid_t uid
, converted
;
806 r
= sd_bus_message_read(message
, "u", &uid
);
809 if (!uid_is_valid(uid
))
810 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
812 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
814 r
= manager_find_machine_for_uid(m
, uid
, &machine
, &converted
);
818 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
820 o
= machine_bus_path(machine
);
824 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
827 static int method_map_from_machine_group(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
828 Manager
*m
= userdata
;
835 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
839 if (!gid_is_valid(gid
))
840 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
842 machine
= hashmap_get(m
->machines
, name
);
844 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
846 if (machine
->class != MACHINE_CONTAINER
)
847 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
849 r
= machine_translate_gid(machine
, gid
, &converted
);
851 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
855 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
858 static int method_map_to_machine_group(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
859 _cleanup_free_
char *o
= NULL
;
860 Manager
*m
= userdata
;
862 gid_t gid
, converted
;
865 r
= sd_bus_message_read(message
, "u", &gid
);
868 if (!gid_is_valid(gid
))
869 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
871 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
873 r
= manager_find_machine_for_gid(m
, gid
, &machine
, &converted
);
877 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
879 o
= machine_bus_path(machine
);
883 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
886 const sd_bus_vtable manager_vtable
[] = {
887 SD_BUS_VTABLE_START(0),
889 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
890 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
891 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
893 SD_BUS_METHOD_WITH_ARGS("GetMachine",
894 SD_BUS_ARGS("s", name
),
895 SD_BUS_RESULT("o", machine
),
897 SD_BUS_VTABLE_UNPRIVILEGED
),
898 SD_BUS_METHOD_WITH_ARGS("GetImage",
899 SD_BUS_ARGS("s", name
),
900 SD_BUS_RESULT("o", image
),
902 SD_BUS_VTABLE_UNPRIVILEGED
),
903 SD_BUS_METHOD_WITH_ARGS("GetMachineByPID",
904 SD_BUS_ARGS("u", pid
),
905 SD_BUS_RESULT("o", machine
),
906 method_get_machine_by_pid
,
907 SD_BUS_VTABLE_UNPRIVILEGED
),
908 SD_BUS_METHOD_WITH_ARGS("ListMachines",
910 SD_BUS_RESULT("a(ssso)", machines
),
911 method_list_machines
,
912 SD_BUS_VTABLE_UNPRIVILEGED
),
913 SD_BUS_METHOD_WITH_ARGS("ListImages",
915 SD_BUS_RESULT("a(ssbttto)", images
),
917 SD_BUS_VTABLE_UNPRIVILEGED
),
918 SD_BUS_METHOD_WITH_ARGS("CreateMachine",
919 SD_BUS_ARGS("s", name
, "ay", id
, "s", service
, "s", class, "u", leader
, "s", root_directory
, "a(sv)", scope_properties
),
920 SD_BUS_RESULT("o", path
),
921 method_create_machine
,
922 SD_BUS_VTABLE_UNPRIVILEGED
),
923 SD_BUS_METHOD_WITH_ARGS("CreateMachineWithNetwork",
924 SD_BUS_ARGS("s", name
, "ay", id
, "s", service
, "s", class, "u", leader
, "s", root_directory
, "ai", ifindices
, "a(sv)", scope_properties
),
925 SD_BUS_RESULT("o", path
),
926 method_create_machine_with_network
,
927 SD_BUS_VTABLE_UNPRIVILEGED
),
928 SD_BUS_METHOD_WITH_ARGS("RegisterMachine",
929 SD_BUS_ARGS("s", name
, "ay", id
, "s", service
, "s", class, "u", leader
, "s", root_directory
),
930 SD_BUS_RESULT("o", path
),
931 method_register_machine
,
932 SD_BUS_VTABLE_UNPRIVILEGED
),
933 SD_BUS_METHOD_WITH_ARGS("RegisterMachineWithNetwork",
934 SD_BUS_ARGS("s", name
, "ay", id
, "s", service
, "s", class, "u", leader
, "s", root_directory
, "ai", ifindices
),
935 SD_BUS_RESULT("o", path
),
936 method_register_machine_with_network
,
937 SD_BUS_VTABLE_UNPRIVILEGED
),
938 SD_BUS_METHOD_WITH_ARGS("UnregisterMachine",
939 SD_BUS_ARGS("s", name
),
941 method_unregister_machine
,
942 SD_BUS_VTABLE_UNPRIVILEGED
),
943 SD_BUS_METHOD_WITH_ARGS("TerminateMachine",
944 SD_BUS_ARGS("s", id
),
946 method_terminate_machine
,
947 SD_BUS_VTABLE_UNPRIVILEGED
),
948 SD_BUS_METHOD_WITH_ARGS("KillMachine",
949 SD_BUS_ARGS("s", name
, "s", whom
, "i", signal
),
952 SD_BUS_VTABLE_UNPRIVILEGED
),
953 SD_BUS_METHOD_WITH_ARGS("GetMachineAddresses",
954 SD_BUS_ARGS("s", name
),
955 SD_BUS_RESULT("a(iay)", addresses
),
956 method_get_machine_addresses
,
957 SD_BUS_VTABLE_UNPRIVILEGED
),
958 SD_BUS_METHOD_WITH_ARGS("GetMachineSSHInfo",
959 SD_BUS_ARGS("s", name
),
960 SD_BUS_RESULT("s", ssh_address
, "s", ssh_private_key_path
),
961 method_get_machine_ssh_info
,
962 SD_BUS_VTABLE_UNPRIVILEGED
),
963 SD_BUS_METHOD_WITH_ARGS("GetMachineOSRelease",
964 SD_BUS_ARGS("s", name
),
965 SD_BUS_RESULT("a{ss}", fields
),
966 method_get_machine_os_release
,
967 SD_BUS_VTABLE_UNPRIVILEGED
),
968 SD_BUS_METHOD_WITH_ARGS("OpenMachinePTY",
969 SD_BUS_ARGS("s", name
),
970 SD_BUS_RESULT("h", pty
, "s", pty_path
),
971 method_open_machine_pty
,
972 SD_BUS_VTABLE_UNPRIVILEGED
),
973 SD_BUS_METHOD_WITH_ARGS("OpenMachineLogin",
974 SD_BUS_ARGS("s", name
),
975 SD_BUS_RESULT("h", pty
, "s", pty_path
),
976 method_open_machine_login
,
977 SD_BUS_VTABLE_UNPRIVILEGED
),
978 SD_BUS_METHOD_WITH_ARGS("OpenMachineShell",
979 SD_BUS_ARGS("s", name
, "s", user
, "s", path
, "as", args
, "as", environment
),
980 SD_BUS_RESULT("h", pty
, "s", pty_path
),
981 method_open_machine_shell
,
982 SD_BUS_VTABLE_UNPRIVILEGED
),
983 SD_BUS_METHOD_WITH_ARGS("BindMountMachine",
984 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
, "b", read_only
, "b", mkdir
),
986 method_bind_mount_machine
,
987 SD_BUS_VTABLE_UNPRIVILEGED
),
988 SD_BUS_METHOD_WITH_ARGS("CopyFromMachine",
989 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
),
992 SD_BUS_VTABLE_UNPRIVILEGED
),
993 SD_BUS_METHOD_WITH_ARGS("CopyToMachine",
994 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
),
997 SD_BUS_VTABLE_UNPRIVILEGED
),
998 SD_BUS_METHOD_WITH_ARGS("CopyFromMachineWithFlags",
999 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
, "t", flags
),
1001 method_copy_machine
,
1002 SD_BUS_VTABLE_UNPRIVILEGED
),
1003 SD_BUS_METHOD_WITH_ARGS("CopyToMachineWithFlags",
1004 SD_BUS_ARGS("s", name
, "s", source
, "s", destination
, "t", flags
),
1006 method_copy_machine
,
1007 SD_BUS_VTABLE_UNPRIVILEGED
),
1008 SD_BUS_METHOD_WITH_ARGS("OpenMachineRootDirectory",
1009 SD_BUS_ARGS("s", name
),
1010 SD_BUS_RESULT("h", fd
),
1011 method_open_machine_root_directory
,
1012 SD_BUS_VTABLE_UNPRIVILEGED
),
1013 SD_BUS_METHOD_WITH_ARGS("GetMachineUIDShift",
1014 SD_BUS_ARGS("s", name
),
1015 SD_BUS_RESULT("u", shift
),
1016 method_get_machine_uid_shift
,
1017 SD_BUS_VTABLE_UNPRIVILEGED
),
1018 SD_BUS_METHOD_WITH_ARGS("RemoveImage",
1019 SD_BUS_ARGS("s", name
),
1021 method_remove_image
,
1022 SD_BUS_VTABLE_UNPRIVILEGED
),
1023 SD_BUS_METHOD_WITH_ARGS("RenameImage",
1024 SD_BUS_ARGS("s", name
, "s", new_name
),
1026 method_rename_image
,
1027 SD_BUS_VTABLE_UNPRIVILEGED
),
1028 SD_BUS_METHOD_WITH_ARGS("CloneImage",
1029 SD_BUS_ARGS("s", name
, "s", new_name
, "b", read_only
),
1032 SD_BUS_VTABLE_UNPRIVILEGED
),
1033 SD_BUS_METHOD_WITH_ARGS("MarkImageReadOnly",
1034 SD_BUS_ARGS("s", name
, "b", read_only
),
1036 method_mark_image_read_only
,
1037 SD_BUS_VTABLE_UNPRIVILEGED
),
1038 SD_BUS_METHOD_WITH_ARGS("GetImageHostname",
1039 SD_BUS_ARGS("s", name
),
1040 SD_BUS_RESULT("s", hostname
),
1041 method_get_image_hostname
,
1042 SD_BUS_VTABLE_UNPRIVILEGED
),
1043 SD_BUS_METHOD_WITH_ARGS("GetImageMachineID",
1044 SD_BUS_ARGS("s", name
),
1045 SD_BUS_RESULT("ay", id
),
1046 method_get_image_machine_id
,
1047 SD_BUS_VTABLE_UNPRIVILEGED
),
1048 SD_BUS_METHOD_WITH_ARGS("GetImageMachineInfo",
1049 SD_BUS_ARGS("s", name
),
1050 SD_BUS_RESULT("a{ss}", machine_info
),
1051 method_get_image_machine_info
,
1052 SD_BUS_VTABLE_UNPRIVILEGED
),
1053 SD_BUS_METHOD_WITH_ARGS("GetImageOSRelease",
1054 SD_BUS_ARGS("s", name
),
1055 SD_BUS_RESULT("a{ss}", os_release
),
1056 method_get_image_os_release
,
1057 SD_BUS_VTABLE_UNPRIVILEGED
),
1058 SD_BUS_METHOD_WITH_ARGS("SetPoolLimit",
1059 SD_BUS_ARGS("t", size
),
1061 method_set_pool_limit
,
1062 SD_BUS_VTABLE_UNPRIVILEGED
),
1063 SD_BUS_METHOD_WITH_ARGS("SetImageLimit",
1064 SD_BUS_ARGS("s", name
, "t", size
),
1066 method_set_image_limit
,
1067 SD_BUS_VTABLE_UNPRIVILEGED
),
1068 SD_BUS_METHOD_WITH_ARGS("CleanPool",
1069 SD_BUS_ARGS("s", mode
),
1070 SD_BUS_RESULT("a(st)",images
),
1072 SD_BUS_VTABLE_UNPRIVILEGED
),
1073 SD_BUS_METHOD_WITH_ARGS("MapFromMachineUser",
1074 SD_BUS_ARGS("s", name
, "u", uid_inner
),
1075 SD_BUS_RESULT("u", uid_outer
),
1076 method_map_from_machine_user
,
1077 SD_BUS_VTABLE_UNPRIVILEGED
),
1078 SD_BUS_METHOD_WITH_ARGS("MapToMachineUser",
1079 SD_BUS_ARGS("u", uid_outer
),
1080 SD_BUS_RESULT("s", machine_name
, "o", machine_path
, "u", uid_inner
),
1081 method_map_to_machine_user
,
1082 SD_BUS_VTABLE_UNPRIVILEGED
),
1083 SD_BUS_METHOD_WITH_ARGS("MapFromMachineGroup",
1084 SD_BUS_ARGS("s", name
, "u", gid_inner
),
1085 SD_BUS_RESULT("u", gid_outer
),
1086 method_map_from_machine_group
,
1087 SD_BUS_VTABLE_UNPRIVILEGED
),
1088 SD_BUS_METHOD_WITH_ARGS("MapToMachineGroup",
1089 SD_BUS_ARGS("u", gid_outer
),
1090 SD_BUS_RESULT("s", machine_name
, "o", machine_path
, "u", gid_inner
),
1091 method_map_to_machine_group
,
1092 SD_BUS_VTABLE_UNPRIVILEGED
),
1094 SD_BUS_SIGNAL_WITH_ARGS("MachineNew",
1095 SD_BUS_ARGS("s", machine
, "o", path
),
1097 SD_BUS_SIGNAL_WITH_ARGS("MachineRemoved",
1098 SD_BUS_ARGS("s", machine
, "o", path
),
1104 const BusObjectImplementation manager_object
= {
1105 "/org/freedesktop/machine1",
1106 "org.freedesktop.machine1.Manager",
1107 .vtables
= BUS_VTABLES(manager_vtable
),
1108 .children
= BUS_IMPLEMENTATIONS( &machine_object
,
1112 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1113 const char *path
, *result
, *unit
;
1114 Manager
*m
= ASSERT_PTR(userdata
);
1121 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1123 bus_log_parse_error(r
);
1127 machine
= hashmap_get(m
->machines_by_unit
, unit
);
1131 if (streq_ptr(path
, machine
->scope_job
)) {
1132 machine
->scope_job
= mfree(machine
->scope_job
);
1134 if (machine
->started
) {
1135 if (streq(result
, "done"))
1136 machine_send_create_reply(machine
, NULL
);
1138 _cleanup_(sd_bus_error_free
) sd_bus_error e
= SD_BUS_ERROR_NULL
;
1140 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1142 machine_send_create_reply(machine
, &e
);
1146 machine_save(machine
);
1149 machine_add_to_gc_queue(machine
);
1153 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1154 _cleanup_free_
char *unit
= NULL
;
1156 Manager
*m
= ASSERT_PTR(userdata
);
1162 path
= sd_bus_message_get_path(message
);
1166 r
= unit_name_from_dbus_path(path
, &unit
);
1167 if (r
== -EINVAL
) /* not for a unit */
1174 machine
= hashmap_get(m
->machines_by_unit
, unit
);
1178 machine_add_to_gc_queue(machine
);
1182 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1183 const char *path
, *unit
;
1184 Manager
*m
= ASSERT_PTR(userdata
);
1190 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1192 bus_log_parse_error(r
);
1196 machine
= hashmap_get(m
->machines_by_unit
, unit
);
1200 machine_add_to_gc_queue(machine
);
1204 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1205 Manager
*m
= ASSERT_PTR(userdata
);
1211 r
= sd_bus_message_read(message
, "b", &b
);
1213 bus_log_parse_error(r
);
1219 /* systemd finished reloading, let's recheck all our machines */
1220 log_debug("System manager has been reloaded, rechecking machines...");
1222 HASHMAP_FOREACH(machine
, m
->machines
)
1223 machine_add_to_gc_queue(machine
);
1228 int manager_unref_unit(
1231 sd_bus_error
*error
) {
1236 return bus_call_method(m
->bus
, bus_systemd_mgr
, "UnrefUnit", error
, NULL
, "s", unit
);
1239 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1240 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1246 r
= bus_call_method(manager
->bus
, bus_systemd_mgr
, "StopUnit", error
, &reply
, "ss", unit
, "fail");
1248 if (sd_bus_error_has_names(error
, BUS_ERROR_NO_SUCH_UNIT
,
1249 BUS_ERROR_LOAD_FAILED
)) {
1254 sd_bus_error_free(error
);
1265 r
= sd_bus_message_read(reply
, "o", &j
);
1279 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1283 return bus_call_method(manager
->bus
, bus_systemd_mgr
, "KillUnit", error
, NULL
, "ssi", unit
, "all", signo
);
1286 int manager_unit_is_active(Manager
*manager
, const char *unit
, sd_bus_error
*reterr_error
) {
1287 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1288 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1289 _cleanup_free_
char *path
= NULL
;
1296 path
= unit_dbus_path_from_name(unit
);
1300 r
= sd_bus_get_property(
1302 "org.freedesktop.systemd1",
1304 "org.freedesktop.systemd1.Unit",
1310 if (bus_error_is_connection(&error
))
1313 if (sd_bus_error_has_names(&error
, BUS_ERROR_NO_SUCH_UNIT
,
1314 BUS_ERROR_LOAD_FAILED
))
1317 sd_bus_error_move(reterr_error
, &error
);
1321 r
= sd_bus_message_read(reply
, "s", &state
);
1325 return !STR_IN_SET(state
, "inactive", "failed");
1328 int manager_job_is_active(Manager
*manager
, const char *path
, sd_bus_error
*reterr_error
) {
1329 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1330 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1336 r
= sd_bus_get_property(
1338 "org.freedesktop.systemd1",
1340 "org.freedesktop.systemd1.Job",
1346 if (bus_error_is_connection(&error
))
1349 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1352 sd_bus_error_move(reterr_error
, &error
);
1356 /* We don't actually care about the state really. The fact
1357 * that we could read the job state is enough for us */