1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include "alloc-util.h"
10 #include "btrfs-util.h"
11 #include "bus-common-errors.h"
13 #include "cgroup-util.h"
16 #include "format-util.h"
17 #include "hostname-util.h"
18 #include "image-dbus.h"
20 #include "machine-dbus.h"
21 #include "machine-image.h"
22 #include "machine-pool.h"
24 #include "missing_capability.h"
25 #include "path-util.h"
26 #include "process-util.h"
27 #include "stdio-util.h"
29 #include "tmpfile-util.h"
30 #include "unit-name.h"
31 #include "user-util.h"
33 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_pool_path
, "s", "/var/lib/machines");
35 static int property_get_pool_usage(
38 const char *interface
,
40 sd_bus_message
*reply
,
42 sd_bus_error
*error
) {
44 _cleanup_close_
int fd
= -1;
45 uint64_t usage
= (uint64_t) -1;
50 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
54 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
58 return sd_bus_message_append(reply
, "t", usage
);
61 static int property_get_pool_limit(
64 const char *interface
,
66 sd_bus_message
*reply
,
68 sd_bus_error
*error
) {
70 _cleanup_close_
int fd
= -1;
71 uint64_t size
= (uint64_t) -1;
76 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
80 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
81 size
= q
.referenced_max
;
84 return sd_bus_message_append(reply
, "t", size
);
87 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
88 _cleanup_free_
char *p
= NULL
;
89 Manager
*m
= userdata
;
97 r
= sd_bus_message_read(message
, "s", &name
);
101 machine
= hashmap_get(m
->machines
, name
);
103 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
105 p
= machine_bus_path(machine
);
109 return sd_bus_reply_method_return(message
, "o", p
);
112 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
113 _cleanup_free_
char *p
= NULL
;
114 Manager
*m
= userdata
;
121 r
= sd_bus_message_read(message
, "s", &name
);
125 r
= image_find(IMAGE_MACHINE
, name
, NULL
);
127 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
131 p
= image_bus_path(name
);
135 return sd_bus_reply_method_return(message
, "o", p
);
138 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
139 _cleanup_free_
char *p
= NULL
;
140 Manager
*m
= userdata
;
141 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
= userdata
;
192 r
= sd_bus_message_new_method_return(message
, &reply
);
194 return sd_bus_error_set_errno(error
, r
);
196 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
198 return sd_bus_error_set_errno(error
, r
);
200 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
201 _cleanup_free_
char *p
= NULL
;
203 p
= machine_bus_path(machine
);
207 r
= sd_bus_message_append(reply
, "(ssso)",
209 strempty(machine_class_to_string(machine
->class)),
213 return sd_bus_error_set_errno(error
, r
);
216 r
= sd_bus_message_close_container(reply
);
218 return sd_bus_error_set_errno(error
, r
);
220 return sd_bus_send(NULL
, reply
, NULL
);
223 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
224 const char *name
, *service
, *class, *root_directory
;
225 const int32_t *netif
= NULL
;
231 size_t n
, n_netif
= 0;
238 r
= sd_bus_message_read(message
, "s", &name
);
241 if (!machine_name_is_valid(name
))
242 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
244 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
252 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
254 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
261 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
265 n_netif
/= sizeof(int32_t);
267 for (i
= 0; i
< n_netif
; i
++) {
269 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
274 c
= _MACHINE_CLASS_INVALID
;
276 c
= machine_class_from_string(class);
278 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
282 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
284 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
285 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
288 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
290 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
294 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
296 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
301 if (hashmap_get(manager
->machines
, name
))
302 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
304 r
= manager_add_machine(manager
, name
, &m
);
312 if (!isempty(service
)) {
313 m
->service
= strdup(service
);
320 if (!isempty(root_directory
)) {
321 m
->root_directory
= strdup(root_directory
);
322 if (!m
->root_directory
) {
329 assert_cc(sizeof(int32_t) == sizeof(int));
330 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
336 m
->n_netif
= n_netif
;
344 machine_add_to_gc_queue(m
);
348 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
349 Manager
*manager
= 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
= userdata
;
386 _cleanup_free_
char *p
= NULL
;
393 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
397 r
= cg_pid_get_unit(m
->leader
, &m
->unit
);
399 r
= sd_bus_error_set_errnof(error
, r
,
400 "Failed to determine unit of process "PID_FMT
" : %m",
405 r
= machine_start(m
, NULL
, error
);
409 p
= machine_bus_path(m
);
415 return sd_bus_reply_method_return(message
, "o", p
);
418 machine_add_to_gc_queue(m
);
422 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
423 return method_register_machine_internal(message
, true, userdata
, error
);
426 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
427 return method_register_machine_internal(message
, false, userdata
, error
);
430 static int redirect_method_to_machine(sd_bus_message
*message
, Manager
*m
, sd_bus_error
*error
, sd_bus_message_handler_t method
) {
439 r
= sd_bus_message_read(message
, "s", &name
);
441 return sd_bus_error_set_errno(error
, r
);
443 machine
= hashmap_get(m
->machines
, name
);
445 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
447 return method(message
, machine
, error
);
450 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
451 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_terminate
);
454 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
455 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_kill
);
458 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
459 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_addresses
);
462 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
463 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_os_release
);
466 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
467 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
468 _cleanup_hashmap_free_ Hashmap
*images
= NULL
;
469 Manager
*m
= userdata
;
477 images
= hashmap_new(&image_hash_ops
);
481 r
= image_discover(IMAGE_MACHINE
, images
);
485 r
= sd_bus_message_new_method_return(message
, &reply
);
489 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
493 HASHMAP_FOREACH(image
, images
, i
) {
494 _cleanup_free_
char *p
= NULL
;
496 p
= image_bus_path(image
->name
);
500 r
= sd_bus_message_append(reply
, "(ssbttto)",
502 image_type_to_string(image
->type
),
512 r
= sd_bus_message_close_container(reply
);
516 return sd_bus_send(NULL
, reply
, NULL
);
519 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
520 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_pty
);
523 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
524 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_login
);
527 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
528 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_shell
);
531 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
532 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_bind_mount
);
535 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
536 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_copy
);
539 static int method_open_machine_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
540 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_open_root_directory
);
543 static int method_get_machine_uid_shift(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
544 return redirect_method_to_machine(message
, userdata
, error
, bus_machine_method_get_uid_shift
);
547 static int redirect_method_to_image(sd_bus_message
*message
, Manager
*m
, sd_bus_error
*error
, sd_bus_message_handler_t method
) {
548 _cleanup_(image_unrefp
) Image
* i
= NULL
;
556 r
= sd_bus_message_read(message
, "s", &name
);
560 if (!image_name_is_valid(name
))
561 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
563 r
= image_find(IMAGE_MACHINE
, name
, &i
);
565 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
570 return method(message
, i
, error
);
573 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
574 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_remove
);
577 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
578 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_rename
);
581 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
582 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_clone
);
585 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
586 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_mark_read_only
);
589 static int method_get_image_hostname(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
590 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_hostname
);
593 static int method_get_image_machine_id(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
594 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_machine_id
);
597 static int method_get_image_machine_info(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
598 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_machine_info
);
601 static int method_get_image_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
602 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_get_os_release
);
605 static int clean_pool_done(Operation
*operation
, int ret
, sd_bus_error
*error
) {
606 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
607 _cleanup_fclose_
FILE *f
= NULL
;
613 assert(operation
->extra_fd
>= 0);
615 if (lseek(operation
->extra_fd
, 0, SEEK_SET
) == (off_t
) -1)
618 f
= fdopen(operation
->extra_fd
, "r");
622 operation
->extra_fd
= -1;
624 /* The resulting temporary file starts with a boolean value that indicates success or not. */
626 n
= fread(&success
, 1, sizeof(success
), f
);
627 if (n
!= sizeof(success
))
628 return ret
< 0 ? ret
: (errno
!= 0 ? -errno
: -EIO
);
631 _cleanup_free_
char *name
= NULL
;
633 /* The clean-up operation failed. In this case the resulting temporary file should contain a boolean
634 * set to false followed by the name of the failed image. Let's try to read this and use it for the
635 * error message. If we can't read it, don't mind, and return the naked error. */
637 if (success
) /* The resulting temporary file could not be updated, ignore it. */
640 r
= read_nul_string(f
, &name
);
641 if (r
< 0 || isempty(name
)) /* Same here... */
644 return sd_bus_error_set_errnof(error
, ret
, "Failed to remove image %s: %m", name
);
649 r
= sd_bus_message_new_method_return(operation
->message
, &reply
);
653 r
= sd_bus_message_open_container(reply
, 'a', "(st)");
657 /* On success the resulting temporary file will contain a list of image names that were removed followed by
658 * their size on disk. Let's read that and turn it into a bus message. */
660 _cleanup_free_
char *name
= NULL
;
663 r
= read_nul_string(f
, &name
);
666 if (isempty(name
)) /* reached the end */
670 n
= fread(&size
, 1, sizeof(size
), f
);
671 if (n
!= sizeof(size
))
672 return errno
!= 0 ? -errno
: -EIO
;
674 r
= sd_bus_message_append(reply
, "(st)", name
, size
);
679 r
= sd_bus_message_close_container(reply
);
683 return sd_bus_send(NULL
, reply
, NULL
);
686 static int method_clean_pool(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
692 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
693 _cleanup_close_
int result_fd
= -1;
694 Manager
*m
= userdata
;
695 Operation
*operation
;
702 if (m
->n_operations
>= OPERATIONS_MAX
)
703 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing operations.");
705 r
= sd_bus_message_read(message
, "s", &mm
);
709 if (streq(mm
, "all"))
711 else if (streq(mm
, "hidden"))
712 mode
= REMOVE_HIDDEN
;
714 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown mode '%s'.", mm
);
716 r
= bus_verify_polkit_async(
719 "org.freedesktop.machine1.manage-machines",
728 return 1; /* Will call us back */
730 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
731 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
733 /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
734 * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
736 result_fd
= open_tmpfile_unlinkable(NULL
, O_RDWR
|O_CLOEXEC
);
740 /* This might be a slow operation, run it asynchronously in a background process */
741 r
= safe_fork("(sd-clean)", FORK_RESET_SIGNALS
, &child
);
743 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
745 _cleanup_hashmap_free_ Hashmap
*images
= NULL
;
751 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
753 images
= hashmap_new(&image_hash_ops
);
759 r
= image_discover(IMAGE_MACHINE
, images
);
763 l
= write(result_fd
, &success
, sizeof(success
));
769 HASHMAP_FOREACH(image
, images
, i
) {
771 /* We can't remove vendor images (i.e. those in /usr) */
772 if (IMAGE_IS_VENDOR(image
))
775 if (IMAGE_IS_HOST(image
))
778 if (mode
== REMOVE_HIDDEN
&& !IMAGE_IS_HIDDEN(image
))
781 r
= image_remove(image
);
782 if (r
== -EBUSY
) /* keep images that are currently being used. */
785 /* If the operation failed, let's override everything we wrote, and instead write there at which image we failed. */
787 (void) ftruncate(result_fd
, 0);
788 (void) lseek(result_fd
, 0, SEEK_SET
);
789 (void) write(result_fd
, &success
, sizeof(success
));
790 (void) write(result_fd
, image
->name
, strlen(image
->name
)+1);
794 l
= write(result_fd
, image
->name
, strlen(image
->name
)+1);
800 l
= write(result_fd
, &image
->usage_exclusive
, sizeof(image
->usage_exclusive
));
807 result_fd
= safe_close(result_fd
);
811 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
815 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
817 /* The clean-up might take a while, hence install a watch on the child and return */
819 r
= operation_new(m
, NULL
, child
, message
, errno_pipe_fd
[0], &operation
);
821 (void) sigkill_wait(child
);
825 operation
->extra_fd
= result_fd
;
826 operation
->done
= clean_pool_done
;
829 errno_pipe_fd
[0] = -1;
834 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
835 Manager
*m
= userdata
;
841 r
= sd_bus_message_read(message
, "t", &limit
);
844 if (!FILE_SIZE_VALID_OR_INFINITY(limit
))
845 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "New limit out of range");
847 r
= bus_verify_polkit_async(
850 "org.freedesktop.machine1.manage-machines",
859 return 1; /* Will call us back */
861 /* Set up the machine directory if necessary */
862 r
= setup_machine_directory(error
);
866 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit
);
868 r
= btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit
);
870 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
872 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
874 return sd_bus_reply_method_return(message
, NULL
);
877 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
878 return redirect_method_to_image(message
, userdata
, error
, bus_image_method_set_limit
);
881 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
882 _cleanup_fclose_
FILE *f
= NULL
;
883 Manager
*m
= userdata
;
884 const char *name
, *p
;
889 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
893 if (!uid_is_valid(uid
))
894 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
896 machine
= hashmap_get(m
->machines
, name
);
898 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
900 if (machine
->class != MACHINE_CONTAINER
)
901 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
903 p
= procfs_file_alloca(machine
->leader
, "uid_map");
909 uid_t uid_base
, uid_shift
, uid_range
, converted
;
913 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
914 if (k
< 0 && feof(f
))
917 if (ferror(f
) && errno
> 0)
923 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
926 converted
= uid
- uid_base
+ uid_shift
;
927 if (!uid_is_valid(converted
))
928 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
930 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
933 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
936 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
937 Manager
*m
= userdata
;
943 r
= sd_bus_message_read(message
, "u", &uid
);
946 if (!uid_is_valid(uid
))
947 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
949 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
951 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
952 _cleanup_fclose_
FILE *f
= NULL
;
953 char p
[STRLEN("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
955 if (machine
->class != MACHINE_CONTAINER
)
958 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
961 log_warning_errno(errno
, "Failed to open %s, ignoring,", p
);
966 _cleanup_free_
char *o
= NULL
;
967 uid_t uid_base
, uid_shift
, uid_range
, converted
;
971 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
972 if (k
< 0 && feof(f
))
975 if (ferror(f
) && errno
> 0)
981 /* The private user namespace is disabled, ignoring. */
985 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
988 converted
= (uid
- uid_shift
+ uid_base
);
989 if (!uid_is_valid(converted
))
990 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
992 o
= machine_bus_path(machine
);
996 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1000 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
1003 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1004 _cleanup_fclose_
FILE *f
= NULL
;
1005 Manager
*m
= groupdata
;
1006 const char *name
, *p
;
1011 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
1015 if (!gid_is_valid(gid
))
1016 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1018 machine
= hashmap_get(m
->machines
, name
);
1020 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1022 if (machine
->class != MACHINE_CONTAINER
)
1023 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1025 p
= procfs_file_alloca(machine
->leader
, "gid_map");
1031 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1035 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1036 if (k
< 0 && feof(f
))
1039 if (ferror(f
) && errno
> 0)
1045 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
1048 converted
= gid
- gid_base
+ gid_shift
;
1049 if (!gid_is_valid(converted
))
1050 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1052 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1055 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1058 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1059 Manager
*m
= groupdata
;
1065 r
= sd_bus_message_read(message
, "u", &gid
);
1068 if (!gid_is_valid(gid
))
1069 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1071 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1073 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1074 _cleanup_fclose_
FILE *f
= NULL
;
1075 char p
[STRLEN("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1077 if (machine
->class != MACHINE_CONTAINER
)
1080 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1083 log_warning_errno(errno
, "Failed to open %s, ignoring,", p
);
1088 _cleanup_free_
char *o
= NULL
;
1089 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1093 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1094 if (k
< 0 && feof(f
))
1097 if (ferror(f
) && errno
> 0)
1103 /* The private user namespace is disabled, ignoring. */
1107 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1110 converted
= (gid
- gid_shift
+ gid_base
);
1111 if (!gid_is_valid(converted
))
1112 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1114 o
= machine_bus_path(machine
);
1118 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1122 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1125 const sd_bus_vtable manager_vtable
[] = {
1126 SD_BUS_VTABLE_START(0),
1127 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1128 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1129 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1130 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1131 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1132 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1133 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1134 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1135 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1136 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1137 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1138 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1139 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1140 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1141 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1142 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1143 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1144 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1145 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1146 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1147 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1148 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1149 SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory
, SD_BUS_VTABLE_UNPRIVILEGED
),
1150 SD_BUS_METHOD("GetMachineUIDShift", "s", "u", method_get_machine_uid_shift
, SD_BUS_VTABLE_UNPRIVILEGED
),
1151 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1152 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1153 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1154 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1155 SD_BUS_METHOD("GetImageHostname", "s", "s", method_get_image_hostname
, SD_BUS_VTABLE_UNPRIVILEGED
),
1156 SD_BUS_METHOD("GetImageMachineID", "s", "ay", method_get_image_machine_id
, SD_BUS_VTABLE_UNPRIVILEGED
),
1157 SD_BUS_METHOD("GetImageMachineInfo", "s", "a{ss}", method_get_image_machine_info
, SD_BUS_VTABLE_UNPRIVILEGED
),
1158 SD_BUS_METHOD("GetImageOSRelease", "s", "a{ss}", method_get_image_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1159 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1160 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1161 SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool
, SD_BUS_VTABLE_UNPRIVILEGED
),
1162 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1163 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1164 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1165 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1166 SD_BUS_SIGNAL("MachineNew", "so", 0),
1167 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1171 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1172 const char *path
, *result
, *unit
;
1173 Manager
*m
= userdata
;
1181 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1183 bus_log_parse_error(r
);
1187 machine
= hashmap_get(m
->machine_units
, unit
);
1191 if (streq_ptr(path
, machine
->scope_job
)) {
1192 machine
->scope_job
= mfree(machine
->scope_job
);
1194 if (machine
->started
) {
1195 if (streq(result
, "done"))
1196 machine_send_create_reply(machine
, NULL
);
1198 _cleanup_(sd_bus_error_free
) sd_bus_error e
= SD_BUS_ERROR_NULL
;
1200 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1202 machine_send_create_reply(machine
, &e
);
1206 machine_save(machine
);
1209 machine_add_to_gc_queue(machine
);
1213 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1214 _cleanup_free_
char *unit
= NULL
;
1216 Manager
*m
= userdata
;
1223 path
= sd_bus_message_get_path(message
);
1227 r
= unit_name_from_dbus_path(path
, &unit
);
1228 if (r
== -EINVAL
) /* not for a unit */
1235 machine
= hashmap_get(m
->machine_units
, unit
);
1239 machine_add_to_gc_queue(machine
);
1243 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1244 const char *path
, *unit
;
1245 Manager
*m
= userdata
;
1252 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1254 bus_log_parse_error(r
);
1258 machine
= hashmap_get(m
->machine_units
, unit
);
1262 machine_add_to_gc_queue(machine
);
1266 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1267 Manager
*m
= userdata
;
1275 r
= sd_bus_message_read(message
, "b", &b
);
1277 bus_log_parse_error(r
);
1283 /* systemd finished reloading, let's recheck all our machines */
1284 log_debug("System manager has been reloaded, rechecking machines...");
1286 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1287 machine_add_to_gc_queue(machine
);
1292 int manager_start_scope(
1297 const char *description
,
1298 sd_bus_message
*more_properties
,
1299 sd_bus_error
*error
,
1302 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1309 r
= sd_bus_message_new_method_call(
1312 "org.freedesktop.systemd1",
1313 "/org/freedesktop/systemd1",
1314 "org.freedesktop.systemd1.Manager",
1315 "StartTransientUnit");
1319 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1323 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1327 if (!isempty(slice
)) {
1328 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1333 if (!isempty(description
)) {
1334 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1339 r
= sd_bus_message_append(m
, "(sv)(sv)(sv)(sv)(sv)",
1340 "PIDs", "au", 1, pid
,
1342 "CollectMode", "s", "inactive-or-failed",
1344 "TasksMax", "t", UINT64_C(16384));
1348 if (more_properties
) {
1349 r
= sd_bus_message_copy(m
, more_properties
, true);
1354 r
= sd_bus_message_close_container(m
);
1358 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1362 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1370 r
= sd_bus_message_read(reply
, "o", &j
);
1384 int manager_unref_unit(
1387 sd_bus_error
*error
) {
1392 return sd_bus_call_method(
1394 "org.freedesktop.systemd1",
1395 "/org/freedesktop/systemd1",
1396 "org.freedesktop.systemd1.Manager",
1404 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1405 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1411 r
= sd_bus_call_method(
1413 "org.freedesktop.systemd1",
1414 "/org/freedesktop/systemd1",
1415 "org.freedesktop.systemd1.Manager",
1419 "ss", unit
, "fail");
1421 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1422 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1427 sd_bus_error_free(error
);
1438 r
= sd_bus_message_read(reply
, "o", &j
);
1452 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1456 return sd_bus_call_method(
1458 "org.freedesktop.systemd1",
1459 "/org/freedesktop/systemd1",
1460 "org.freedesktop.systemd1.Manager",
1464 "ssi", unit
, "all", signo
);
1467 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1468 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1469 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1470 _cleanup_free_
char *path
= NULL
;
1477 path
= unit_dbus_path_from_name(unit
);
1481 r
= sd_bus_get_property(
1483 "org.freedesktop.systemd1",
1485 "org.freedesktop.systemd1.Unit",
1491 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1492 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1495 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1496 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1502 r
= sd_bus_message_read(reply
, "s", &state
);
1506 return !STR_IN_SET(state
, "inactive", "failed");
1509 int manager_job_is_active(Manager
*manager
, const char *path
) {
1510 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1511 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1517 r
= sd_bus_get_property(
1519 "org.freedesktop.systemd1",
1521 "org.freedesktop.systemd1.Job",
1527 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1528 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1531 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1537 /* We don't actually care about the state really. The fact
1538 * that we could read the job state is enough for us */
1543 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1551 mm
= hashmap_get(m
->machine_leaders
, PID_TO_PTR(pid
));
1553 _cleanup_free_
char *unit
= NULL
;
1555 r
= cg_pid_get_unit(pid
, &unit
);
1557 mm
= hashmap_get(m
->machine_units
, unit
);
1566 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1572 machine
= hashmap_get(m
->machines
, name
);
1574 machine
= machine_new(m
, _MACHINE_CLASS_INVALID
, name
);
1580 *_machine
= machine
;