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_bind_mount_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
641 Manager
*m
= userdata
;
649 r
= sd_bus_message_read(message
, "s", &name
);
653 machine
= hashmap_get(m
->machines
, name
);
655 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
657 return bus_machine_method_bind_mount(message
, machine
, error
);
660 static int method_copy_machine(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
661 Manager
*m
= userdata
;
669 r
= sd_bus_message_read(message
, "s", &name
);
673 machine
= hashmap_get(m
->machines
, name
);
675 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
677 return bus_machine_method_copy(message
, machine
, error
);
680 static int method_remove_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
681 _cleanup_(image_unrefp
) Image
* i
= NULL
;
687 r
= sd_bus_message_read(message
, "s", &name
);
691 if (!image_name_is_valid(name
))
692 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
694 r
= image_find(name
, &i
);
698 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
700 i
->userdata
= userdata
;
701 return bus_image_method_remove(message
, i
, error
);
704 static int method_rename_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
705 _cleanup_(image_unrefp
) Image
* i
= NULL
;
706 const char *old_name
;
711 r
= sd_bus_message_read(message
, "s", &old_name
);
715 if (!image_name_is_valid(old_name
))
716 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
718 r
= image_find(old_name
, &i
);
722 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
724 i
->userdata
= userdata
;
725 return bus_image_method_rename(message
, i
, error
);
728 static int method_clone_image(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
729 _cleanup_(image_unrefp
) Image
*i
= NULL
;
730 const char *old_name
;
735 r
= sd_bus_message_read(message
, "s", &old_name
);
739 if (!image_name_is_valid(old_name
))
740 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", old_name
);
742 r
= image_find(old_name
, &i
);
746 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", old_name
);
748 i
->userdata
= userdata
;
749 return bus_image_method_clone(message
, i
, error
);
752 static int method_mark_image_read_only(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
753 _cleanup_(image_unrefp
) Image
*i
= NULL
;
759 r
= sd_bus_message_read(message
, "s", &name
);
763 if (!image_name_is_valid(name
))
764 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
766 r
= image_find(name
, &i
);
770 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
772 i
->userdata
= userdata
;
773 return bus_image_method_mark_read_only(message
, i
, error
);
776 static int method_set_pool_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
777 Manager
*m
= userdata
;
783 r
= sd_bus_message_read(message
, "t", &limit
);
787 r
= bus_verify_polkit_async(
790 "org.freedesktop.machine1.manage-machines",
798 return 1; /* Will call us back */
800 /* Set up the machine directory if necessary */
801 r
= setup_machine_directory(limit
, error
);
805 r
= btrfs_resize_loopback("/var/lib/machines", limit
, false);
807 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
808 if (r
< 0 && r
!= -ENODEV
) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
809 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust loopback limit: %m");
811 r
= btrfs_quota_limit("/var/lib/machines", limit
);
813 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Quota is only supported on btrfs.");
815 return sd_bus_error_set_errnof(error
, r
, "Failed to adjust quota limit: %m");
817 return sd_bus_reply_method_return(message
, NULL
);
820 static int method_set_image_limit(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
821 _cleanup_(image_unrefp
) Image
*i
= NULL
;
827 r
= sd_bus_message_read(message
, "s", &name
);
831 if (!image_name_is_valid(name
))
832 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", name
);
834 r
= image_find(name
, &i
);
838 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_IMAGE
, "No image '%s' known", name
);
840 i
->userdata
= userdata
;
841 return bus_image_method_set_limit(message
, i
, error
);
844 static int method_map_from_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
845 _cleanup_fclose_
FILE *f
= NULL
;
846 Manager
*m
= userdata
;
847 const char *name
, *p
;
852 r
= sd_bus_message_read(message
, "su", &name
, &uid
);
856 if (UID_IS_INVALID(uid
))
857 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
859 machine
= hashmap_get(m
->machines
, name
);
861 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
863 p
= procfs_file_alloca(machine
->leader
, "uid_map");
869 uid_t uid_base
, uid_shift
, uid_range
, converted
;
873 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
874 if (k
< 0 && feof(f
))
877 if (ferror(f
) && errno
!= 0)
883 if (uid
< uid_base
|| uid
>= uid_base
+ uid_range
)
886 converted
= uid
- uid_base
+ uid_shift
;
887 if (UID_IS_INVALID(converted
))
888 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
890 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
893 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "Machine '%s' has no matching user mappings.", name
);
896 static int method_map_to_machine_user(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
897 Manager
*m
= userdata
;
903 r
= sd_bus_message_read(message
, "u", &uid
);
906 if (UID_IS_INVALID(uid
))
907 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
909 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "User " UID_FMT
" belongs to host UID range", uid
);
911 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
912 _cleanup_fclose_
FILE *f
= NULL
;
913 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
915 xsprintf(p
, "/proc/" UID_FMT
"/uid_map", machine
->leader
);
918 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
923 _cleanup_free_
char *o
= NULL
;
924 uid_t uid_base
, uid_shift
, uid_range
, converted
;
928 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
, &uid_base
, &uid_shift
, &uid_range
);
929 if (k
< 0 && feof(f
))
932 if (ferror(f
) && errno
!= 0)
938 if (uid
< uid_shift
|| uid
>= uid_shift
+ uid_range
)
941 converted
= (uid
- uid_shift
+ uid_base
);
942 if (UID_IS_INVALID(converted
))
943 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid user ID " UID_FMT
, uid
);
945 o
= machine_bus_path(machine
);
949 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
953 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_USER_MAPPING
, "No matching user mapping for " UID_FMT
".", uid
);
956 static int method_map_from_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
957 _cleanup_fclose_
FILE *f
= NULL
;
958 Manager
*m
= groupdata
;
959 const char *name
, *p
;
964 r
= sd_bus_message_read(message
, "su", &name
, &gid
);
968 if (GID_IS_INVALID(gid
))
969 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
971 machine
= hashmap_get(m
->machines
, name
);
973 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_MACHINE
, "No machine '%s' known", name
);
975 p
= procfs_file_alloca(machine
->leader
, "gid_map");
981 gid_t gid_base
, gid_shift
, gid_range
, converted
;
985 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
986 if (k
< 0 && feof(f
))
989 if (ferror(f
) && errno
!= 0)
995 if (gid
< gid_base
|| gid
>= gid_base
+ gid_range
)
998 converted
= gid
- gid_base
+ gid_shift
;
999 if (GID_IS_INVALID(converted
))
1000 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1002 return sd_bus_reply_method_return(message
, "u", (uint32_t) converted
);
1005 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Machine '%s' has no matching group mappings.", name
);
1008 static int method_map_to_machine_group(sd_bus_message
*message
, void *groupdata
, sd_bus_error
*error
) {
1009 Manager
*m
= groupdata
;
1015 r
= sd_bus_message_read(message
, "u", &gid
);
1018 if (GID_IS_INVALID(gid
))
1019 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1021 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "Group " GID_FMT
" belongs to host GID range", gid
);
1023 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1024 _cleanup_fclose_
FILE *f
= NULL
;
1025 char p
[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
1027 xsprintf(p
, "/proc/" GID_FMT
"/gid_map", machine
->leader
);
1030 log_warning_errno(errno
, "Failed top open %s, ignoring,", p
);
1035 _cleanup_free_
char *o
= NULL
;
1036 gid_t gid_base
, gid_shift
, gid_range
, converted
;
1040 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
, &gid_base
, &gid_shift
, &gid_range
);
1041 if (k
< 0 && feof(f
))
1044 if (ferror(f
) && errno
!= 0)
1050 if (gid
< gid_shift
|| gid
>= gid_shift
+ gid_range
)
1053 converted
= (gid
- gid_shift
+ gid_base
);
1054 if (GID_IS_INVALID(converted
))
1055 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid group ID " GID_FMT
, gid
);
1057 o
= machine_bus_path(machine
);
1061 return sd_bus_reply_method_return(message
, "sou", machine
->name
, o
, (uint32_t) converted
);
1065 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_GROUP_MAPPING
, "No matching group mapping for " GID_FMT
".", gid
);
1068 const sd_bus_vtable manager_vtable
[] = {
1069 SD_BUS_VTABLE_START(0),
1070 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path
, 0, 0),
1071 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage
, 0, 0),
1072 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit
, 0, 0),
1073 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1074 SD_BUS_METHOD("GetImage", "s", "o", method_get_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1075 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
1076 SD_BUS_METHOD("ListMachines", NULL
, "a(ssso)", method_list_machines
, SD_BUS_VTABLE_UNPRIVILEGED
),
1077 SD_BUS_METHOD("ListImages", NULL
, "a(ssbttto)", method_list_images
, SD_BUS_VTABLE_UNPRIVILEGED
),
1078 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine
, 0),
1079 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network
, 0),
1080 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine
, 0),
1081 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network
, 0),
1082 SD_BUS_METHOD("TerminateMachine", "s", NULL
, method_terminate_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1083 SD_BUS_METHOD("KillMachine", "ssi", NULL
, method_kill_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1084 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1085 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1086 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty
, 0),
1087 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1088 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL
, method_bind_mount_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1089 SD_BUS_METHOD("CopyFromMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1090 SD_BUS_METHOD("CopyToMachine", "sss", NULL
, method_copy_machine
, SD_BUS_VTABLE_UNPRIVILEGED
),
1091 SD_BUS_METHOD("RemoveImage", "s", NULL
, method_remove_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1092 SD_BUS_METHOD("RenameImage", "ss", NULL
, method_rename_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1093 SD_BUS_METHOD("CloneImage", "ssb", NULL
, method_clone_image
, SD_BUS_VTABLE_UNPRIVILEGED
),
1094 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL
, method_mark_image_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
1095 SD_BUS_METHOD("SetPoolLimit", "t", NULL
, method_set_pool_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1096 SD_BUS_METHOD("SetImageLimit", "st", NULL
, method_set_image_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
1097 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1098 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
1099 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1100 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group
, SD_BUS_VTABLE_UNPRIVILEGED
),
1101 SD_BUS_SIGNAL("MachineNew", "so", 0),
1102 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1106 int match_job_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1107 const char *path
, *result
, *unit
;
1108 Manager
*m
= userdata
;
1116 r
= sd_bus_message_read(message
, "uoss", &id
, &path
, &unit
, &result
);
1118 bus_log_parse_error(r
);
1122 machine
= hashmap_get(m
->machine_units
, unit
);
1126 if (streq_ptr(path
, machine
->scope_job
)) {
1127 free(machine
->scope_job
);
1128 machine
->scope_job
= NULL
;
1130 if (machine
->started
) {
1131 if (streq(result
, "done"))
1132 machine_send_create_reply(machine
, NULL
);
1134 _cleanup_bus_error_free_ sd_bus_error e
= SD_BUS_ERROR_NULL
;
1136 sd_bus_error_setf(&e
, BUS_ERROR_JOB_FAILED
, "Start job for unit %s failed with '%s'", unit
, result
);
1138 machine_send_create_reply(machine
, &e
);
1141 machine_save(machine
);
1144 machine_add_to_gc_queue(machine
);
1148 int match_properties_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1149 _cleanup_free_
char *unit
= NULL
;
1150 const char *path
, *interface
;
1151 Manager
*m
= userdata
;
1158 path
= sd_bus_message_get_path(message
);
1162 r
= unit_name_from_dbus_path(path
, &unit
);
1163 if (r
== -EINVAL
) /* not for a unit */
1170 machine
= hashmap_get(m
->machine_units
, unit
);
1174 r
= sd_bus_message_read(message
, "s", &interface
);
1176 bus_log_parse_error(r
);
1180 if (streq(interface
, "org.freedesktop.systemd1.Unit")) {
1186 const struct bus_properties_map map
[] = {
1187 { "ActiveState", "s", NULL
, offsetof(struct properties
, active_state
) },
1188 { "SubState", "s", NULL
, offsetof(struct properties
, sub_state
) },
1192 r
= bus_message_map_properties_changed(message
, map
, &properties
);
1194 bus_log_parse_error(r
);
1195 else if (streq_ptr(properties
.active_state
, "inactive") ||
1196 streq_ptr(properties
.active_state
, "failed") ||
1197 streq_ptr(properties
.sub_state
, "auto-restart"))
1198 machine_release_unit(machine
);
1200 free(properties
.active_state
);
1201 free(properties
.sub_state
);
1204 machine_add_to_gc_queue(machine
);
1208 int match_unit_removed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1209 const char *path
, *unit
;
1210 Manager
*m
= userdata
;
1217 r
= sd_bus_message_read(message
, "so", &unit
, &path
);
1219 bus_log_parse_error(r
);
1223 machine
= hashmap_get(m
->machine_units
, unit
);
1227 machine_release_unit(machine
);
1228 machine_add_to_gc_queue(machine
);
1233 int match_reloading(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1234 Manager
*m
= userdata
;
1242 r
= sd_bus_message_read(message
, "b", &b
);
1244 bus_log_parse_error(r
);
1250 /* systemd finished reloading, let's recheck all our machines */
1251 log_debug("System manager has been reloaded, rechecking machines...");
1253 HASHMAP_FOREACH(machine
, m
->machines
, i
)
1254 machine_add_to_gc_queue(machine
);
1259 int manager_start_scope(
1264 const char *description
,
1265 sd_bus_message
*more_properties
,
1266 sd_bus_error
*error
,
1269 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1276 r
= sd_bus_message_new_method_call(
1279 "org.freedesktop.systemd1",
1280 "/org/freedesktop/systemd1",
1281 "org.freedesktop.systemd1.Manager",
1282 "StartTransientUnit");
1286 r
= sd_bus_message_append(m
, "ss", strempty(scope
), "fail");
1290 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1294 if (!isempty(slice
)) {
1295 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
1300 if (!isempty(description
)) {
1301 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", description
);
1306 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, pid
);
1310 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
1314 if (more_properties
) {
1315 r
= sd_bus_message_copy(m
, more_properties
, true);
1320 r
= sd_bus_message_close_container(m
);
1324 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1328 r
= sd_bus_call(manager
->bus
, m
, 0, error
, &reply
);
1336 r
= sd_bus_message_read(reply
, "o", &j
);
1350 int manager_stop_unit(Manager
*manager
, const char *unit
, sd_bus_error
*error
, char **job
) {
1351 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1357 r
= sd_bus_call_method(
1359 "org.freedesktop.systemd1",
1360 "/org/freedesktop/systemd1",
1361 "org.freedesktop.systemd1.Manager",
1365 "ss", unit
, "fail");
1367 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1368 sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
)) {
1373 sd_bus_error_free(error
);
1384 r
= sd_bus_message_read(reply
, "o", &j
);
1398 int manager_kill_unit(Manager
*manager
, const char *unit
, int signo
, sd_bus_error
*error
) {
1402 return sd_bus_call_method(
1404 "org.freedesktop.systemd1",
1405 "/org/freedesktop/systemd1",
1406 "org.freedesktop.systemd1.Manager",
1410 "ssi", unit
, "all", signo
);
1413 int manager_unit_is_active(Manager
*manager
, const char *unit
) {
1414 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1415 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1416 _cleanup_free_
char *path
= NULL
;
1423 path
= unit_dbus_path_from_name(unit
);
1427 r
= sd_bus_get_property(
1429 "org.freedesktop.systemd1",
1431 "org.freedesktop.systemd1.Unit",
1437 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1438 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1441 if (sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
) ||
1442 sd_bus_error_has_name(&error
, BUS_ERROR_LOAD_FAILED
))
1448 r
= sd_bus_message_read(reply
, "s", &state
);
1452 return !STR_IN_SET(state
, "inactive", "failed");
1455 int manager_job_is_active(Manager
*manager
, const char *path
) {
1456 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1457 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1463 r
= sd_bus_get_property(
1465 "org.freedesktop.systemd1",
1467 "org.freedesktop.systemd1.Job",
1473 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_NO_REPLY
) ||
1474 sd_bus_error_has_name(&error
, SD_BUS_ERROR_DISCONNECTED
))
1477 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_OBJECT
))
1483 /* We don't actually care about the state really. The fact
1484 * that we could read the job state is enough for us */
1489 int manager_get_machine_by_pid(Manager
*m
, pid_t pid
, Machine
**machine
) {
1490 _cleanup_free_
char *unit
= NULL
;
1498 r
= cg_pid_get_unit(pid
, &unit
);
1500 mm
= hashmap_get(m
->machine_leaders
, UINT_TO_PTR(pid
));
1502 mm
= hashmap_get(m
->machine_units
, unit
);
1511 int manager_add_machine(Manager
*m
, const char *name
, Machine
**_machine
) {
1517 machine
= hashmap_get(m
->machines
, name
);
1519 machine
= machine_new(m
, name
);
1525 *_machine
= machine
;