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
);
206 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
208 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
212 r
= sd_bus_creds_get_pid(creds
, &pid
);
217 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
221 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
223 p
= machine_bus_path(machine
);
227 return sd_bus_reply_method_return(message
, "o", p
);
230 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
231 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
232 Manager
*m
= userdata
;
240 r
= sd_bus_message_new_method_return(message
, &reply
);
242 return sd_bus_error_set_errno(error
, r
);
244 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
246 return sd_bus_error_set_errno(error
, r
);
248 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
249 _cleanup_free_
char *p
= NULL
;
251 p
= machine_bus_path(machine
);
255 r
= sd_bus_message_append(reply
, "(ssso)",
257 strempty(machine_class_to_string(machine
->class)),
261 return sd_bus_error_set_errno(error
, r
);
264 r
= sd_bus_message_close_container(reply
);
266 return sd_bus_error_set_errno(error
, r
);
268 return sd_bus_send(NULL
, reply
, NULL
);
271 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
272 const char *name
, *service
, *class, *root_directory
;
273 const int32_t *netif
= NULL
;
279 size_t n
, n_netif
= 0;
286 r
= sd_bus_message_read(message
, "s", &name
);
289 if (!machine_name_is_valid(name
))
290 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
292 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
300 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
302 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
309 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
313 n_netif
/= sizeof(int32_t);
315 for (i
= 0; i
< n_netif
; i
++) {
317 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
322 c
= _MACHINE_CLASS_INVALID
;
324 c
= machine_class_from_string(class);
326 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
330 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
332 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
333 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
336 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
338 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
342 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
344 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
349 if (hashmap_get(manager
->machines
, name
))
350 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
352 r
= manager_add_machine(manager
, name
, &m
);
360 if (!isempty(service
)) {
361 m
->service
= strdup(service
);
368 if (!isempty(root_directory
)) {
369 m
->root_directory
= strdup(root_directory
);
370 if (!m
->root_directory
) {
377 assert_cc(sizeof(int32_t) == sizeof(int));
378 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
384 m
->n_netif
= n_netif
;
392 machine_add_to_gc_queue(m
);
396 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
397 Manager
*manager
= userdata
;
404 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
408 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
412 r
= machine_start(m
, message
, error
);
416 m
->create_message
= sd_bus_message_ref(message
);
420 machine_add_to_gc_queue(m
);
424 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
425 return method_create_machine_internal(message
, true, userdata
, error
);
428 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
429 return method_create_machine_internal(message
, false, userdata
, error
);
432 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
433 Manager
*manager
= userdata
;
434 _cleanup_free_
char *p
= NULL
;
441 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
445 r
= cg_pid_get_unit(m
->leader
, &m
->unit
);
447 r
= sd_bus_error_set_errnof(error
, r
, "Failed to determine unit of process "PID_FMT
" : %s", m
->leader
, strerror(-r
));
451 r
= machine_start(m
, NULL
, error
);
455 p
= machine_bus_path(m
);
461 return sd_bus_reply_method_return(message
, "o", p
);
464 machine_add_to_gc_queue(m
);
468 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
469 return method_register_machine_internal(message
, true, userdata
, error
);
472 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
473 return method_register_machine_internal(message
, false, userdata
, error
);
476 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
477 Manager
*m
= userdata
;
485 r
= sd_bus_message_read(message
, "s", &name
);
487 return sd_bus_error_set_errno(error
, r
);
489 machine
= hashmap_get(m
->machines
, name
);
491 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
493 return bus_machine_method_terminate(message
, machine
, error
);
496 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
497 Manager
*m
= userdata
;
505 r
= sd_bus_message_read(message
, "s", &name
);
507 return sd_bus_error_set_errno(error
, r
);
509 machine
= hashmap_get(m
->machines
, name
);
511 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
513 return bus_machine_method_kill(message
, machine
, error
);
516 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
517 Manager
*m
= userdata
;
525 r
= sd_bus_message_read(message
, "s", &name
);
527 return sd_bus_error_set_errno(error
, r
);
529 machine
= hashmap_get(m
->machines
, name
);
531 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
533 return bus_machine_method_get_addresses(message
, machine
, error
);
536 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
537 Manager
*m
= userdata
;
545 r
= sd_bus_message_read(message
, "s", &name
);
547 return sd_bus_error_set_errno(error
, r
);
549 machine
= hashmap_get(m
->machines
, name
);
551 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
553 return bus_machine_method_get_os_release(message
, machine
, error
);
556 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
557 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
558 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
559 Manager
*m
= userdata
;
567 images
= hashmap_new(&string_hash_ops
);
571 r
= image_discover(images
);
575 r
= sd_bus_message_new_method_return(message
, &reply
);
579 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
583 HASHMAP_FOREACH(image
, images
, i
) {
584 _cleanup_free_
char *p
= NULL
;
586 p
= image_bus_path(image
->name
);
590 r
= sd_bus_message_append(reply
, "(ssbttto)",
592 image_type_to_string(image
->type
),
602 r
= sd_bus_message_close_container(reply
);
606 return sd_bus_send(NULL
, reply
, NULL
);
609 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
610 Manager
*m
= userdata
;
618 r
= sd_bus_message_read(message
, "s", &name
);
620 return sd_bus_error_set_errno(error
, r
);
622 machine
= hashmap_get(m
->machines
, name
);
624 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
626 return bus_machine_method_open_pty(message
, machine
, error
);
629 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
630 Manager
*m
= userdata
;
638 r
= sd_bus_message_read(message
, "s", &name
);
642 machine
= hashmap_get(m
->machines
, name
);
644 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
646 return bus_machine_method_open_login(message
, machine
, error
);
649 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
650 Manager
*m
= userdata
;
659 r
= sd_bus_message_read(message
, "s", &name
);
663 machine
= hashmap_get(m
->machines
, name
);
665 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
667 return bus_machine_method_open_shell(message
, machine
, error
);
670 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
671 Manager
*m
= userdata
;
679 r
= sd_bus_message_read(message
, "s", &name
);
683 machine
= hashmap_get(m
->machines
, name
);
685 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
687 return bus_machine_method_bind_mount(message
, machine
, error
);
690 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
691 Manager
*m
= userdata
;
699 r
= sd_bus_message_read(message
, "s", &name
);
703 machine
= hashmap_get(m
->machines
, name
);
705 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
707 return bus_machine_method_copy(message
, machine
, error
);
710 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
711 _cleanup_(image_unrefp
) Image
* i
= NULL
;
717 r
= sd_bus_message_read(message
, "s", &name
);
721 if (!image_name_is_valid(name
))
722 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
724 r
= image_find(name
, &i
);
728 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
730 i
->userdata
= userdata
;
731 return bus_image_method_remove(message
, i
, error
);
734 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
735 _cleanup_(image_unrefp
) Image
* i
= NULL
;
736 const char *old_name
;
741 r
= sd_bus_message_read(message
, "s", &old_name
);
745 if (!image_name_is_valid(old_name
))
746 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
748 r
= image_find(old_name
, &i
);
752 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
754 i
->userdata
= userdata
;
755 return bus_image_method_rename(message
, i
, error
);
758 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
759 _cleanup_(image_unrefp
) Image
*i
= NULL
;
760 const char *old_name
;
765 r
= sd_bus_message_read(message
, "s", &old_name
);
769 if (!image_name_is_valid(old_name
))
770 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
772 r
= image_find(old_name
, &i
);
776 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
778 i
->userdata
= userdata
;
779 return bus_image_method_clone(message
, i
, error
);
782 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
783 _cleanup_(image_unrefp
) Image
*i
= NULL
;
789 r
= sd_bus_message_read(message
, "s", &name
);
793 if (!image_name_is_valid(name
))
794 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
796 r
= image_find(name
, &i
);
800 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
802 i
->userdata
= userdata
;
803 return bus_image_method_mark_read_only(message
, i
, error
);
806 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
807 Manager
*m
= userdata
;
813 r
= sd_bus_message_read(message
, "t", &limit
);
817 r
= bus_verify_polkit_async(
820 "org.freedesktop.machine1.manage-machines",
829 return 1; /* Will call us back */
831 /* Set up the machine directory if necessary */
832 r
= setup_machine_directory(limit
, error
);
836 r
= btrfs_resize_loopback("/var/lib/machines", limit
, false);
838 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
839 if (r
< 0 && r
!= -ENODEV
) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
840 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust loopback limit: %m");
842 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit
);
844 r
= btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit
);
846 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
848 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
850 return sd_bus_reply_method_return(message
, NULL
);
853 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
854 _cleanup_(image_unrefp
) Image
*i
= NULL
;
860 r
= sd_bus_message_read(message
, "s", &name
);
864 if (!image_name_is_valid(name
))
865 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
867 r
= image_find(name
, &i
);
871 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
873 i
->userdata
= userdata
;
874 return bus_image_method_set_limit(message
, i
, error
);
877 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
878 _cleanup_fclose_
FILE *f
= NULL
;
879 Manager
*m
= userdata
;
880 const char *name
, *p
;
885 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
889 if (!uid_is_valid(uid
))
890 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
892 machine
= hashmap_get(m
->machines
, name
);
894 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
896 if (machine
->class != MACHINE_CONTAINER
)
897 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
899 p
= procfs_file_alloca(machine
->leader
, "uid_map");
905 uid_t uid_base
, uid_shift
, uid_range
, converted
;
909 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
910 if (k
< 0 && feof(f
))
913 if (ferror(f
) && errno
!= 0)
919 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
922 converted
= uid
- uid_base
+ uid_shift
;
923 if (!uid_is_valid(converted
))
924 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
926 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
929 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
932 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
933 Manager
*m
= userdata
;
939 r
= sd_bus_message_read(message
, "u", &uid
);
942 if (!uid_is_valid(uid
))
943 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
945 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
947 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
948 _cleanup_fclose_
FILE *f
= NULL
;
949 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
951 if (machine
->class != MACHINE_CONTAINER
)
954 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
957 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
962 _cleanup_free_
char *o
= NULL
;
963 uid_t uid_base
, uid_shift
, uid_range
, converted
;
967 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
968 if (k
< 0 && feof(f
))
971 if (ferror(f
) && errno
!= 0)
977 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
980 converted
= (uid
- uid_shift
+ uid_base
);
981 if (!uid_is_valid(converted
))
982 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
984 o
= machine_bus_path(machine
);
988 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
992 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
995 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
996 _cleanup_fclose_
FILE *f
= NULL
;
997 Manager
*m
= groupdata
;
998 const char *name
, *p
;
1003 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
1007 if (!gid_is_valid(gid
))
1008 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1010 machine
= hashmap_get(m
->machines
, name
);
1012 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1014 if (machine
->class != MACHINE_CONTAINER
)
1015 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1017 p
= procfs_file_alloca(machine
->leader
, "gid_map");
1023 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1027 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1028 if (k
< 0 && feof(f
))
1031 if (ferror(f
) && errno
!= 0)
1037 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
1040 converted
= gid
- gid_base
+ gid_shift
;
1041 if (!gid_is_valid(converted
))
1042 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1044 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1047 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1050 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1051 Manager
*m
= groupdata
;
1057 r
= sd_bus_message_read(message
, "u", &gid
);
1060 if (!gid_is_valid(gid
))
1061 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1063 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1065 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1066 _cleanup_fclose_
FILE *f
= NULL
;
1067 char p
[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1069 if (machine
->class != MACHINE_CONTAINER
)
1072 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1075 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1080 _cleanup_free_
char *o
= NULL
;
1081 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1085 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1086 if (k
< 0 && feof(f
))
1089 if (ferror(f
) && errno
!= 0)
1095 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1098 converted
= (gid
- gid_shift
+ gid_base
);
1099 if (!gid_is_valid(converted
))
1100 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1102 o
= machine_bus_path(machine
);
1106 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1110 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1113 const sd_bus_vtable manager_vtable
[] = {
1114 SD_BUS_VTABLE_START(0),
1115 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1116 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1117 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1118 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1119 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1120 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1121 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1122 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1123 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1124 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1125 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1126 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1127 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1128 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1129 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1130 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1131 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1132 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1133 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1134 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1135 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1136 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1137 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1138 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1139 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1140 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1141 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1142 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1143 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1144 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1145 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1146 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1147 SD_BUS_SIGNAL("MachineNew", "so", 0),
1148 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1152 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1153 const char *path
, *result
, *unit
;
1154 Manager
*m
= userdata
;
1162 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1164 bus_log_parse_error(r
);
1168 machine
= hashmap_get(m
->machine_units
, unit
);
1172 if (streq_ptr(path
, machine
->scope_job
)) {
1173 machine
->scope_job
= mfree(machine
->scope_job
);
1175 if (machine
->started
) {
1176 if (streq(result
, "done"))
1177 machine_send_create_reply(machine
, NULL
);
1179 _cleanup_(sd_bus_error_free
) sd_bus_error e
= SD_BUS_ERROR_NULL
;
1181 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1183 machine_send_create_reply(machine
, &e
);
1187 machine_save(machine
);
1190 machine_add_to_gc_queue(machine
);
1194 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1195 _cleanup_free_
char *unit
= NULL
;
1197 Manager
*m
= userdata
;
1204 path
= sd_bus_message_get_path(message
);
1208 r
= unit_name_from_dbus_path(path
, &unit
);
1209 if (r
== -EINVAL
) /* not for a unit */
1216 machine
= hashmap_get(m
->machine_units
, unit
);
1220 machine_add_to_gc_queue(machine
);
1224 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1225 const char *path
, *unit
;
1226 Manager
*m
= userdata
;
1233 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1235 bus_log_parse_error(r
);
1239 machine
= hashmap_get(m
->machine_units
, unit
);
1243 machine_add_to_gc_queue(machine
);
1247 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1248 Manager
*m
= userdata
;
1256 r
= sd_bus_message_read(message
, "b", &b
);
1258 bus_log_parse_error(r
);
1264 /* systemd finished reloading, let's recheck all our machines */
1265 log_debug("System manager has been reloaded, rechecking machines...");
1267 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1268 machine_add_to_gc_queue(machine
);
1273 int manager_start_scope(
1278 const char *description
,
1279 sd_bus_message
*more_properties
,
1280 sd_bus_error
*error
,
1283 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1290 r
= sd_bus_message_new_method_call(
1293 "org.freedesktop.systemd1",
1294 "/org/freedesktop/systemd1",
1295 "org.freedesktop.systemd1.Manager",
1296 "StartTransientUnit");
1300 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1304 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1308 if (!isempty(slice
)) {
1309 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1314 if (!isempty(description
)) {
1315 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1320 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, pid
);
1324 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
1328 if (more_properties
) {
1329 r
= sd_bus_message_copy(m
, more_properties
, true);
1334 r
= sd_bus_message_close_container(m
);
1338 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1342 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1350 r
= sd_bus_message_read(reply
, "o", &j
);
1364 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1365 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1371 r
= sd_bus_call_method(
1373 "org.freedesktop.systemd1",
1374 "/org/freedesktop/systemd1",
1375 "org.freedesktop.systemd1.Manager",
1379 "ss", unit
, "fail");
1381 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1382 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1387 sd_bus_error_free(error
);
1398 r
= sd_bus_message_read(reply
, "o", &j
);
1412 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1416 return sd_bus_call_method(
1418 "org.freedesktop.systemd1",
1419 "/org/freedesktop/systemd1",
1420 "org.freedesktop.systemd1.Manager",
1424 "ssi", unit
, "all", signo
);
1427 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1428 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1429 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1430 _cleanup_free_
char *path
= NULL
;
1437 path
= unit_dbus_path_from_name(unit
);
1441 r
= sd_bus_get_property(
1443 "org.freedesktop.systemd1",
1445 "org.freedesktop.systemd1.Unit",
1451 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1452 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1455 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1456 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1462 r
= sd_bus_message_read(reply
, "s", &state
);
1466 return !STR_IN_SET(state
, "inactive", "failed");
1469 int manager_job_is_active(Manager
*manager
, const char *path
) {
1470 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1471 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1477 r
= sd_bus_get_property(
1479 "org.freedesktop.systemd1",
1481 "org.freedesktop.systemd1.Job",
1487 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1488 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1491 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1497 /* We don't actually care about the state really. The fact
1498 * that we could read the job state is enough for us */
1503 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1511 mm
= hashmap_get(m
->machine_leaders
, PID_TO_PTR(pid
));
1513 _cleanup_free_
char *unit
= NULL
;
1515 r
= cg_pid_get_unit(pid
, &unit
);
1517 mm
= hashmap_get(m
->machine_units
, unit
);
1526 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1532 machine
= hashmap_get(m
->machines
, name
);
1534 machine
= machine_new(m
, _MACHINE_CLASS_INVALID
, name
);
1540 *_machine
= machine
;