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 "machine-image.h"
37 #include "machine-pool.h"
38 #include "image-dbus.h"
40 #include "machine-dbus.h"
42 static int property_get_pool_path(
45 const char *interface
,
47 sd_bus_message
*reply
,
49 sd_bus_error
*error
) {
54 return sd_bus_message_append(reply
, "s", "/var/lib/machines");
57 static int property_get_pool_usage(
60 const char *interface
,
62 sd_bus_message
*reply
,
64 sd_bus_error
*error
) {
66 _cleanup_close_
int fd
= -1;
67 uint64_t usage
= (uint64_t) -1;
73 /* We try to read the quota info from /var/lib/machines, as
74 * well as the usage of the loopback file
75 * /var/lib/machines.raw, and pick the larger value. */
77 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
81 if (btrfs_subvol_get_quota_fd(fd
, &q
) >= 0)
85 if (stat("/var/lib/machines.raw", &st
) >= 0) {
86 if (usage
== (uint64_t) -1 || st
.st_blocks
* 512ULL > usage
)
87 usage
= st
.st_blocks
* 512ULL;
90 return sd_bus_message_append(reply
, "t", usage
);
93 static int property_get_pool_limit(
96 const char *interface
,
98 sd_bus_message
*reply
,
100 sd_bus_error
*error
) {
102 _cleanup_close_
int fd
= -1;
103 uint64_t size
= (uint64_t) -1;
109 /* We try to read the quota limit from /var/lib/machines, as
110 * well as the size of the loopback file
111 * /var/lib/machines.raw, and pick the smaller value. */
113 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
117 if (btrfs_subvol_get_quota_fd(fd
, &q
) >= 0)
118 size
= q
.referenced_max
;
121 if (stat("/var/lib/machines.raw", &st
) >= 0) {
122 if (size
== (uint64_t) -1 || (uint64_t) st
.st_size
< size
)
126 return sd_bus_message_append(reply
, "t", size
);
129 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
130 _cleanup_free_
char *p
= NULL
;
131 Manager
*m
= userdata
;
139 r
= sd_bus_message_read(message
, "s", &name
);
143 machine
= hashmap_get(m
->machines
, name
);
145 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
147 p
= machine_bus_path(machine
);
151 return sd_bus_reply_method_return(message
, "o", p
);
154 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
155 _cleanup_free_
char *p
= NULL
;
156 Manager
*m
= userdata
;
163 r
= sd_bus_message_read(message
, "s", &name
);
167 r
= image_find(name
, NULL
);
169 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
173 p
= image_bus_path(name
);
177 return sd_bus_reply_method_return(message
, "o", p
);
180 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
181 _cleanup_free_
char *p
= NULL
;
182 Manager
*m
= userdata
;
183 Machine
*machine
= NULL
;
190 assert_cc(sizeof(pid_t
) == sizeof(uint32_t));
192 r
= sd_bus_message_read(message
, "u", &pid
);
197 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
199 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
203 r
= sd_bus_creds_get_pid(creds
, &pid
);
208 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
212 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
214 p
= machine_bus_path(machine
);
218 return sd_bus_reply_method_return(message
, "o", p
);
221 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
222 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
223 Manager
*m
= userdata
;
231 r
= sd_bus_message_new_method_return(message
, &reply
);
233 return sd_bus_error_set_errno(error
, r
);
235 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
237 return sd_bus_error_set_errno(error
, r
);
239 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
240 _cleanup_free_
char *p
= NULL
;
242 p
= machine_bus_path(machine
);
246 r
= sd_bus_message_append(reply
, "(ssso)",
248 strempty(machine_class_to_string(machine
->class)),
252 return sd_bus_error_set_errno(error
, r
);
255 r
= sd_bus_message_close_container(reply
);
257 return sd_bus_error_set_errno(error
, r
);
259 return sd_bus_send(NULL
, reply
, NULL
);
262 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
263 const char *name
, *service
, *class, *root_directory
;
264 const int32_t *netif
= NULL
;
270 size_t n
, n_netif
= 0;
277 r
= sd_bus_message_read(message
, "s", &name
);
280 if (!machine_name_is_valid(name
))
281 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
283 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
291 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
293 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
300 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
304 n_netif
/= sizeof(int32_t);
306 for (i
= 0; i
< n_netif
; i
++) {
308 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
313 c
= _MACHINE_CLASS_INVALID
;
315 c
= machine_class_from_string(class);
317 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
321 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
323 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
324 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
327 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
329 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
333 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
335 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
340 if (hashmap_get(manager
->machines
, name
))
341 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
343 r
= manager_add_machine(manager
, name
, &m
);
351 if (!isempty(service
)) {
352 m
->service
= strdup(service
);
359 if (!isempty(root_directory
)) {
360 m
->root_directory
= strdup(root_directory
);
361 if (!m
->root_directory
) {
368 assert_cc(sizeof(int32_t) == sizeof(int));
369 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
375 m
->n_netif
= n_netif
;
383 machine_add_to_gc_queue(m
);
387 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
388 Manager
*manager
= userdata
;
395 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
399 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
403 r
= machine_start(m
, message
, error
);
407 m
->create_message
= sd_bus_message_ref(message
);
411 machine_add_to_gc_queue(m
);
415 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
416 return method_create_machine_internal(message
, true, userdata
, error
);
419 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
420 return method_create_machine_internal(message
, false, userdata
, error
);
423 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
424 Manager
*manager
= userdata
;
425 _cleanup_free_
char *p
= NULL
;
432 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
436 r
= cg_pid_get_unit(m
->leader
, &m
->unit
);
438 r
= sd_bus_error_set_errnof(error
, r
, "Failed to determine unit of process "PID_FMT
" : %s", m
->leader
, strerror(-r
));
442 r
= machine_start(m
, NULL
, error
);
446 p
= machine_bus_path(m
);
452 return sd_bus_reply_method_return(message
, "o", p
);
455 machine_add_to_gc_queue(m
);
459 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
460 return method_register_machine_internal(message
, true, userdata
, error
);
463 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
464 return method_register_machine_internal(message
, false, userdata
, error
);
467 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
468 Manager
*m
= userdata
;
476 r
= sd_bus_message_read(message
, "s", &name
);
478 return sd_bus_error_set_errno(error
, r
);
480 machine
= hashmap_get(m
->machines
, name
);
482 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
484 return bus_machine_method_terminate(message
, machine
, error
);
487 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
488 Manager
*m
= userdata
;
496 r
= sd_bus_message_read(message
, "s", &name
);
498 return sd_bus_error_set_errno(error
, r
);
500 machine
= hashmap_get(m
->machines
, name
);
502 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
504 return bus_machine_method_kill(message
, machine
, error
);
507 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
508 Manager
*m
= userdata
;
516 r
= sd_bus_message_read(message
, "s", &name
);
518 return sd_bus_error_set_errno(error
, r
);
520 machine
= hashmap_get(m
->machines
, name
);
522 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
524 return bus_machine_method_get_addresses(message
, machine
, error
);
527 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
528 Manager
*m
= userdata
;
536 r
= sd_bus_message_read(message
, "s", &name
);
538 return sd_bus_error_set_errno(error
, r
);
540 machine
= hashmap_get(m
->machines
, name
);
542 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
544 return bus_machine_method_get_os_release(message
, machine
, error
);
547 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
548 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
549 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
550 Manager
*m
= userdata
;
558 images
= hashmap_new(&string_hash_ops
);
562 r
= image_discover(images
);
566 r
= sd_bus_message_new_method_return(message
, &reply
);
570 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
574 HASHMAP_FOREACH(image
, images
, i
) {
575 _cleanup_free_
char *p
= NULL
;
577 p
= image_bus_path(image
->name
);
581 r
= sd_bus_message_append(reply
, "(ssbttto)",
583 image_type_to_string(image
->type
),
593 r
= sd_bus_message_close_container(reply
);
597 return sd_bus_send(NULL
, reply
, NULL
);
600 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
601 Manager
*m
= userdata
;
609 r
= sd_bus_message_read(message
, "s", &name
);
611 return sd_bus_error_set_errno(error
, r
);
613 machine
= hashmap_get(m
->machines
, name
);
615 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
617 return bus_machine_method_open_pty(message
, machine
, error
);
620 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
621 Manager
*m
= userdata
;
629 r
= sd_bus_message_read(message
, "s", &name
);
633 machine
= hashmap_get(m
->machines
, name
);
635 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
637 return bus_machine_method_open_login(message
, machine
, error
);
640 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
641 Manager
*m
= userdata
;
650 r
= sd_bus_message_read(message
, "s", &name
);
654 machine
= hashmap_get(m
->machines
, name
);
656 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
658 return bus_machine_method_open_shell(message
, machine
, error
);
661 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
662 Manager
*m
= userdata
;
670 r
= sd_bus_message_read(message
, "s", &name
);
674 machine
= hashmap_get(m
->machines
, name
);
676 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
678 return bus_machine_method_bind_mount(message
, machine
, error
);
681 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
682 Manager
*m
= userdata
;
690 r
= sd_bus_message_read(message
, "s", &name
);
694 machine
= hashmap_get(m
->machines
, name
);
696 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
698 return bus_machine_method_copy(message
, machine
, error
);
701 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
702 _cleanup_(image_unrefp
) Image
* i
= NULL
;
708 r
= sd_bus_message_read(message
, "s", &name
);
712 if (!image_name_is_valid(name
))
713 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
715 r
= image_find(name
, &i
);
719 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
721 i
->userdata
= userdata
;
722 return bus_image_method_remove(message
, i
, error
);
725 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
726 _cleanup_(image_unrefp
) Image
* i
= NULL
;
727 const char *old_name
;
732 r
= sd_bus_message_read(message
, "s", &old_name
);
736 if (!image_name_is_valid(old_name
))
737 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
739 r
= image_find(old_name
, &i
);
743 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
745 i
->userdata
= userdata
;
746 return bus_image_method_rename(message
, i
, error
);
749 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
750 _cleanup_(image_unrefp
) Image
*i
= NULL
;
751 const char *old_name
;
756 r
= sd_bus_message_read(message
, "s", &old_name
);
760 if (!image_name_is_valid(old_name
))
761 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
763 r
= image_find(old_name
, &i
);
767 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
769 i
->userdata
= userdata
;
770 return bus_image_method_clone(message
, i
, error
);
773 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
774 _cleanup_(image_unrefp
) Image
*i
= NULL
;
780 r
= sd_bus_message_read(message
, "s", &name
);
784 if (!image_name_is_valid(name
))
785 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
787 r
= image_find(name
, &i
);
791 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
793 i
->userdata
= userdata
;
794 return bus_image_method_mark_read_only(message
, i
, error
);
797 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
798 Manager
*m
= userdata
;
804 r
= sd_bus_message_read(message
, "t", &limit
);
808 r
= bus_verify_polkit_async(
811 "org.freedesktop.machine1.manage-machines",
819 return 1; /* Will call us back */
821 /* Set up the machine directory if necessary */
822 r
= setup_machine_directory(limit
, error
);
826 r
= btrfs_resize_loopback("/var/lib/machines", limit
, false);
828 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
829 if (r
< 0 && r
!= -ENODEV
) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
830 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust loopback limit: %m");
832 r
= btrfs_quota_limit("/var/lib/machines", limit
);
834 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
836 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
838 return sd_bus_reply_method_return(message
, NULL
);
841 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
842 _cleanup_(image_unrefp
) Image
*i
= NULL
;
848 r
= sd_bus_message_read(message
, "s", &name
);
852 if (!image_name_is_valid(name
))
853 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
855 r
= image_find(name
, &i
);
859 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
861 i
->userdata
= userdata
;
862 return bus_image_method_set_limit(message
, i
, error
);
865 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
866 _cleanup_fclose_
FILE *f
= NULL
;
867 Manager
*m
= userdata
;
868 const char *name
, *p
;
873 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
877 if (UID_IS_INVALID(uid
))
878 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
880 machine
= hashmap_get(m
->machines
, name
);
882 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
884 p
= procfs_file_alloca(machine
->leader
, "uid_map");
890 uid_t uid_base
, uid_shift
, uid_range
, converted
;
894 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
895 if (k
< 0 && feof(f
))
898 if (ferror(f
) && errno
!= 0)
904 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
907 converted
= uid
- uid_base
+ uid_shift
;
908 if (UID_IS_INVALID(converted
))
909 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
911 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
914 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
917 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
918 Manager
*m
= userdata
;
924 r
= sd_bus_message_read(message
, "u", &uid
);
927 if (UID_IS_INVALID(uid
))
928 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
930 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
932 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
933 _cleanup_fclose_
FILE *f
= NULL
;
934 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
936 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
939 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
944 _cleanup_free_
char *o
= NULL
;
945 uid_t uid_base
, uid_shift
, uid_range
, converted
;
949 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
950 if (k
< 0 && feof(f
))
953 if (ferror(f
) && errno
!= 0)
959 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
962 converted
= (uid
- uid_shift
+ uid_base
);
963 if (UID_IS_INVALID(converted
))
964 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
966 o
= machine_bus_path(machine
);
970 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
974 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
977 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
978 _cleanup_fclose_
FILE *f
= NULL
;
979 Manager
*m
= groupdata
;
980 const char *name
, *p
;
985 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
989 if (GID_IS_INVALID(gid
))
990 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
992 machine
= hashmap_get(m
->machines
, name
);
994 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
996 p
= procfs_file_alloca(machine
->leader
, "gid_map");
1002 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1006 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1007 if (k
< 0 && feof(f
))
1010 if (ferror(f
) && errno
!= 0)
1016 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
1019 converted
= gid
- gid_base
+ gid_shift
;
1020 if (GID_IS_INVALID(converted
))
1021 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1023 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1026 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1029 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1030 Manager
*m
= groupdata
;
1036 r
= sd_bus_message_read(message
, "u", &gid
);
1039 if (GID_IS_INVALID(gid
))
1040 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1042 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1044 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1045 _cleanup_fclose_
FILE *f
= NULL
;
1046 char p
[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1048 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1051 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1056 _cleanup_free_
char *o
= NULL
;
1057 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1061 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1062 if (k
< 0 && feof(f
))
1065 if (ferror(f
) && errno
!= 0)
1071 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1074 converted
= (gid
- gid_shift
+ gid_base
);
1075 if (GID_IS_INVALID(converted
))
1076 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1078 o
= machine_bus_path(machine
);
1082 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1086 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1089 const sd_bus_vtable manager_vtable
[] = {
1090 SD_BUS_VTABLE_START(0),
1091 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1092 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1093 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1094 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1095 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1096 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1097 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1098 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1099 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1100 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1101 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1102 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1103 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1104 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1105 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1106 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1107 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1108 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1109 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1110 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1111 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1112 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1113 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1114 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1115 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1116 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1117 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1118 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1119 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1120 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1121 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1122 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1123 SD_BUS_SIGNAL("MachineNew", "so", 0),
1124 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1128 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1129 const char *path
, *result
, *unit
;
1130 Manager
*m
= userdata
;
1138 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1140 bus_log_parse_error(r
);
1144 machine
= hashmap_get(m
->machine_units
, unit
);
1148 if (streq_ptr(path
, machine
->scope_job
)) {
1149 machine
->scope_job
= mfree(machine
->scope_job
);
1151 if (machine
->started
) {
1152 if (streq(result
, "done"))
1153 machine_send_create_reply(machine
, NULL
);
1155 _cleanup_bus_error_free_ sd_bus_error e
= SD_BUS_ERROR_NULL
;
1157 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1159 machine_send_create_reply(machine
, &e
);
1163 machine_save(machine
);
1166 machine_add_to_gc_queue(machine
);
1170 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1171 _cleanup_free_
char *unit
= NULL
;
1173 Manager
*m
= userdata
;
1180 path
= sd_bus_message_get_path(message
);
1184 r
= unit_name_from_dbus_path(path
, &unit
);
1185 if (r
== -EINVAL
) /* not for a unit */
1192 machine
= hashmap_get(m
->machine_units
, unit
);
1196 machine_add_to_gc_queue(machine
);
1200 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1201 const char *path
, *unit
;
1202 Manager
*m
= userdata
;
1209 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1211 bus_log_parse_error(r
);
1215 machine
= hashmap_get(m
->machine_units
, unit
);
1219 machine_add_to_gc_queue(machine
);
1223 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1224 Manager
*m
= userdata
;
1232 r
= sd_bus_message_read(message
, "b", &b
);
1234 bus_log_parse_error(r
);
1240 /* systemd finished reloading, let's recheck all our machines */
1241 log_debug("System manager has been reloaded, rechecking machines...");
1243 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1244 machine_add_to_gc_queue(machine
);
1249 int manager_start_scope(
1254 const char *description
,
1255 sd_bus_message
*more_properties
,
1256 sd_bus_error
*error
,
1259 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1266 r
= sd_bus_message_new_method_call(
1269 "org.freedesktop.systemd1",
1270 "/org/freedesktop/systemd1",
1271 "org.freedesktop.systemd1.Manager",
1272 "StartTransientUnit");
1276 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1280 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1284 if (!isempty(slice
)) {
1285 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1290 if (!isempty(description
)) {
1291 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1296 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, pid
);
1300 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
1304 if (more_properties
) {
1305 r
= sd_bus_message_copy(m
, more_properties
, true);
1310 r
= sd_bus_message_close_container(m
);
1314 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1318 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1326 r
= sd_bus_message_read(reply
, "o", &j
);
1340 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1341 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1347 r
= sd_bus_call_method(
1349 "org.freedesktop.systemd1",
1350 "/org/freedesktop/systemd1",
1351 "org.freedesktop.systemd1.Manager",
1355 "ss", unit
, "fail");
1357 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1358 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1363 sd_bus_error_free(error
);
1374 r
= sd_bus_message_read(reply
, "o", &j
);
1388 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1392 return sd_bus_call_method(
1394 "org.freedesktop.systemd1",
1395 "/org/freedesktop/systemd1",
1396 "org.freedesktop.systemd1.Manager",
1400 "ssi", unit
, "all", signo
);
1403 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1404 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1405 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1406 _cleanup_free_
char *path
= NULL
;
1413 path
= unit_dbus_path_from_name(unit
);
1417 r
= sd_bus_get_property(
1419 "org.freedesktop.systemd1",
1421 "org.freedesktop.systemd1.Unit",
1427 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1428 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1431 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1432 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1438 r
= sd_bus_message_read(reply
, "s", &state
);
1442 return !STR_IN_SET(state
, "inactive", "failed");
1445 int manager_job_is_active(Manager
*manager
, const char *path
) {
1446 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1447 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1453 r
= sd_bus_get_property(
1455 "org.freedesktop.systemd1",
1457 "org.freedesktop.systemd1.Job",
1463 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1464 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1467 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1473 /* We don't actually care about the state really. The fact
1474 * that we could read the job state is enough for us */
1479 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1487 mm
= hashmap_get(m
->machine_leaders
, UINT_TO_PTR(pid
));
1489 _cleanup_free_
char *unit
= NULL
;
1491 r
= cg_pid_get_unit(pid
, &unit
);
1493 mm
= hashmap_get(m
->machine_units
, unit
);
1502 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1508 machine
= hashmap_get(m
->machines
, name
);
1510 machine
= machine_new(m
, name
);
1516 *_machine
= machine
;