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 "alloc-util.h"
29 #include "btrfs-util.h"
30 #include "bus-common-errors.h"
32 #include "cgroup-util.h"
34 #include "formats-util.h"
35 #include "hostname-util.h"
36 #include "image-dbus.h"
37 #include "machine-dbus.h"
38 #include "machine-image.h"
39 #include "machine-pool.h"
41 #include "path-util.h"
42 #include "process-util.h"
43 #include "stdio-util.h"
45 #include "unit-name.h"
46 #include "user-util.h"
48 static int property_get_pool_path(
51 const char *interface
,
53 sd_bus_message
*reply
,
55 sd_bus_error
*error
) {
60 return sd_bus_message_append(reply
, "s", "/var/lib/machines");
63 static int property_get_pool_usage(
66 const char *interface
,
68 sd_bus_message
*reply
,
70 sd_bus_error
*error
) {
72 _cleanup_close_
int fd
= -1;
73 uint64_t usage
= (uint64_t) -1;
79 /* We try to read the quota info from /var/lib/machines, as
80 * well as the usage of the loopback file
81 * /var/lib/machines.raw, and pick the larger value. */
83 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
87 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
91 if (stat("/var/lib/machines.raw", &st
) >= 0) {
92 if (usage
== (uint64_t) -1 || st
.st_blocks
* 512ULL > usage
)
93 usage
= st
.st_blocks
* 512ULL;
96 return sd_bus_message_append(reply
, "t", usage
);
99 static int property_get_pool_limit(
102 const char *interface
,
103 const char *property
,
104 sd_bus_message
*reply
,
106 sd_bus_error
*error
) {
108 _cleanup_close_
int fd
= -1;
109 uint64_t size
= (uint64_t) -1;
115 /* We try to read the quota limit from /var/lib/machines, as
116 * well as the size of the loopback file
117 * /var/lib/machines.raw, and pick the smaller value. */
119 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
123 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
124 size
= q
.referenced_max
;
127 if (stat("/var/lib/machines.raw", &st
) >= 0) {
128 if (size
== (uint64_t) -1 || (uint64_t) st
.st_size
< size
)
132 return sd_bus_message_append(reply
, "t", size
);
135 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
136 _cleanup_free_
char *p
= NULL
;
137 Manager
*m
= userdata
;
145 r
= sd_bus_message_read(message
, "s", &name
);
149 machine
= hashmap_get(m
->machines
, name
);
151 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
153 p
= machine_bus_path(machine
);
157 return sd_bus_reply_method_return(message
, "o", p
);
160 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
161 _cleanup_free_
char *p
= NULL
;
162 Manager
*m
= userdata
;
169 r
= sd_bus_message_read(message
, "s", &name
);
173 r
= image_find(name
, NULL
);
175 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
179 p
= image_bus_path(name
);
183 return sd_bus_reply_method_return(message
, "o", p
);
186 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
187 _cleanup_free_
char *p
= NULL
;
188 Manager
*m
= userdata
;
189 Machine
*machine
= NULL
;
196 assert_cc(sizeof(pid_t
) == sizeof(uint32_t));
198 r
= sd_bus_message_read(message
, "u", &pid
);
203 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
205 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
209 r
= sd_bus_creds_get_pid(creds
, &pid
);
214 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
218 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
220 p
= machine_bus_path(machine
);
224 return sd_bus_reply_method_return(message
, "o", p
);
227 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
228 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
229 Manager
*m
= userdata
;
237 r
= sd_bus_message_new_method_return(message
, &reply
);
239 return sd_bus_error_set_errno(error
, r
);
241 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
243 return sd_bus_error_set_errno(error
, r
);
245 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
246 _cleanup_free_
char *p
= NULL
;
248 p
= machine_bus_path(machine
);
252 r
= sd_bus_message_append(reply
, "(ssso)",
254 strempty(machine_class_to_string(machine
->class)),
258 return sd_bus_error_set_errno(error
, r
);
261 r
= sd_bus_message_close_container(reply
);
263 return sd_bus_error_set_errno(error
, r
);
265 return sd_bus_send(NULL
, reply
, NULL
);
268 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
269 const char *name
, *service
, *class, *root_directory
;
270 const int32_t *netif
= NULL
;
276 size_t n
, n_netif
= 0;
283 r
= sd_bus_message_read(message
, "s", &name
);
286 if (!machine_name_is_valid(name
))
287 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
289 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
297 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
299 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
306 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
310 n_netif
/= sizeof(int32_t);
312 for (i
= 0; i
< n_netif
; i
++) {
314 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
319 c
= _MACHINE_CLASS_INVALID
;
321 c
= machine_class_from_string(class);
323 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
327 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
329 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
330 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
333 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
335 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
339 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
341 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
346 if (hashmap_get(manager
->machines
, name
))
347 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
349 r
= manager_add_machine(manager
, name
, &m
);
357 if (!isempty(service
)) {
358 m
->service
= strdup(service
);
365 if (!isempty(root_directory
)) {
366 m
->root_directory
= strdup(root_directory
);
367 if (!m
->root_directory
) {
374 assert_cc(sizeof(int32_t) == sizeof(int));
375 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
381 m
->n_netif
= n_netif
;
389 machine_add_to_gc_queue(m
);
393 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
394 Manager
*manager
= userdata
;
401 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
405 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
409 r
= machine_start(m
, message
, error
);
413 m
->create_message
= sd_bus_message_ref(message
);
417 machine_add_to_gc_queue(m
);
421 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
422 return method_create_machine_internal(message
, true, userdata
, error
);
425 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
426 return method_create_machine_internal(message
, false, userdata
, error
);
429 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
430 Manager
*manager
= userdata
;
431 _cleanup_free_
char *p
= NULL
;
438 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
442 r
= cg_pid_get_unit(m
->leader
, &m
->unit
);
444 r
= sd_bus_error_set_errnof(error
, r
, "Failed to determine unit of process "PID_FMT
" : %s", m
->leader
, strerror(-r
));
448 r
= machine_start(m
, NULL
, error
);
452 p
= machine_bus_path(m
);
458 return sd_bus_reply_method_return(message
, "o", p
);
461 machine_add_to_gc_queue(m
);
465 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
466 return method_register_machine_internal(message
, true, userdata
, error
);
469 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
470 return method_register_machine_internal(message
, false, userdata
, error
);
473 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
474 Manager
*m
= userdata
;
482 r
= sd_bus_message_read(message
, "s", &name
);
484 return sd_bus_error_set_errno(error
, r
);
486 machine
= hashmap_get(m
->machines
, name
);
488 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
490 return bus_machine_method_terminate(message
, machine
, error
);
493 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
494 Manager
*m
= userdata
;
502 r
= sd_bus_message_read(message
, "s", &name
);
504 return sd_bus_error_set_errno(error
, r
);
506 machine
= hashmap_get(m
->machines
, name
);
508 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
510 return bus_machine_method_kill(message
, machine
, error
);
513 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
514 Manager
*m
= userdata
;
522 r
= sd_bus_message_read(message
, "s", &name
);
524 return sd_bus_error_set_errno(error
, r
);
526 machine
= hashmap_get(m
->machines
, name
);
528 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
530 return bus_machine_method_get_addresses(message
, machine
, error
);
533 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
534 Manager
*m
= userdata
;
542 r
= sd_bus_message_read(message
, "s", &name
);
544 return sd_bus_error_set_errno(error
, r
);
546 machine
= hashmap_get(m
->machines
, name
);
548 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
550 return bus_machine_method_get_os_release(message
, machine
, error
);
553 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
554 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
555 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
556 Manager
*m
= userdata
;
564 images
= hashmap_new(&string_hash_ops
);
568 r
= image_discover(images
);
572 r
= sd_bus_message_new_method_return(message
, &reply
);
576 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
580 HASHMAP_FOREACH(image
, images
, i
) {
581 _cleanup_free_
char *p
= NULL
;
583 p
= image_bus_path(image
->name
);
587 r
= sd_bus_message_append(reply
, "(ssbttto)",
589 image_type_to_string(image
->type
),
599 r
= sd_bus_message_close_container(reply
);
603 return sd_bus_send(NULL
, reply
, NULL
);
606 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
607 Manager
*m
= userdata
;
615 r
= sd_bus_message_read(message
, "s", &name
);
617 return sd_bus_error_set_errno(error
, r
);
619 machine
= hashmap_get(m
->machines
, name
);
621 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
623 return bus_machine_method_open_pty(message
, machine
, error
);
626 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
627 Manager
*m
= userdata
;
635 r
= sd_bus_message_read(message
, "s", &name
);
639 machine
= hashmap_get(m
->machines
, name
);
641 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
643 return bus_machine_method_open_login(message
, machine
, error
);
646 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
647 Manager
*m
= userdata
;
656 r
= sd_bus_message_read(message
, "s", &name
);
660 machine
= hashmap_get(m
->machines
, name
);
662 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
664 return bus_machine_method_open_shell(message
, machine
, error
);
667 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
668 Manager
*m
= userdata
;
676 r
= sd_bus_message_read(message
, "s", &name
);
680 machine
= hashmap_get(m
->machines
, name
);
682 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
684 return bus_machine_method_bind_mount(message
, machine
, error
);
687 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
688 Manager
*m
= userdata
;
696 r
= sd_bus_message_read(message
, "s", &name
);
700 machine
= hashmap_get(m
->machines
, name
);
702 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
704 return bus_machine_method_copy(message
, machine
, error
);
707 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
708 _cleanup_(image_unrefp
) Image
* i
= NULL
;
714 r
= sd_bus_message_read(message
, "s", &name
);
718 if (!image_name_is_valid(name
))
719 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
721 r
= image_find(name
, &i
);
725 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
727 i
->userdata
= userdata
;
728 return bus_image_method_remove(message
, i
, error
);
731 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
732 _cleanup_(image_unrefp
) Image
* i
= NULL
;
733 const char *old_name
;
738 r
= sd_bus_message_read(message
, "s", &old_name
);
742 if (!image_name_is_valid(old_name
))
743 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
745 r
= image_find(old_name
, &i
);
749 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
751 i
->userdata
= userdata
;
752 return bus_image_method_rename(message
, i
, error
);
755 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
756 _cleanup_(image_unrefp
) Image
*i
= NULL
;
757 const char *old_name
;
762 r
= sd_bus_message_read(message
, "s", &old_name
);
766 if (!image_name_is_valid(old_name
))
767 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
769 r
= image_find(old_name
, &i
);
773 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
775 i
->userdata
= userdata
;
776 return bus_image_method_clone(message
, i
, error
);
779 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
780 _cleanup_(image_unrefp
) Image
*i
= NULL
;
786 r
= sd_bus_message_read(message
, "s", &name
);
790 if (!image_name_is_valid(name
))
791 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
793 r
= image_find(name
, &i
);
797 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
799 i
->userdata
= userdata
;
800 return bus_image_method_mark_read_only(message
, i
, error
);
803 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
804 Manager
*m
= userdata
;
810 r
= sd_bus_message_read(message
, "t", &limit
);
814 r
= bus_verify_polkit_async(
817 "org.freedesktop.machine1.manage-machines",
826 return 1; /* Will call us back */
828 /* Set up the machine directory if necessary */
829 r
= setup_machine_directory(limit
, error
);
833 r
= btrfs_resize_loopback("/var/lib/machines", limit
, false);
835 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
836 if (r
< 0 && r
!= -ENODEV
) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
837 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust loopback limit: %m");
839 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit
);
841 r
= btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit
);
843 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
845 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
847 return sd_bus_reply_method_return(message
, NULL
);
850 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
851 _cleanup_(image_unrefp
) Image
*i
= NULL
;
857 r
= sd_bus_message_read(message
, "s", &name
);
861 if (!image_name_is_valid(name
))
862 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
864 r
= image_find(name
, &i
);
868 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
870 i
->userdata
= userdata
;
871 return bus_image_method_set_limit(message
, i
, error
);
874 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
875 _cleanup_fclose_
FILE *f
= NULL
;
876 Manager
*m
= userdata
;
877 const char *name
, *p
;
882 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
886 if (!uid_is_valid(uid
))
887 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
889 machine
= hashmap_get(m
->machines
, name
);
891 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
893 if (machine
->class != MACHINE_CONTAINER
)
894 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
896 p
= procfs_file_alloca(machine
->leader
, "uid_map");
902 uid_t uid_base
, uid_shift
, uid_range
, converted
;
906 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
907 if (k
< 0 && feof(f
))
910 if (ferror(f
) && errno
!= 0)
916 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
919 converted
= uid
- uid_base
+ uid_shift
;
920 if (!uid_is_valid(converted
))
921 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
923 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
926 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
929 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
930 Manager
*m
= userdata
;
936 r
= sd_bus_message_read(message
, "u", &uid
);
939 if (!uid_is_valid(uid
))
940 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
942 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
944 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
945 _cleanup_fclose_
FILE *f
= NULL
;
946 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
948 if (machine
->class != MACHINE_CONTAINER
)
951 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
954 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
959 _cleanup_free_
char *o
= NULL
;
960 uid_t uid_base
, uid_shift
, uid_range
, converted
;
964 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
965 if (k
< 0 && feof(f
))
968 if (ferror(f
) && errno
!= 0)
974 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
977 converted
= (uid
- uid_shift
+ uid_base
);
978 if (!uid_is_valid(converted
))
979 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
981 o
= machine_bus_path(machine
);
985 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
989 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
992 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
993 _cleanup_fclose_
FILE *f
= NULL
;
994 Manager
*m
= groupdata
;
995 const char *name
, *p
;
1000 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
1004 if (!gid_is_valid(gid
))
1005 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1007 machine
= hashmap_get(m
->machines
, name
);
1009 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1011 if (machine
->class != MACHINE_CONTAINER
)
1012 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1014 p
= procfs_file_alloca(machine
->leader
, "gid_map");
1020 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1024 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1025 if (k
< 0 && feof(f
))
1028 if (ferror(f
) && errno
!= 0)
1034 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
1037 converted
= gid
- gid_base
+ gid_shift
;
1038 if (!gid_is_valid(converted
))
1039 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1041 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1044 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1047 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1048 Manager
*m
= groupdata
;
1054 r
= sd_bus_message_read(message
, "u", &gid
);
1057 if (!gid_is_valid(gid
))
1058 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1060 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1062 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1063 _cleanup_fclose_
FILE *f
= NULL
;
1064 char p
[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1066 if (machine
->class != MACHINE_CONTAINER
)
1069 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1072 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1077 _cleanup_free_
char *o
= NULL
;
1078 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1082 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1083 if (k
< 0 && feof(f
))
1086 if (ferror(f
) && errno
!= 0)
1092 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1095 converted
= (gid
- gid_shift
+ gid_base
);
1096 if (!gid_is_valid(converted
))
1097 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1099 o
= machine_bus_path(machine
);
1103 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1107 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1110 const sd_bus_vtable manager_vtable
[] = {
1111 SD_BUS_VTABLE_START(0),
1112 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1113 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1114 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1115 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1116 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1117 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1118 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1119 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1120 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1121 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1122 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1123 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1124 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1125 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1126 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1127 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1128 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1129 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1130 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1131 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1132 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1133 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1134 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1135 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1136 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1137 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1138 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1139 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1140 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1141 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1142 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1143 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1144 SD_BUS_SIGNAL("MachineNew", "so", 0),
1145 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1149 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1150 const char *path
, *result
, *unit
;
1151 Manager
*m
= userdata
;
1159 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1161 bus_log_parse_error(r
);
1165 machine
= hashmap_get(m
->machine_units
, unit
);
1169 if (streq_ptr(path
, machine
->scope_job
)) {
1170 machine
->scope_job
= mfree(machine
->scope_job
);
1172 if (machine
->started
) {
1173 if (streq(result
, "done"))
1174 machine_send_create_reply(machine
, NULL
);
1176 _cleanup_bus_error_free_ sd_bus_error e
= SD_BUS_ERROR_NULL
;
1178 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1180 machine_send_create_reply(machine
, &e
);
1184 machine_save(machine
);
1187 machine_add_to_gc_queue(machine
);
1191 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1192 _cleanup_free_
char *unit
= NULL
;
1194 Manager
*m
= userdata
;
1201 path
= sd_bus_message_get_path(message
);
1205 r
= unit_name_from_dbus_path(path
, &unit
);
1206 if (r
== -EINVAL
) /* not for a unit */
1213 machine
= hashmap_get(m
->machine_units
, unit
);
1217 machine_add_to_gc_queue(machine
);
1221 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1222 const char *path
, *unit
;
1223 Manager
*m
= userdata
;
1230 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1232 bus_log_parse_error(r
);
1236 machine
= hashmap_get(m
->machine_units
, unit
);
1240 machine_add_to_gc_queue(machine
);
1244 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1245 Manager
*m
= userdata
;
1253 r
= sd_bus_message_read(message
, "b", &b
);
1255 bus_log_parse_error(r
);
1261 /* systemd finished reloading, let's recheck all our machines */
1262 log_debug("System manager has been reloaded, rechecking machines...");
1264 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1265 machine_add_to_gc_queue(machine
);
1270 int manager_start_scope(
1275 const char *description
,
1276 sd_bus_message
*more_properties
,
1277 sd_bus_error
*error
,
1280 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1287 r
= sd_bus_message_new_method_call(
1290 "org.freedesktop.systemd1",
1291 "/org/freedesktop/systemd1",
1292 "org.freedesktop.systemd1.Manager",
1293 "StartTransientUnit");
1297 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1301 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1305 if (!isempty(slice
)) {
1306 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1311 if (!isempty(description
)) {
1312 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1317 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, pid
);
1321 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
1325 if (more_properties
) {
1326 r
= sd_bus_message_copy(m
, more_properties
, true);
1331 r
= sd_bus_message_close_container(m
);
1335 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1339 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1347 r
= sd_bus_message_read(reply
, "o", &j
);
1361 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1362 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1368 r
= sd_bus_call_method(
1370 "org.freedesktop.systemd1",
1371 "/org/freedesktop/systemd1",
1372 "org.freedesktop.systemd1.Manager",
1376 "ss", unit
, "fail");
1378 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1379 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1384 sd_bus_error_free(error
);
1395 r
= sd_bus_message_read(reply
, "o", &j
);
1409 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1413 return sd_bus_call_method(
1415 "org.freedesktop.systemd1",
1416 "/org/freedesktop/systemd1",
1417 "org.freedesktop.systemd1.Manager",
1421 "ssi", unit
, "all", signo
);
1424 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1425 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1426 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1427 _cleanup_free_
char *path
= NULL
;
1434 path
= unit_dbus_path_from_name(unit
);
1438 r
= sd_bus_get_property(
1440 "org.freedesktop.systemd1",
1442 "org.freedesktop.systemd1.Unit",
1448 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1449 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1452 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1453 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1459 r
= sd_bus_message_read(reply
, "s", &state
);
1463 return !STR_IN_SET(state
, "inactive", "failed");
1466 int manager_job_is_active(Manager
*manager
, const char *path
) {
1467 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1468 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1474 r
= sd_bus_get_property(
1476 "org.freedesktop.systemd1",
1478 "org.freedesktop.systemd1.Job",
1484 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1485 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1488 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1494 /* We don't actually care about the state really. The fact
1495 * that we could read the job state is enough for us */
1500 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1508 mm
= hashmap_get(m
->machine_leaders
, UINT_TO_PTR(pid
));
1510 _cleanup_free_
char *unit
= NULL
;
1512 r
= cg_pid_get_unit(pid
, &unit
);
1514 mm
= hashmap_get(m
->machine_units
, unit
);
1523 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1529 machine
= hashmap_get(m
->machines
, name
);
1531 machine
= machine_new(m
, _MACHINE_CLASS_INVALID
, name
);
1537 *_machine
= machine
;