1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "path-util.h"
29 #include "unit-name.h"
31 #include "bus-common-errors.h"
32 #include "cgroup-util.h"
33 #include "btrfs-util.h"
34 #include "formats-util.h"
35 #include "process-util.h"
36 #include "hostname-util.h"
37 #include "machine-image.h"
38 #include "machine-pool.h"
39 #include "image-dbus.h"
41 #include "machine-dbus.h"
43 static int property_get_pool_path(
46 const char *interface
,
48 sd_bus_message
*reply
,
50 sd_bus_error
*error
) {
55 return sd_bus_message_append(reply
, "s", "/var/lib/machines");
58 static int property_get_pool_usage(
61 const char *interface
,
63 sd_bus_message
*reply
,
65 sd_bus_error
*error
) {
67 _cleanup_close_
int fd
= -1;
68 uint64_t usage
= (uint64_t) -1;
74 /* We try to read the quota info from /var/lib/machines, as
75 * well as the usage of the loopback file
76 * /var/lib/machines.raw, and pick the larger value. */
78 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
82 if (btrfs_subvol_get_quota_fd(fd
, &q
) >= 0)
86 if (stat("/var/lib/machines.raw", &st
) >= 0) {
87 if (usage
== (uint64_t) -1 || st
.st_blocks
* 512ULL > usage
)
88 usage
= st
.st_blocks
* 512ULL;
91 return sd_bus_message_append(reply
, "t", usage
);
94 static int property_get_pool_limit(
97 const char *interface
,
99 sd_bus_message
*reply
,
101 sd_bus_error
*error
) {
103 _cleanup_close_
int fd
= -1;
104 uint64_t size
= (uint64_t) -1;
110 /* We try to read the quota limit from /var/lib/machines, as
111 * well as the size of the loopback file
112 * /var/lib/machines.raw, and pick the smaller value. */
114 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
118 if (btrfs_subvol_get_quota_fd(fd
, &q
) >= 0)
119 size
= q
.referenced_max
;
122 if (stat("/var/lib/machines.raw", &st
) >= 0) {
123 if (size
== (uint64_t) -1 || (uint64_t) st
.st_size
< size
)
127 return sd_bus_message_append(reply
, "t", size
);
130 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
131 _cleanup_free_
char *p
= NULL
;
132 Manager
*m
= userdata
;
140 r
= sd_bus_message_read(message
, "s", &name
);
144 machine
= hashmap_get(m
->machines
, name
);
146 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
148 p
= machine_bus_path(machine
);
152 return sd_bus_reply_method_return(message
, "o", p
);
155 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
156 _cleanup_free_
char *p
= NULL
;
157 Manager
*m
= userdata
;
164 r
= sd_bus_message_read(message
, "s", &name
);
168 r
= image_find(name
, NULL
);
170 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
174 p
= image_bus_path(name
);
178 return sd_bus_reply_method_return(message
, "o", p
);
181 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
182 _cleanup_free_
char *p
= NULL
;
183 Manager
*m
= userdata
;
184 Machine
*machine
= NULL
;
191 assert_cc(sizeof(pid_t
) == sizeof(uint32_t));
193 r
= sd_bus_message_read(message
, "u", &pid
);
198 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
200 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
204 r
= sd_bus_creds_get_pid(creds
, &pid
);
209 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
213 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
215 p
= machine_bus_path(machine
);
219 return sd_bus_reply_method_return(message
, "o", p
);
222 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
223 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
224 Manager
*m
= userdata
;
232 r
= sd_bus_message_new_method_return(message
, &reply
);
234 return sd_bus_error_set_errno(error
, r
);
236 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
238 return sd_bus_error_set_errno(error
, r
);
240 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
241 _cleanup_free_
char *p
= NULL
;
243 p
= machine_bus_path(machine
);
247 r
= sd_bus_message_append(reply
, "(ssso)",
249 strempty(machine_class_to_string(machine
->class)),
253 return sd_bus_error_set_errno(error
, r
);
256 r
= sd_bus_message_close_container(reply
);
258 return sd_bus_error_set_errno(error
, r
);
260 return sd_bus_send(NULL
, reply
, NULL
);
263 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
264 const char *name
, *service
, *class, *root_directory
;
265 const int32_t *netif
= NULL
;
271 size_t n
, n_netif
= 0;
278 r
= sd_bus_message_read(message
, "s", &name
);
281 if (!machine_name_is_valid(name
))
282 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
284 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
292 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
294 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
301 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
305 n_netif
/= sizeof(int32_t);
307 for (i
= 0; i
< n_netif
; i
++) {
309 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
314 c
= _MACHINE_CLASS_INVALID
;
316 c
= machine_class_from_string(class);
318 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
322 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
324 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
325 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
328 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
330 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
334 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
336 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
341 if (hashmap_get(manager
->machines
, name
))
342 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
344 r
= manager_add_machine(manager
, name
, &m
);
352 if (!isempty(service
)) {
353 m
->service
= strdup(service
);
360 if (!isempty(root_directory
)) {
361 m
->root_directory
= strdup(root_directory
);
362 if (!m
->root_directory
) {
369 assert_cc(sizeof(int32_t) == sizeof(int));
370 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
376 m
->n_netif
= n_netif
;
384 machine_add_to_gc_queue(m
);
388 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
389 Manager
*manager
= userdata
;
396 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
400 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
404 r
= machine_start(m
, message
, error
);
408 m
->create_message
= sd_bus_message_ref(message
);
412 machine_add_to_gc_queue(m
);
416 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
417 return method_create_machine_internal(message
, true, userdata
, error
);
420 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
421 return method_create_machine_internal(message
, false, userdata
, error
);
424 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
425 Manager
*manager
= userdata
;
426 _cleanup_free_
char *p
= NULL
;
433 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
437 r
= cg_pid_get_unit(m
->leader
, &m
->unit
);
439 r
= sd_bus_error_set_errnof(error
, r
, "Failed to determine unit of process "PID_FMT
" : %s", m
->leader
, strerror(-r
));
443 r
= machine_start(m
, NULL
, error
);
447 p
= machine_bus_path(m
);
453 return sd_bus_reply_method_return(message
, "o", p
);
456 machine_add_to_gc_queue(m
);
460 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
461 return method_register_machine_internal(message
, true, userdata
, error
);
464 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
465 return method_register_machine_internal(message
, false, userdata
, error
);
468 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
469 Manager
*m
= userdata
;
477 r
= sd_bus_message_read(message
, "s", &name
);
479 return sd_bus_error_set_errno(error
, r
);
481 machine
= hashmap_get(m
->machines
, name
);
483 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
485 return bus_machine_method_terminate(message
, machine
, error
);
488 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
489 Manager
*m
= userdata
;
497 r
= sd_bus_message_read(message
, "s", &name
);
499 return sd_bus_error_set_errno(error
, r
);
501 machine
= hashmap_get(m
->machines
, name
);
503 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
505 return bus_machine_method_kill(message
, machine
, error
);
508 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
509 Manager
*m
= userdata
;
517 r
= sd_bus_message_read(message
, "s", &name
);
519 return sd_bus_error_set_errno(error
, r
);
521 machine
= hashmap_get(m
->machines
, name
);
523 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
525 return bus_machine_method_get_addresses(message
, machine
, error
);
528 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
529 Manager
*m
= userdata
;
537 r
= sd_bus_message_read(message
, "s", &name
);
539 return sd_bus_error_set_errno(error
, r
);
541 machine
= hashmap_get(m
->machines
, name
);
543 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
545 return bus_machine_method_get_os_release(message
, machine
, error
);
548 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
549 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
550 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
551 Manager
*m
= userdata
;
559 images
= hashmap_new(&string_hash_ops
);
563 r
= image_discover(images
);
567 r
= sd_bus_message_new_method_return(message
, &reply
);
571 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
575 HASHMAP_FOREACH(image
, images
, i
) {
576 _cleanup_free_
char *p
= NULL
;
578 p
= image_bus_path(image
->name
);
582 r
= sd_bus_message_append(reply
, "(ssbttto)",
584 image_type_to_string(image
->type
),
594 r
= sd_bus_message_close_container(reply
);
598 return sd_bus_send(NULL
, reply
, NULL
);
601 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
602 Manager
*m
= userdata
;
610 r
= sd_bus_message_read(message
, "s", &name
);
612 return sd_bus_error_set_errno(error
, r
);
614 machine
= hashmap_get(m
->machines
, name
);
616 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
618 return bus_machine_method_open_pty(message
, machine
, error
);
621 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
622 Manager
*m
= userdata
;
630 r
= sd_bus_message_read(message
, "s", &name
);
634 machine
= hashmap_get(m
->machines
, name
);
636 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
638 return bus_machine_method_open_login(message
, machine
, error
);
641 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
642 Manager
*m
= userdata
;
651 r
= sd_bus_message_read(message
, "s", &name
);
655 machine
= hashmap_get(m
->machines
, name
);
657 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
659 return bus_machine_method_open_shell(message
, machine
, error
);
662 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
663 Manager
*m
= userdata
;
671 r
= sd_bus_message_read(message
, "s", &name
);
675 machine
= hashmap_get(m
->machines
, name
);
677 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
679 return bus_machine_method_bind_mount(message
, machine
, error
);
682 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
683 Manager
*m
= userdata
;
691 r
= sd_bus_message_read(message
, "s", &name
);
695 machine
= hashmap_get(m
->machines
, name
);
697 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
699 return bus_machine_method_copy(message
, machine
, error
);
702 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
703 _cleanup_(image_unrefp
) Image
* i
= NULL
;
709 r
= sd_bus_message_read(message
, "s", &name
);
713 if (!image_name_is_valid(name
))
714 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
716 r
= image_find(name
, &i
);
720 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
722 i
->userdata
= userdata
;
723 return bus_image_method_remove(message
, i
, error
);
726 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
727 _cleanup_(image_unrefp
) Image
* i
= NULL
;
728 const char *old_name
;
733 r
= sd_bus_message_read(message
, "s", &old_name
);
737 if (!image_name_is_valid(old_name
))
738 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
740 r
= image_find(old_name
, &i
);
744 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
746 i
->userdata
= userdata
;
747 return bus_image_method_rename(message
, i
, error
);
750 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
751 _cleanup_(image_unrefp
) Image
*i
= NULL
;
752 const char *old_name
;
757 r
= sd_bus_message_read(message
, "s", &old_name
);
761 if (!image_name_is_valid(old_name
))
762 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
764 r
= image_find(old_name
, &i
);
768 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
770 i
->userdata
= userdata
;
771 return bus_image_method_clone(message
, i
, error
);
774 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
775 _cleanup_(image_unrefp
) Image
*i
= NULL
;
781 r
= sd_bus_message_read(message
, "s", &name
);
785 if (!image_name_is_valid(name
))
786 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
788 r
= image_find(name
, &i
);
792 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
794 i
->userdata
= userdata
;
795 return bus_image_method_mark_read_only(message
, i
, error
);
798 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
799 Manager
*m
= userdata
;
805 r
= sd_bus_message_read(message
, "t", &limit
);
809 r
= bus_verify_polkit_async(
812 "org.freedesktop.machine1.manage-machines",
820 return 1; /* Will call us back */
822 /* Set up the machine directory if necessary */
823 r
= setup_machine_directory(limit
, error
);
827 r
= btrfs_resize_loopback("/var/lib/machines", limit
, false);
829 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
830 if (r
< 0 && r
!= -ENODEV
) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
831 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust loopback limit: %m");
833 r
= btrfs_quota_limit("/var/lib/machines", limit
);
835 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
837 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
839 return sd_bus_reply_method_return(message
, NULL
);
842 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
843 _cleanup_(image_unrefp
) Image
*i
= NULL
;
849 r
= sd_bus_message_read(message
, "s", &name
);
853 if (!image_name_is_valid(name
))
854 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
856 r
= image_find(name
, &i
);
860 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
862 i
->userdata
= userdata
;
863 return bus_image_method_set_limit(message
, i
, error
);
866 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
867 _cleanup_fclose_
FILE *f
= NULL
;
868 Manager
*m
= userdata
;
869 const char *name
, *p
;
874 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
878 if (UID_IS_INVALID(uid
))
879 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
881 machine
= hashmap_get(m
->machines
, name
);
883 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
885 if (machine
->class != MACHINE_CONTAINER
)
886 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
888 p
= procfs_file_alloca(machine
->leader
, "uid_map");
894 uid_t uid_base
, uid_shift
, uid_range
, converted
;
898 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
899 if (k
< 0 && feof(f
))
902 if (ferror(f
) && errno
!= 0)
908 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
911 converted
= uid
- uid_base
+ uid_shift
;
912 if (UID_IS_INVALID(converted
))
913 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
915 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
918 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
921 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
922 Manager
*m
= userdata
;
928 r
= sd_bus_message_read(message
, "u", &uid
);
931 if (UID_IS_INVALID(uid
))
932 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
934 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
936 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
937 _cleanup_fclose_
FILE *f
= NULL
;
938 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
940 if (machine
->class != MACHINE_CONTAINER
)
943 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
946 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
951 _cleanup_free_
char *o
= NULL
;
952 uid_t uid_base
, uid_shift
, uid_range
, converted
;
956 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
957 if (k
< 0 && feof(f
))
960 if (ferror(f
) && errno
!= 0)
966 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
969 converted
= (uid
- uid_shift
+ uid_base
);
970 if (UID_IS_INVALID(converted
))
971 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
973 o
= machine_bus_path(machine
);
977 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
981 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
984 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
985 _cleanup_fclose_
FILE *f
= NULL
;
986 Manager
*m
= groupdata
;
987 const char *name
, *p
;
992 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
996 if (GID_IS_INVALID(gid
))
997 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
999 machine
= hashmap_get(m
->machines
, name
);
1001 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1003 if (machine
->class != MACHINE_CONTAINER
)
1004 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1006 p
= procfs_file_alloca(machine
->leader
, "gid_map");
1012 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1016 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1017 if (k
< 0 && feof(f
))
1020 if (ferror(f
) && errno
!= 0)
1026 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
1029 converted
= gid
- gid_base
+ gid_shift
;
1030 if (GID_IS_INVALID(converted
))
1031 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1033 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1036 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1039 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1040 Manager
*m
= groupdata
;
1046 r
= sd_bus_message_read(message
, "u", &gid
);
1049 if (GID_IS_INVALID(gid
))
1050 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1052 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1054 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1055 _cleanup_fclose_
FILE *f
= NULL
;
1056 char p
[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1058 if (machine
->class != MACHINE_CONTAINER
)
1061 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1064 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1069 _cleanup_free_
char *o
= NULL
;
1070 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1074 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1075 if (k
< 0 && feof(f
))
1078 if (ferror(f
) && errno
!= 0)
1084 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1087 converted
= (gid
- gid_shift
+ gid_base
);
1088 if (GID_IS_INVALID(converted
))
1089 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1091 o
= machine_bus_path(machine
);
1095 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1099 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1102 const sd_bus_vtable manager_vtable
[] = {
1103 SD_BUS_VTABLE_START(0),
1104 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1105 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1106 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1107 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1108 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1109 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1110 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1111 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1112 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1113 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1114 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1115 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1116 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1117 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1118 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1119 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1120 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1121 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1122 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1123 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1124 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1125 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1126 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1127 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1128 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1129 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1130 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1131 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1132 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1133 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1134 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1135 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1136 SD_BUS_SIGNAL("MachineNew", "so", 0),
1137 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1141 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1142 const char *path
, *result
, *unit
;
1143 Manager
*m
= userdata
;
1151 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1153 bus_log_parse_error(r
);
1157 machine
= hashmap_get(m
->machine_units
, unit
);
1161 if (streq_ptr(path
, machine
->scope_job
)) {
1162 machine
->scope_job
= mfree(machine
->scope_job
);
1164 if (machine
->started
) {
1165 if (streq(result
, "done"))
1166 machine_send_create_reply(machine
, NULL
);
1168 _cleanup_bus_error_free_ sd_bus_error e
= SD_BUS_ERROR_NULL
;
1170 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1172 machine_send_create_reply(machine
, &e
);
1176 machine_save(machine
);
1179 machine_add_to_gc_queue(machine
);
1183 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1184 _cleanup_free_
char *unit
= NULL
;
1186 Manager
*m
= userdata
;
1193 path
= sd_bus_message_get_path(message
);
1197 r
= unit_name_from_dbus_path(path
, &unit
);
1198 if (r
== -EINVAL
) /* not for a unit */
1205 machine
= hashmap_get(m
->machine_units
, unit
);
1209 machine_add_to_gc_queue(machine
);
1213 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1214 const char *path
, *unit
;
1215 Manager
*m
= userdata
;
1222 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1224 bus_log_parse_error(r
);
1228 machine
= hashmap_get(m
->machine_units
, unit
);
1232 machine_add_to_gc_queue(machine
);
1236 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1237 Manager
*m
= userdata
;
1245 r
= sd_bus_message_read(message
, "b", &b
);
1247 bus_log_parse_error(r
);
1253 /* systemd finished reloading, let's recheck all our machines */
1254 log_debug("System manager has been reloaded, rechecking machines...");
1256 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1257 machine_add_to_gc_queue(machine
);
1262 int manager_start_scope(
1267 const char *description
,
1268 sd_bus_message
*more_properties
,
1269 sd_bus_error
*error
,
1272 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1279 r
= sd_bus_message_new_method_call(
1282 "org.freedesktop.systemd1",
1283 "/org/freedesktop/systemd1",
1284 "org.freedesktop.systemd1.Manager",
1285 "StartTransientUnit");
1289 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1293 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1297 if (!isempty(slice
)) {
1298 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1303 if (!isempty(description
)) {
1304 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1309 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, pid
);
1313 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
1317 if (more_properties
) {
1318 r
= sd_bus_message_copy(m
, more_properties
, true);
1323 r
= sd_bus_message_close_container(m
);
1327 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1331 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1339 r
= sd_bus_message_read(reply
, "o", &j
);
1353 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1354 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1360 r
= sd_bus_call_method(
1362 "org.freedesktop.systemd1",
1363 "/org/freedesktop/systemd1",
1364 "org.freedesktop.systemd1.Manager",
1368 "ss", unit
, "fail");
1370 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1371 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1376 sd_bus_error_free(error
);
1387 r
= sd_bus_message_read(reply
, "o", &j
);
1401 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1405 return sd_bus_call_method(
1407 "org.freedesktop.systemd1",
1408 "/org/freedesktop/systemd1",
1409 "org.freedesktop.systemd1.Manager",
1413 "ssi", unit
, "all", signo
);
1416 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1417 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1418 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1419 _cleanup_free_
char *path
= NULL
;
1426 path
= unit_dbus_path_from_name(unit
);
1430 r
= sd_bus_get_property(
1432 "org.freedesktop.systemd1",
1434 "org.freedesktop.systemd1.Unit",
1440 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1441 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1444 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1445 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1451 r
= sd_bus_message_read(reply
, "s", &state
);
1455 return !STR_IN_SET(state
, "inactive", "failed");
1458 int manager_job_is_active(Manager
*manager
, const char *path
) {
1459 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1460 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1466 r
= sd_bus_get_property(
1468 "org.freedesktop.systemd1",
1470 "org.freedesktop.systemd1.Job",
1476 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1477 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1480 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1486 /* We don't actually care about the state really. The fact
1487 * that we could read the job state is enough for us */
1492 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1500 mm
= hashmap_get(m
->machine_leaders
, UINT_TO_PTR(pid
));
1502 _cleanup_free_
char *unit
= NULL
;
1504 r
= cg_pid_get_unit(pid
, &unit
);
1506 mm
= hashmap_get(m
->machine_units
, unit
);
1515 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1521 machine
= hashmap_get(m
->machines
, name
);
1523 machine
= machine_new(m
, _MACHINE_CLASS_INVALID
, name
);
1529 *_machine
= machine
;