2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "alloc-util.h"
27 #include "btrfs-util.h"
28 #include "bus-common-errors.h"
30 #include "cgroup-util.h"
32 #include "formats-util.h"
33 #include "hostname-util.h"
34 #include "image-dbus.h"
36 #include "machine-dbus.h"
37 #include "machine-image.h"
38 #include "machine-pool.h"
40 #include "path-util.h"
41 #include "process-util.h"
42 #include "stdio-util.h"
44 #include "unit-name.h"
45 #include "user-util.h"
47 static int property_get_pool_path(
50 const char *interface
,
52 sd_bus_message
*reply
,
54 sd_bus_error
*error
) {
59 return sd_bus_message_append(reply
, "s", "/var/lib/machines");
62 static int property_get_pool_usage(
65 const char *interface
,
67 sd_bus_message
*reply
,
69 sd_bus_error
*error
) {
71 _cleanup_close_
int fd
= -1;
72 uint64_t usage
= (uint64_t) -1;
78 /* We try to read the quota info from /var/lib/machines, as
79 * well as the usage of the loopback file
80 * /var/lib/machines.raw, and pick the larger value. */
82 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
86 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
90 if (stat("/var/lib/machines.raw", &st
) >= 0) {
91 if (usage
== (uint64_t) -1 || st
.st_blocks
* 512ULL > usage
)
92 usage
= st
.st_blocks
* 512ULL;
95 return sd_bus_message_append(reply
, "t", usage
);
98 static int property_get_pool_limit(
101 const char *interface
,
102 const char *property
,
103 sd_bus_message
*reply
,
105 sd_bus_error
*error
) {
107 _cleanup_close_
int fd
= -1;
108 uint64_t size
= (uint64_t) -1;
114 /* We try to read the quota limit from /var/lib/machines, as
115 * well as the size of the loopback file
116 * /var/lib/machines.raw, and pick the smaller value. */
118 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
122 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
123 size
= q
.referenced_max
;
126 if (stat("/var/lib/machines.raw", &st
) >= 0) {
127 if (size
== (uint64_t) -1 || (uint64_t) st
.st_size
< size
)
131 return sd_bus_message_append(reply
, "t", size
);
134 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
135 _cleanup_free_
char *p
= NULL
;
136 Manager
*m
= userdata
;
144 r
= sd_bus_message_read(message
, "s", &name
);
148 machine
= hashmap_get(m
->machines
, name
);
150 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
152 p
= machine_bus_path(machine
);
156 return sd_bus_reply_method_return(message
, "o", p
);
159 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
160 _cleanup_free_
char *p
= NULL
;
161 Manager
*m
= userdata
;
168 r
= sd_bus_message_read(message
, "s", &name
);
172 r
= image_find(name
, NULL
);
174 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
178 p
= image_bus_path(name
);
182 return sd_bus_reply_method_return(message
, "o", p
);
185 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
186 _cleanup_free_
char *p
= NULL
;
187 Manager
*m
= userdata
;
188 Machine
*machine
= NULL
;
195 assert_cc(sizeof(pid_t
) == sizeof(uint32_t));
197 r
= sd_bus_message_read(message
, "u", &pid
);
205 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
207 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
211 r
= sd_bus_creds_get_pid(creds
, &pid
);
216 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
220 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
222 p
= machine_bus_path(machine
);
226 return sd_bus_reply_method_return(message
, "o", p
);
229 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
230 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
231 Manager
*m
= userdata
;
239 r
= sd_bus_message_new_method_return(message
, &reply
);
241 return sd_bus_error_set_errno(error
, r
);
243 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
245 return sd_bus_error_set_errno(error
, r
);
247 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
248 _cleanup_free_
char *p
= NULL
;
250 p
= machine_bus_path(machine
);
254 r
= sd_bus_message_append(reply
, "(ssso)",
256 strempty(machine_class_to_string(machine
->class)),
260 return sd_bus_error_set_errno(error
, r
);
263 r
= sd_bus_message_close_container(reply
);
265 return sd_bus_error_set_errno(error
, r
);
267 return sd_bus_send(NULL
, reply
, NULL
);
270 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
271 const char *name
, *service
, *class, *root_directory
;
272 const int32_t *netif
= NULL
;
278 size_t n
, n_netif
= 0;
285 r
= sd_bus_message_read(message
, "s", &name
);
288 if (!machine_name_is_valid(name
))
289 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
291 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
299 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
301 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
308 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
312 n_netif
/= sizeof(int32_t);
314 for (i
= 0; i
< n_netif
; i
++) {
316 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
321 c
= _MACHINE_CLASS_INVALID
;
323 c
= machine_class_from_string(class);
325 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
329 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
331 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
332 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
335 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
337 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
341 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
343 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
348 if (hashmap_get(manager
->machines
, name
))
349 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
351 r
= manager_add_machine(manager
, name
, &m
);
359 if (!isempty(service
)) {
360 m
->service
= strdup(service
);
367 if (!isempty(root_directory
)) {
368 m
->root_directory
= strdup(root_directory
);
369 if (!m
->root_directory
) {
376 assert_cc(sizeof(int32_t) == sizeof(int));
377 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
383 m
->n_netif
= n_netif
;
391 machine_add_to_gc_queue(m
);
395 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
396 Manager
*manager
= userdata
;
403 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
407 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
411 r
= machine_start(m
, message
, error
);
415 m
->create_message
= sd_bus_message_ref(message
);
419 machine_add_to_gc_queue(m
);
423 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
424 return method_create_machine_internal(message
, true, userdata
, error
);
427 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
428 return method_create_machine_internal(message
, false, userdata
, error
);
431 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
432 Manager
*manager
= userdata
;
433 _cleanup_free_
char *p
= NULL
;
440 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
444 r
= cg_pid_get_unit(m
->leader
, &m
->unit
);
446 r
= sd_bus_error_set_errnof(error
, r
, "Failed to determine unit of process "PID_FMT
" : %s", m
->leader
, strerror(-r
));
450 r
= machine_start(m
, NULL
, error
);
454 p
= machine_bus_path(m
);
460 return sd_bus_reply_method_return(message
, "o", p
);
463 machine_add_to_gc_queue(m
);
467 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
468 return method_register_machine_internal(message
, true, userdata
, error
);
471 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
472 return method_register_machine_internal(message
, false, userdata
, error
);
475 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
476 Manager
*m
= userdata
;
484 r
= sd_bus_message_read(message
, "s", &name
);
486 return sd_bus_error_set_errno(error
, r
);
488 machine
= hashmap_get(m
->machines
, name
);
490 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
492 return bus_machine_method_terminate(message
, machine
, error
);
495 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
496 Manager
*m
= userdata
;
504 r
= sd_bus_message_read(message
, "s", &name
);
506 return sd_bus_error_set_errno(error
, r
);
508 machine
= hashmap_get(m
->machines
, name
);
510 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
512 return bus_machine_method_kill(message
, machine
, error
);
515 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
516 Manager
*m
= userdata
;
524 r
= sd_bus_message_read(message
, "s", &name
);
526 return sd_bus_error_set_errno(error
, r
);
528 machine
= hashmap_get(m
->machines
, name
);
530 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
532 return bus_machine_method_get_addresses(message
, machine
, error
);
535 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
536 Manager
*m
= userdata
;
544 r
= sd_bus_message_read(message
, "s", &name
);
546 return sd_bus_error_set_errno(error
, r
);
548 machine
= hashmap_get(m
->machines
, name
);
550 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
552 return bus_machine_method_get_os_release(message
, machine
, error
);
555 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
556 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
557 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
558 Manager
*m
= userdata
;
566 images
= hashmap_new(&string_hash_ops
);
570 r
= image_discover(images
);
574 r
= sd_bus_message_new_method_return(message
, &reply
);
578 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
582 HASHMAP_FOREACH(image
, images
, i
) {
583 _cleanup_free_
char *p
= NULL
;
585 p
= image_bus_path(image
->name
);
589 r
= sd_bus_message_append(reply
, "(ssbttto)",
591 image_type_to_string(image
->type
),
601 r
= sd_bus_message_close_container(reply
);
605 return sd_bus_send(NULL
, reply
, NULL
);
608 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
609 Manager
*m
= userdata
;
617 r
= sd_bus_message_read(message
, "s", &name
);
619 return sd_bus_error_set_errno(error
, r
);
621 machine
= hashmap_get(m
->machines
, name
);
623 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
625 return bus_machine_method_open_pty(message
, machine
, error
);
628 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
629 Manager
*m
= userdata
;
637 r
= sd_bus_message_read(message
, "s", &name
);
641 machine
= hashmap_get(m
->machines
, name
);
643 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
645 return bus_machine_method_open_login(message
, machine
, error
);
648 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
649 Manager
*m
= userdata
;
658 r
= sd_bus_message_read(message
, "s", &name
);
662 machine
= hashmap_get(m
->machines
, name
);
664 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
666 return bus_machine_method_open_shell(message
, machine
, error
);
669 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
670 Manager
*m
= userdata
;
678 r
= sd_bus_message_read(message
, "s", &name
);
682 machine
= hashmap_get(m
->machines
, name
);
684 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
686 return bus_machine_method_bind_mount(message
, machine
, error
);
689 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
690 Manager
*m
= userdata
;
698 r
= sd_bus_message_read(message
, "s", &name
);
702 machine
= hashmap_get(m
->machines
, name
);
704 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
706 return bus_machine_method_copy(message
, machine
, error
);
709 static int method_open_machine_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
710 Manager
*m
= userdata
;
718 r
= sd_bus_message_read(message
, "s", &name
);
722 machine
= hashmap_get(m
->machines
, name
);
724 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
726 return bus_machine_method_open_root_directory(message
, machine
, error
);
729 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
730 _cleanup_(image_unrefp
) Image
* i
= NULL
;
736 r
= sd_bus_message_read(message
, "s", &name
);
740 if (!image_name_is_valid(name
))
741 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
743 r
= image_find(name
, &i
);
747 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
749 i
->userdata
= userdata
;
750 return bus_image_method_remove(message
, i
, error
);
753 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
754 _cleanup_(image_unrefp
) Image
* i
= NULL
;
755 const char *old_name
;
760 r
= sd_bus_message_read(message
, "s", &old_name
);
764 if (!image_name_is_valid(old_name
))
765 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
767 r
= image_find(old_name
, &i
);
771 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
773 i
->userdata
= userdata
;
774 return bus_image_method_rename(message
, i
, error
);
777 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
778 _cleanup_(image_unrefp
) Image
*i
= NULL
;
779 const char *old_name
;
784 r
= sd_bus_message_read(message
, "s", &old_name
);
788 if (!image_name_is_valid(old_name
))
789 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
791 r
= image_find(old_name
, &i
);
795 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
797 i
->userdata
= userdata
;
798 return bus_image_method_clone(message
, i
, error
);
801 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
802 _cleanup_(image_unrefp
) Image
*i
= NULL
;
808 r
= sd_bus_message_read(message
, "s", &name
);
812 if (!image_name_is_valid(name
))
813 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
815 r
= image_find(name
, &i
);
819 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
821 i
->userdata
= userdata
;
822 return bus_image_method_mark_read_only(message
, i
, error
);
825 static int method_clean_pool(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
831 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
832 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
833 Manager
*m
= userdata
;
841 r
= sd_bus_message_read(message
, "s", &mm
);
845 if (streq(mm
, "all"))
847 else if (streq(mm
, "hidden"))
848 mode
= REMOVE_HIDDEN
;
850 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown mode '%s'.", mm
);
852 r
= bus_verify_polkit_async(
855 "org.freedesktop.machine1.manage-machines",
864 return 1; /* Will call us back */
866 images
= hashmap_new(&string_hash_ops
);
870 r
= image_discover(images
);
874 r
= sd_bus_message_new_method_return(message
, &reply
);
878 r
= sd_bus_message_open_container(reply
, 'a', "(st)");
882 HASHMAP_FOREACH(image
, images
, i
) {
884 /* We can't remove vendor images (i.e. those in /usr) */
885 if (IMAGE_IS_VENDOR(image
))
888 if (IMAGE_IS_HOST(image
))
891 if (mode
== REMOVE_HIDDEN
&& !IMAGE_IS_HIDDEN(image
))
894 r
= image_remove(image
);
895 if (r
== -EBUSY
) /* keep images that are currently being used. */
898 return sd_bus_error_set_errnof(error
, r
, "Failed to remove image %s: %m", image
->name
);
900 r
= sd_bus_message_append(reply
, "(st)", image
->name
, image
->usage_exclusive
);
905 r
= sd_bus_message_close_container(reply
);
909 return sd_bus_send(NULL
, reply
, NULL
);
912 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
913 Manager
*m
= userdata
;
919 r
= sd_bus_message_read(message
, "t", &limit
);
922 if (!FILE_SIZE_VALID_OR_INFINITY(limit
))
923 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "New limit out of range");
925 r
= bus_verify_polkit_async(
928 "org.freedesktop.machine1.manage-machines",
937 return 1; /* Will call us back */
939 /* Set up the machine directory if necessary */
940 r
= setup_machine_directory(limit
, error
);
944 /* Resize the backing loopback device, if there is one, except if we asked to drop any limit */
945 if (limit
!= (uint64_t) -1) {
946 r
= btrfs_resize_loopback("/var/lib/machines", limit
, false);
948 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
949 if (r
< 0 && r
!= -ENODEV
) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
950 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust loopback limit: %m");
953 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit
);
955 r
= btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit
);
957 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
959 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
961 return sd_bus_reply_method_return(message
, NULL
);
964 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
965 _cleanup_(image_unrefp
) Image
*i
= NULL
;
971 r
= sd_bus_message_read(message
, "s", &name
);
975 if (!image_name_is_valid(name
))
976 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
978 r
= image_find(name
, &i
);
982 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
984 i
->userdata
= userdata
;
985 return bus_image_method_set_limit(message
, i
, error
);
988 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
989 _cleanup_fclose_
FILE *f
= NULL
;
990 Manager
*m
= userdata
;
991 const char *name
, *p
;
996 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
1000 if (!uid_is_valid(uid
))
1001 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1003 machine
= hashmap_get(m
->machines
, name
);
1005 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1007 if (machine
->class != MACHINE_CONTAINER
)
1008 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1010 p
= procfs_file_alloca(machine
->leader
, "uid_map");
1016 uid_t uid_base
, uid_shift
, uid_range
, converted
;
1020 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
1021 if (k
< 0 && feof(f
))
1024 if (ferror(f
) && errno
> 0)
1030 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
1033 converted
= uid
- uid_base
+ uid_shift
;
1034 if (!uid_is_valid(converted
))
1035 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1037 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1040 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
1043 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1044 Manager
*m
= userdata
;
1050 r
= sd_bus_message_read(message
, "u", &uid
);
1053 if (!uid_is_valid(uid
))
1054 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1056 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
1058 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1059 _cleanup_fclose_
FILE *f
= NULL
;
1060 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1062 if (machine
->class != MACHINE_CONTAINER
)
1065 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
1068 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1073 _cleanup_free_
char *o
= NULL
;
1074 uid_t uid_base
, uid_shift
, uid_range
, converted
;
1078 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
1079 if (k
< 0 && feof(f
))
1082 if (ferror(f
) && errno
> 0)
1088 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
1091 converted
= (uid
- uid_shift
+ uid_base
);
1092 if (!uid_is_valid(converted
))
1093 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
1095 o
= machine_bus_path(machine
);
1099 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1103 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
1106 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1107 _cleanup_fclose_
FILE *f
= NULL
;
1108 Manager
*m
= groupdata
;
1109 const char *name
, *p
;
1114 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
1118 if (!gid_is_valid(gid
))
1119 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1121 machine
= hashmap_get(m
->machines
, name
);
1123 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1125 if (machine
->class != MACHINE_CONTAINER
)
1126 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1128 p
= procfs_file_alloca(machine
->leader
, "gid_map");
1134 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1138 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1139 if (k
< 0 && feof(f
))
1142 if (ferror(f
) && errno
> 0)
1148 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
1151 converted
= gid
- gid_base
+ gid_shift
;
1152 if (!gid_is_valid(converted
))
1153 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1155 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1158 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1161 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1162 Manager
*m
= groupdata
;
1168 r
= sd_bus_message_read(message
, "u", &gid
);
1171 if (!gid_is_valid(gid
))
1172 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1174 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1176 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1177 _cleanup_fclose_
FILE *f
= NULL
;
1178 char p
[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1180 if (machine
->class != MACHINE_CONTAINER
)
1183 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1186 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1191 _cleanup_free_
char *o
= NULL
;
1192 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1196 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1197 if (k
< 0 && feof(f
))
1200 if (ferror(f
) && errno
> 0)
1206 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1209 converted
= (gid
- gid_shift
+ gid_base
);
1210 if (!gid_is_valid(converted
))
1211 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1213 o
= machine_bus_path(machine
);
1217 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1221 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1224 const sd_bus_vtable manager_vtable
[] = {
1225 SD_BUS_VTABLE_START(0),
1226 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1227 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1228 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1229 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1230 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1231 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1232 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1233 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1234 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1235 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1236 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1237 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1238 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1239 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1240 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1241 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1242 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1243 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1244 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1245 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1246 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1247 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1248 SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory
, SD_BUS_VTABLE_UNPRIVILEGED
),
1249 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1250 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1251 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1252 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1253 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1254 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1255 SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool
, SD_BUS_VTABLE_UNPRIVILEGED
),
1256 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1257 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1258 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1259 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1260 SD_BUS_SIGNAL("MachineNew", "so", 0),
1261 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1265 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1266 const char *path
, *result
, *unit
;
1267 Manager
*m
= userdata
;
1275 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1277 bus_log_parse_error(r
);
1281 machine
= hashmap_get(m
->machine_units
, unit
);
1285 if (streq_ptr(path
, machine
->scope_job
)) {
1286 machine
->scope_job
= mfree(machine
->scope_job
);
1288 if (machine
->started
) {
1289 if (streq(result
, "done"))
1290 machine_send_create_reply(machine
, NULL
);
1292 _cleanup_(sd_bus_error_free
) sd_bus_error e
= SD_BUS_ERROR_NULL
;
1294 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1296 machine_send_create_reply(machine
, &e
);
1300 machine_save(machine
);
1303 machine_add_to_gc_queue(machine
);
1307 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1308 _cleanup_free_
char *unit
= NULL
;
1310 Manager
*m
= userdata
;
1317 path
= sd_bus_message_get_path(message
);
1321 r
= unit_name_from_dbus_path(path
, &unit
);
1322 if (r
== -EINVAL
) /* not for a unit */
1329 machine
= hashmap_get(m
->machine_units
, unit
);
1333 machine_add_to_gc_queue(machine
);
1337 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1338 const char *path
, *unit
;
1339 Manager
*m
= userdata
;
1346 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1348 bus_log_parse_error(r
);
1352 machine
= hashmap_get(m
->machine_units
, unit
);
1356 machine_add_to_gc_queue(machine
);
1360 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1361 Manager
*m
= userdata
;
1369 r
= sd_bus_message_read(message
, "b", &b
);
1371 bus_log_parse_error(r
);
1377 /* systemd finished reloading, let's recheck all our machines */
1378 log_debug("System manager has been reloaded, rechecking machines...");
1380 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1381 machine_add_to_gc_queue(machine
);
1386 int manager_start_scope(
1391 const char *description
,
1392 sd_bus_message
*more_properties
,
1393 sd_bus_error
*error
,
1396 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1403 r
= sd_bus_message_new_method_call(
1406 "org.freedesktop.systemd1",
1407 "/org/freedesktop/systemd1",
1408 "org.freedesktop.systemd1.Manager",
1409 "StartTransientUnit");
1413 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1417 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1421 if (!isempty(slice
)) {
1422 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1427 if (!isempty(description
)) {
1428 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1433 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, pid
);
1437 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
1441 r
= sd_bus_message_append(m
, "(sv)", "TasksMax", "t", UINT64_C(16384));
1443 return bus_log_create_error(r
);
1445 if (more_properties
) {
1446 r
= sd_bus_message_copy(m
, more_properties
, true);
1451 r
= sd_bus_message_close_container(m
);
1455 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1459 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1467 r
= sd_bus_message_read(reply
, "o", &j
);
1481 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1482 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1488 r
= sd_bus_call_method(
1490 "org.freedesktop.systemd1",
1491 "/org/freedesktop/systemd1",
1492 "org.freedesktop.systemd1.Manager",
1496 "ss", unit
, "fail");
1498 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1499 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1504 sd_bus_error_free(error
);
1515 r
= sd_bus_message_read(reply
, "o", &j
);
1529 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1533 return sd_bus_call_method(
1535 "org.freedesktop.systemd1",
1536 "/org/freedesktop/systemd1",
1537 "org.freedesktop.systemd1.Manager",
1541 "ssi", unit
, "all", signo
);
1544 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1545 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1546 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1547 _cleanup_free_
char *path
= NULL
;
1554 path
= unit_dbus_path_from_name(unit
);
1558 r
= sd_bus_get_property(
1560 "org.freedesktop.systemd1",
1562 "org.freedesktop.systemd1.Unit",
1568 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1569 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1572 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1573 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1579 r
= sd_bus_message_read(reply
, "s", &state
);
1583 return !STR_IN_SET(state
, "inactive", "failed");
1586 int manager_job_is_active(Manager
*manager
, const char *path
) {
1587 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1588 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1594 r
= sd_bus_get_property(
1596 "org.freedesktop.systemd1",
1598 "org.freedesktop.systemd1.Job",
1604 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1605 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1608 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1614 /* We don't actually care about the state really. The fact
1615 * that we could read the job state is enough for us */
1620 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1628 mm
= hashmap_get(m
->machine_leaders
, PID_TO_PTR(pid
));
1630 _cleanup_free_
char *unit
= NULL
;
1632 r
= cg_pid_get_unit(pid
, &unit
);
1634 mm
= hashmap_get(m
->machine_units
, unit
);
1643 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1649 machine
= hashmap_get(m
->machines
, name
);
1651 machine
= machine_new(m
, _MACHINE_CLASS_INVALID
, name
);
1657 *_machine
= machine
;