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 "btrfs-util.h"
29 #include "bus-common-errors.h"
31 #include "cgroup-util.h"
33 #include "formats-util.h"
34 #include "hostname-util.h"
35 #include "image-dbus.h"
36 #include "machine-dbus.h"
37 #include "machine-image.h"
38 #include "machine-pool.h"
40 #include "path-util.h"
41 #include "process-util.h"
43 #include "unit-name.h"
44 #include "user-util.h"
46 static int property_get_pool_path(
49 const char *interface
,
51 sd_bus_message
*reply
,
53 sd_bus_error
*error
) {
58 return sd_bus_message_append(reply
, "s", "/var/lib/machines");
61 static int property_get_pool_usage(
64 const char *interface
,
66 sd_bus_message
*reply
,
68 sd_bus_error
*error
) {
70 _cleanup_close_
int fd
= -1;
71 uint64_t usage
= (uint64_t) -1;
77 /* We try to read the quota info from /var/lib/machines, as
78 * well as the usage of the loopback file
79 * /var/lib/machines.raw, and pick the larger value. */
81 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
85 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
89 if (stat("/var/lib/machines.raw", &st
) >= 0) {
90 if (usage
== (uint64_t) -1 || st
.st_blocks
* 512ULL > usage
)
91 usage
= st
.st_blocks
* 512ULL;
94 return sd_bus_message_append(reply
, "t", usage
);
97 static int property_get_pool_limit(
100 const char *interface
,
101 const char *property
,
102 sd_bus_message
*reply
,
104 sd_bus_error
*error
) {
106 _cleanup_close_
int fd
= -1;
107 uint64_t size
= (uint64_t) -1;
113 /* We try to read the quota limit from /var/lib/machines, as
114 * well as the size of the loopback file
115 * /var/lib/machines.raw, and pick the smaller value. */
117 fd
= open("/var/lib/machines", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
121 if (btrfs_subvol_get_subtree_quota_fd(fd
, 0, &q
) >= 0)
122 size
= q
.referenced_max
;
125 if (stat("/var/lib/machines.raw", &st
) >= 0) {
126 if (size
== (uint64_t) -1 || (uint64_t) st
.st_size
< size
)
130 return sd_bus_message_append(reply
, "t", size
);
133 static int method_get_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
134 _cleanup_free_
char *p
= NULL
;
135 Manager
*m
= userdata
;
143 r
= sd_bus_message_read(message
, "s", &name
);
147 machine
= hashmap_get(m
->machines
, name
);
149 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
151 p
= machine_bus_path(machine
);
155 return sd_bus_reply_method_return(message
, "o", p
);
158 static int method_get_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
159 _cleanup_free_
char *p
= NULL
;
160 Manager
*m
= userdata
;
167 r
= sd_bus_message_read(message
, "s", &name
);
171 r
= image_find(name
, NULL
);
173 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
177 p
= image_bus_path(name
);
181 return sd_bus_reply_method_return(message
, "o", p
);
184 static int method_get_machine_by_pid(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
185 _cleanup_free_
char *p
= NULL
;
186 Manager
*m
= userdata
;
187 Machine
*machine
= NULL
;
194 assert_cc(sizeof(pid_t
) == sizeof(uint32_t));
196 r
= sd_bus_message_read(message
, "u", &pid
);
201 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
203 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
207 r
= sd_bus_creds_get_pid(creds
, &pid
);
212 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
216 return sd_bus_error_setf(error
, BUS_ERROR_NO_MACHINE_FOR_PID
, "PID "PID_FMT
" does not belong to any known machine", pid
);
218 p
= machine_bus_path(machine
);
222 return sd_bus_reply_method_return(message
, "o", p
);
225 static int method_list_machines(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
226 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
227 Manager
*m
= userdata
;
235 r
= sd_bus_message_new_method_return(message
, &reply
);
237 return sd_bus_error_set_errno(error
, r
);
239 r
= sd_bus_message_open_container(reply
, 'a', "(ssso)");
241 return sd_bus_error_set_errno(error
, r
);
243 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
244 _cleanup_free_
char *p
= NULL
;
246 p
= machine_bus_path(machine
);
250 r
= sd_bus_message_append(reply
, "(ssso)",
252 strempty(machine_class_to_string(machine
->class)),
256 return sd_bus_error_set_errno(error
, r
);
259 r
= sd_bus_message_close_container(reply
);
261 return sd_bus_error_set_errno(error
, r
);
263 return sd_bus_send(NULL
, reply
, NULL
);
266 static int method_create_or_register_machine(Manager
*manager
, sd_bus_message
*message
, bool read_network
, Machine
**_m
, sd_bus_error
*error
) {
267 const char *name
, *service
, *class, *root_directory
;
268 const int32_t *netif
= NULL
;
274 size_t n
, n_netif
= 0;
281 r
= sd_bus_message_read(message
, "s", &name
);
284 if (!machine_name_is_valid(name
))
285 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine name");
287 r
= sd_bus_message_read_array(message
, 'y', &v
, &n
);
295 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine ID parameter");
297 r
= sd_bus_message_read(message
, "ssus", &service
, &class, &leader
, &root_directory
);
304 r
= sd_bus_message_read_array(message
, 'i', (const void**) &netif
, &n_netif
);
308 n_netif
/= sizeof(int32_t);
310 for (i
= 0; i
< n_netif
; i
++) {
312 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid network interface index %i", netif
[i
]);
317 c
= _MACHINE_CLASS_INVALID
;
319 c
= machine_class_from_string(class);
321 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid machine class parameter");
325 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid leader PID");
327 if (!isempty(root_directory
) && !path_is_absolute(root_directory
))
328 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Root directory must be empty or an absolute path");
331 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
333 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
337 assert_cc(sizeof(uint32_t) == sizeof(pid_t
));
339 r
= sd_bus_creds_get_pid(creds
, (pid_t
*) &leader
);
344 if (hashmap_get(manager
->machines
, name
))
345 return sd_bus_error_setf(error
, BUS_ERROR_MACHINE_EXISTS
, "Machine '%s' already exists", name
);
347 r
= manager_add_machine(manager
, name
, &m
);
355 if (!isempty(service
)) {
356 m
->service
= strdup(service
);
363 if (!isempty(root_directory
)) {
364 m
->root_directory
= strdup(root_directory
);
365 if (!m
->root_directory
) {
372 assert_cc(sizeof(int32_t) == sizeof(int));
373 m
->netif
= memdup(netif
, sizeof(int32_t) * n_netif
);
379 m
->n_netif
= n_netif
;
387 machine_add_to_gc_queue(m
);
391 static int method_create_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
392 Manager
*manager
= userdata
;
399 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
403 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
407 r
= machine_start(m
, message
, error
);
411 m
->create_message
= sd_bus_message_ref(message
);
415 machine_add_to_gc_queue(m
);
419 static int method_create_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
420 return method_create_machine_internal(message
, true, userdata
, error
);
423 static int method_create_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
424 return method_create_machine_internal(message
, false, userdata
, error
);
427 static int method_register_machine_internal(sd_bus_message
*message
, bool read_network
, void *userdata
, sd_bus_error
*error
) {
428 Manager
*manager
= userdata
;
429 _cleanup_free_
char *p
= NULL
;
436 r
= method_create_or_register_machine(manager
, message
, read_network
, &m
, error
);
440 r
= cg_pid_get_unit(m
->leader
, &m
->unit
);
442 r
= sd_bus_error_set_errnof(error
, r
, "Failed to determine unit of process "PID_FMT
" : %s", m
->leader
, strerror(-r
));
446 r
= machine_start(m
, NULL
, error
);
450 p
= machine_bus_path(m
);
456 return sd_bus_reply_method_return(message
, "o", p
);
459 machine_add_to_gc_queue(m
);
463 static int method_register_machine_with_network(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
464 return method_register_machine_internal(message
, true, userdata
, error
);
467 static int method_register_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
468 return method_register_machine_internal(message
, false, userdata
, error
);
471 static int method_terminate_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
472 Manager
*m
= userdata
;
480 r
= sd_bus_message_read(message
, "s", &name
);
482 return sd_bus_error_set_errno(error
, r
);
484 machine
= hashmap_get(m
->machines
, name
);
486 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
488 return bus_machine_method_terminate(message
, machine
, error
);
491 static int method_kill_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
492 Manager
*m
= userdata
;
500 r
= sd_bus_message_read(message
, "s", &name
);
502 return sd_bus_error_set_errno(error
, r
);
504 machine
= hashmap_get(m
->machines
, name
);
506 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
508 return bus_machine_method_kill(message
, machine
, error
);
511 static int method_get_machine_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
512 Manager
*m
= userdata
;
520 r
= sd_bus_message_read(message
, "s", &name
);
522 return sd_bus_error_set_errno(error
, r
);
524 machine
= hashmap_get(m
->machines
, name
);
526 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
528 return bus_machine_method_get_addresses(message
, machine
, error
);
531 static int method_get_machine_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
532 Manager
*m
= userdata
;
540 r
= sd_bus_message_read(message
, "s", &name
);
542 return sd_bus_error_set_errno(error
, r
);
544 machine
= hashmap_get(m
->machines
, name
);
546 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
548 return bus_machine_method_get_os_release(message
, machine
, error
);
551 static int method_list_images(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
552 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
553 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
554 Manager
*m
= userdata
;
562 images
= hashmap_new(&string_hash_ops
);
566 r
= image_discover(images
);
570 r
= sd_bus_message_new_method_return(message
, &reply
);
574 r
= sd_bus_message_open_container(reply
, 'a', "(ssbttto)");
578 HASHMAP_FOREACH(image
, images
, i
) {
579 _cleanup_free_
char *p
= NULL
;
581 p
= image_bus_path(image
->name
);
585 r
= sd_bus_message_append(reply
, "(ssbttto)",
587 image_type_to_string(image
->type
),
597 r
= sd_bus_message_close_container(reply
);
601 return sd_bus_send(NULL
, reply
, NULL
);
604 static int method_open_machine_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
605 Manager
*m
= userdata
;
613 r
= sd_bus_message_read(message
, "s", &name
);
615 return sd_bus_error_set_errno(error
, r
);
617 machine
= hashmap_get(m
->machines
, name
);
619 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
621 return bus_machine_method_open_pty(message
, machine
, error
);
624 static int method_open_machine_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
625 Manager
*m
= userdata
;
633 r
= sd_bus_message_read(message
, "s", &name
);
637 machine
= hashmap_get(m
->machines
, name
);
639 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
641 return bus_machine_method_open_login(message
, machine
, error
);
644 static int method_open_machine_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
645 Manager
*m
= userdata
;
654 r
= sd_bus_message_read(message
, "s", &name
);
658 machine
= hashmap_get(m
->machines
, name
);
660 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
662 return bus_machine_method_open_shell(message
, machine
, error
);
665 static int method_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
666 Manager
*m
= userdata
;
674 r
= sd_bus_message_read(message
, "s", &name
);
678 machine
= hashmap_get(m
->machines
, name
);
680 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
682 return bus_machine_method_bind_mount(message
, machine
, error
);
685 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
686 Manager
*m
= userdata
;
694 r
= sd_bus_message_read(message
, "s", &name
);
698 machine
= hashmap_get(m
->machines
, name
);
700 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
702 return bus_machine_method_copy(message
, machine
, error
);
705 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
706 _cleanup_(image_unrefp
) Image
* i
= NULL
;
712 r
= sd_bus_message_read(message
, "s", &name
);
716 if (!image_name_is_valid(name
))
717 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
719 r
= image_find(name
, &i
);
723 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
725 i
->userdata
= userdata
;
726 return bus_image_method_remove(message
, i
, error
);
729 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
730 _cleanup_(image_unrefp
) Image
* i
= NULL
;
731 const char *old_name
;
736 r
= sd_bus_message_read(message
, "s", &old_name
);
740 if (!image_name_is_valid(old_name
))
741 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
743 r
= image_find(old_name
, &i
);
747 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
749 i
->userdata
= userdata
;
750 return bus_image_method_rename(message
, i
, error
);
753 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
754 _cleanup_(image_unrefp
) Image
*i
= NULL
;
755 const char *old_name
;
760 r
= sd_bus_message_read(message
, "s", &old_name
);
764 if (!image_name_is_valid(old_name
))
765 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
767 r
= image_find(old_name
, &i
);
771 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
773 i
->userdata
= userdata
;
774 return bus_image_method_clone(message
, i
, error
);
777 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
778 _cleanup_(image_unrefp
) Image
*i
= NULL
;
784 r
= sd_bus_message_read(message
, "s", &name
);
788 if (!image_name_is_valid(name
))
789 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
791 r
= image_find(name
, &i
);
795 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
797 i
->userdata
= userdata
;
798 return bus_image_method_mark_read_only(message
, i
, error
);
801 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
802 Manager
*m
= userdata
;
808 r
= sd_bus_message_read(message
, "t", &limit
);
812 r
= bus_verify_polkit_async(
815 "org.freedesktop.machine1.manage-machines",
824 return 1; /* Will call us back */
826 /* Set up the machine directory if necessary */
827 r
= setup_machine_directory(limit
, error
);
831 r
= btrfs_resize_loopback("/var/lib/machines", limit
, false);
833 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
834 if (r
< 0 && r
!= -ENODEV
) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
835 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust loopback limit: %m");
837 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit
);
839 r
= btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit
);
841 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
843 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
845 return sd_bus_reply_method_return(message
, NULL
);
848 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
849 _cleanup_(image_unrefp
) Image
*i
= NULL
;
855 r
= sd_bus_message_read(message
, "s", &name
);
859 if (!image_name_is_valid(name
))
860 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
862 r
= image_find(name
, &i
);
866 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
868 i
->userdata
= userdata
;
869 return bus_image_method_set_limit(message
, i
, error
);
872 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
873 _cleanup_fclose_
FILE *f
= NULL
;
874 Manager
*m
= userdata
;
875 const char *name
, *p
;
880 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
884 if (!uid_is_valid(uid
))
885 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
887 machine
= hashmap_get(m
->machines
, name
);
889 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
891 if (machine
->class != MACHINE_CONTAINER
)
892 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
894 p
= procfs_file_alloca(machine
->leader
, "uid_map");
900 uid_t uid_base
, uid_shift
, uid_range
, converted
;
904 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
905 if (k
< 0 && feof(f
))
908 if (ferror(f
) && errno
!= 0)
914 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
917 converted
= uid
- uid_base
+ uid_shift
;
918 if (!uid_is_valid(converted
))
919 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
921 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
924 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
927 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
928 Manager
*m
= userdata
;
934 r
= sd_bus_message_read(message
, "u", &uid
);
937 if (!uid_is_valid(uid
))
938 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
940 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
942 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
943 _cleanup_fclose_
FILE *f
= NULL
;
944 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
946 if (machine
->class != MACHINE_CONTAINER
)
949 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
952 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
957 _cleanup_free_
char *o
= NULL
;
958 uid_t uid_base
, uid_shift
, uid_range
, converted
;
962 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
963 if (k
< 0 && feof(f
))
966 if (ferror(f
) && errno
!= 0)
972 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
975 converted
= (uid
- uid_shift
+ uid_base
);
976 if (!uid_is_valid(converted
))
977 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
979 o
= machine_bus_path(machine
);
983 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
987 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
990 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
991 _cleanup_fclose_
FILE *f
= NULL
;
992 Manager
*m
= groupdata
;
993 const char *name
, *p
;
998 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
1002 if (!gid_is_valid(gid
))
1003 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1005 machine
= hashmap_get(m
->machines
, name
);
1007 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
1009 if (machine
->class != MACHINE_CONTAINER
)
1010 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Not supported for non-container machines.");
1012 p
= procfs_file_alloca(machine
->leader
, "gid_map");
1018 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1022 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1023 if (k
< 0 && feof(f
))
1026 if (ferror(f
) && errno
!= 0)
1032 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
1035 converted
= gid
- gid_base
+ gid_shift
;
1036 if (!gid_is_valid(converted
))
1037 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1039 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1042 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1045 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1046 Manager
*m
= groupdata
;
1052 r
= sd_bus_message_read(message
, "u", &gid
);
1055 if (!gid_is_valid(gid
))
1056 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1058 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1060 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1061 _cleanup_fclose_
FILE *f
= NULL
;
1062 char p
[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1064 if (machine
->class != MACHINE_CONTAINER
)
1067 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1070 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1075 _cleanup_free_
char *o
= NULL
;
1076 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1080 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1081 if (k
< 0 && feof(f
))
1084 if (ferror(f
) && errno
!= 0)
1090 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1093 converted
= (gid
- gid_shift
+ gid_base
);
1094 if (!gid_is_valid(converted
))
1095 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1097 o
= machine_bus_path(machine
);
1101 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1105 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1108 const sd_bus_vtable manager_vtable
[] = {
1109 SD_BUS_VTABLE_START(0),
1110 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1111 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1112 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1113 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1114 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1115 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1116 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1117 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1118 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1119 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1120 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1121 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1122 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1123 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1124 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1125 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1126 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1127 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1128 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1129 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1130 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1131 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1132 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1133 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1134 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1135 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1136 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1137 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1138 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1139 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1140 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1141 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1142 SD_BUS_SIGNAL("MachineNew", "so", 0),
1143 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1147 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1148 const char *path
, *result
, *unit
;
1149 Manager
*m
= userdata
;
1157 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1159 bus_log_parse_error(r
);
1163 machine
= hashmap_get(m
->machine_units
, unit
);
1167 if (streq_ptr(path
, machine
->scope_job
)) {
1168 machine
->scope_job
= mfree(machine
->scope_job
);
1170 if (machine
->started
) {
1171 if (streq(result
, "done"))
1172 machine_send_create_reply(machine
, NULL
);
1174 _cleanup_bus_error_free_ sd_bus_error e
= SD_BUS_ERROR_NULL
;
1176 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1178 machine_send_create_reply(machine
, &e
);
1182 machine_save(machine
);
1185 machine_add_to_gc_queue(machine
);
1189 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1190 _cleanup_free_
char *unit
= NULL
;
1192 Manager
*m
= userdata
;
1199 path
= sd_bus_message_get_path(message
);
1203 r
= unit_name_from_dbus_path(path
, &unit
);
1204 if (r
== -EINVAL
) /* not for a unit */
1211 machine
= hashmap_get(m
->machine_units
, unit
);
1215 machine_add_to_gc_queue(machine
);
1219 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1220 const char *path
, *unit
;
1221 Manager
*m
= userdata
;
1228 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1230 bus_log_parse_error(r
);
1234 machine
= hashmap_get(m
->machine_units
, unit
);
1238 machine_add_to_gc_queue(machine
);
1242 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1243 Manager
*m
= userdata
;
1251 r
= sd_bus_message_read(message
, "b", &b
);
1253 bus_log_parse_error(r
);
1259 /* systemd finished reloading, let's recheck all our machines */
1260 log_debug("System manager has been reloaded, rechecking machines...");
1262 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1263 machine_add_to_gc_queue(machine
);
1268 int manager_start_scope(
1273 const char *description
,
1274 sd_bus_message
*more_properties
,
1275 sd_bus_error
*error
,
1278 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1285 r
= sd_bus_message_new_method_call(
1288 "org.freedesktop.systemd1",
1289 "/org/freedesktop/systemd1",
1290 "org.freedesktop.systemd1.Manager",
1291 "StartTransientUnit");
1295 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1299 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1303 if (!isempty(slice
)) {
1304 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1309 if (!isempty(description
)) {
1310 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1315 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, pid
);
1319 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
1323 if (more_properties
) {
1324 r
= sd_bus_message_copy(m
, more_properties
, true);
1329 r
= sd_bus_message_close_container(m
);
1333 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1337 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1345 r
= sd_bus_message_read(reply
, "o", &j
);
1359 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1360 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1366 r
= sd_bus_call_method(
1368 "org.freedesktop.systemd1",
1369 "/org/freedesktop/systemd1",
1370 "org.freedesktop.systemd1.Manager",
1374 "ss", unit
, "fail");
1376 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1377 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1382 sd_bus_error_free(error
);
1393 r
= sd_bus_message_read(reply
, "o", &j
);
1407 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1411 return sd_bus_call_method(
1413 "org.freedesktop.systemd1",
1414 "/org/freedesktop/systemd1",
1415 "org.freedesktop.systemd1.Manager",
1419 "ssi", unit
, "all", signo
);
1422 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1423 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1424 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1425 _cleanup_free_
char *path
= NULL
;
1432 path
= unit_dbus_path_from_name(unit
);
1436 r
= sd_bus_get_property(
1438 "org.freedesktop.systemd1",
1440 "org.freedesktop.systemd1.Unit",
1446 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1447 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1450 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1451 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1457 r
= sd_bus_message_read(reply
, "s", &state
);
1461 return !STR_IN_SET(state
, "inactive", "failed");
1464 int manager_job_is_active(Manager
*manager
, const char *path
) {
1465 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1466 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1472 r
= sd_bus_get_property(
1474 "org.freedesktop.systemd1",
1476 "org.freedesktop.systemd1.Job",
1482 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1483 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1486 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1492 /* We don't actually care about the state really. The fact
1493 * that we could read the job state is enough for us */
1498 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1506 mm
= hashmap_get(m
->machine_leaders
, UINT_TO_PTR(pid
));
1508 _cleanup_free_
char *unit
= NULL
;
1510 r
= cg_pid_get_unit(pid
, &unit
);
1512 mm
= hashmap_get(m
->machine_units
, unit
);
1521 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1527 machine
= hashmap_get(m
->machines
, name
);
1529 machine
= machine_new(m
, _MACHINE_CLASS_INVALID
, name
);
1535 *_machine
= machine
;