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/>.
27 #include "path-util.h"
28 #include "unit-name.h"
30 #include "bus-common-errors.h"
31 #include "cgroup-util.h"
32 #include "btrfs-util.h"
33 #include "machine-image.h"
34 #include "machine-pool.h"
35 #include "image-dbus.h"
37 #include "machine-dbus.h"
39 static int property_get_pool_path(
42 const char *interface,
44 sd_bus_message *reply,
46 sd_bus_error *error) {
51 return sd_bus_message_append(reply, "s", "/var/lib/machines");
54 static int property_get_pool_usage(
57 const char *interface,
59 sd_bus_message *reply,
61 sd_bus_error *error) {
63 _cleanup_close_ int fd = -1;
64 uint64_t usage = (uint64_t) -1;
70 /* We try to read the quota info from /var/lib/machines, as
71 * well as the usage of the loopback file
72 * /var/lib/machines.raw, and pick the larger value. */
74 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
78 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
82 if (stat("/var/lib/machines.raw", &st) >= 0) {
83 if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
84 usage = st.st_blocks * 512ULL;
87 return sd_bus_message_append(reply, "t", usage);
90 static int property_get_pool_limit(
93 const char *interface,
95 sd_bus_message *reply,
97 sd_bus_error *error) {
99 _cleanup_close_ int fd = -1;
100 uint64_t size = (uint64_t) -1;
106 /* We try to read the quota limit from /var/lib/machines, as
107 * well as the size of the loopback file
108 * /var/lib/machines.raw, and pick the smaller value. */
110 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
114 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
115 size = q.referenced_max;
118 if (stat("/var/lib/machines.raw", &st) >= 0) {
119 if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
123 return sd_bus_message_append(reply, "t", size);
126 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
127 _cleanup_free_ char *p = NULL;
128 Manager *m = userdata;
137 r = sd_bus_message_read(message, "s", &name);
141 machine = hashmap_get(m->machines, name);
143 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
145 p = machine_bus_path(machine);
149 return sd_bus_reply_method_return(message, "o", p);
152 static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
153 _cleanup_free_ char *p = NULL;
154 Manager *m = userdata;
162 r = sd_bus_message_read(message, "s", &name);
166 r = image_find(name, NULL);
168 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
172 p = image_bus_path(name);
176 return sd_bus_reply_method_return(message, "o", p);
179 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
180 _cleanup_free_ char *p = NULL;
181 Manager *m = userdata;
182 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 *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
222 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
223 Manager *m = userdata;
232 r = sd_bus_message_new_method_return(message, &reply);
234 return sd_bus_error_set_errno(error, r);
236 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
238 return sd_bus_error_set_errno(error, r);
240 HASHMAP_FOREACH(machine, m->machines, i) {
241 _cleanup_free_ char *p = NULL;
243 p = machine_bus_path(machine);
247 r = sd_bus_message_append(reply, "(ssso)",
249 strempty(machine_class_to_string(machine->class)),
253 return sd_bus_error_set_errno(error, r);
256 r = sd_bus_message_close_container(reply);
258 return sd_bus_error_set_errno(error, r);
260 return sd_bus_send(bus, reply, NULL);
263 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
264 const char *name, *service, *class, *root_directory;
265 const int32_t *netif = NULL;
271 size_t n, n_netif = 0;
278 r = sd_bus_message_read(message, "s", &name);
281 if (!machine_name_is_valid(name))
282 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
284 r = sd_bus_message_read_array(message, 'y', &v, &n);
292 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
294 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
301 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
305 n_netif /= sizeof(int32_t);
307 for (i = 0; i < n_netif; i++) {
309 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
314 c = _MACHINE_CLASS_INVALID;
316 c = machine_class_from_string(class);
318 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
322 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
324 if (!isempty(root_directory) && !path_is_absolute(root_directory))
325 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
328 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
330 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
334 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
336 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
341 if (hashmap_get(manager->machines, name))
342 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
344 r = manager_add_machine(manager, name, &m);
352 if (!isempty(service)) {
353 m->service = strdup(service);
360 if (!isempty(root_directory)) {
361 m->root_directory = strdup(root_directory);
362 if (!m->root_directory) {
369 assert_cc(sizeof(int32_t) == sizeof(int));
370 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
376 m->n_netif = n_netif;
384 machine_add_to_gc_queue(m);
388 static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
389 Manager *manager = userdata;
393 r = method_create_or_register_machine(manager, message, read_network, &m, error);
397 r = sd_bus_message_enter_container(message, 'a', "(sv)");
401 r = machine_start(m, message, error);
405 m->create_message = sd_bus_message_ref(message);
409 machine_add_to_gc_queue(m);
413 static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
414 return method_create_machine_internal(bus, message, true, userdata, error);
417 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
418 return method_create_machine_internal(bus, message, false, userdata, error);
421 static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
422 Manager *manager = userdata;
423 _cleanup_free_ char *p = NULL;
427 r = method_create_or_register_machine(manager, message, read_network, &m, error);
431 r = cg_pid_get_unit(m->leader, &m->unit);
433 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
437 r = machine_start(m, NULL, error);
441 p = machine_bus_path(m);
447 return sd_bus_reply_method_return(message, "o", p);
450 machine_add_to_gc_queue(m);
454 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
455 return method_register_machine_internal(bus, message, true, userdata, error);
458 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
459 return method_register_machine_internal(bus, message, false, userdata, error);
462 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
463 Manager *m = userdata;
472 r = sd_bus_message_read(message, "s", &name);
474 return sd_bus_error_set_errno(error, r);
476 machine = hashmap_get(m->machines, name);
478 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
480 return bus_machine_method_terminate(bus, message, machine, error);
483 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
484 Manager *m = userdata;
493 r = sd_bus_message_read(message, "s", &name);
495 return sd_bus_error_set_errno(error, r);
497 machine = hashmap_get(m->machines, name);
499 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
501 return bus_machine_method_kill(bus, message, machine, error);
504 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
505 Manager *m = userdata;
514 r = sd_bus_message_read(message, "s", &name);
516 return sd_bus_error_set_errno(error, r);
518 machine = hashmap_get(m->machines, name);
520 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
522 return bus_machine_method_get_addresses(bus, message, machine, error);
525 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
526 Manager *m = userdata;
535 r = sd_bus_message_read(message, "s", &name);
537 return sd_bus_error_set_errno(error, r);
539 machine = hashmap_get(m->machines, name);
541 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
543 return bus_machine_method_get_os_release(bus, message, machine, error);
546 static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
547 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
548 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
549 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(bus, reply, NULL);
600 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
601 Manager *m = userdata;
610 r = sd_bus_message_read(message, "s", &name);
612 return sd_bus_error_set_errno(error, r);
614 machine = hashmap_get(m->machines, name);
616 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
618 return bus_machine_method_open_pty(bus, message, machine, error);
621 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
622 Manager *m = userdata;
631 r = sd_bus_message_read(message, "s", &name);
635 machine = hashmap_get(m->machines, name);
637 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
639 return bus_machine_method_open_login(bus, message, machine, error);
642 static int method_bind_mount_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
643 Manager *m = userdata;
652 r = sd_bus_message_read(message, "s", &name);
656 machine = hashmap_get(m->machines, name);
658 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
660 return bus_machine_method_bind_mount(bus, message, machine, error);
663 static int method_copy_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
664 Manager *m = userdata;
673 r = sd_bus_message_read(message, "s", &name);
677 machine = hashmap_get(m->machines, name);
679 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
681 return bus_machine_method_copy(bus, message, machine, error);
684 static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
685 _cleanup_(image_unrefp) Image* i = NULL;
692 r = sd_bus_message_read(message, "s", &name);
696 if (!image_name_is_valid(name))
697 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
699 r = image_find(name, &i);
703 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
705 i->userdata = userdata;
706 return bus_image_method_remove(bus, message, i, error);
709 static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
710 _cleanup_(image_unrefp) Image* i = NULL;
711 const char *old_name;
717 r = sd_bus_message_read(message, "s", &old_name);
721 if (!image_name_is_valid(old_name))
722 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
724 r = image_find(old_name, &i);
728 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
730 i->userdata = userdata;
731 return bus_image_method_rename(bus, message, i, error);
734 static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
735 _cleanup_(image_unrefp) Image *i = NULL;
736 const char *old_name;
740 r = sd_bus_message_read(message, "s", &old_name);
744 if (!image_name_is_valid(old_name))
745 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
747 r = image_find(old_name, &i);
751 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
753 i->userdata = userdata;
754 return bus_image_method_clone(bus, message, i, error);
757 static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
758 _cleanup_(image_unrefp) Image *i = NULL;
763 r = sd_bus_message_read(message, "s", &name);
767 if (!image_name_is_valid(name))
768 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
770 r = image_find(name, &i);
774 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
776 i->userdata = userdata;
777 return bus_image_method_mark_read_only(bus, message, i, error);
780 static int method_set_pool_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
781 Manager *m = userdata;
786 r = sd_bus_message_read(message, "t", &limit);
790 r = bus_verify_polkit_async(
793 "org.freedesktop.machine1.manage-machines",
801 return 1; /* Will call us back */
803 /* Set up the machine directory if necessary */
804 r = setup_machine_directory(limit, error);
808 r = btrfs_resize_loopback("/var/lib/machines", limit, false);
810 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
811 if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
812 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
814 r = btrfs_quota_limit("/var/lib/machines", limit);
816 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
818 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
820 return sd_bus_reply_method_return(message, NULL);
823 static int method_set_image_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
824 _cleanup_(image_unrefp) Image *i = NULL;
829 r = sd_bus_message_read(message, "s", &name);
833 if (!image_name_is_valid(name))
834 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
836 r = image_find(name, &i);
840 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
842 i->userdata = userdata;
843 return bus_image_method_set_limit(bus, message, i, error);
846 const sd_bus_vtable manager_vtable[] = {
847 SD_BUS_VTABLE_START(0),
848 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
849 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
850 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
851 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
852 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
853 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
854 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
855 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
856 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
857 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
858 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
859 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
860 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
861 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
862 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
863 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
864 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
865 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
866 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
867 SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
868 SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
869 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
870 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
871 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
872 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
873 SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
874 SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
875 SD_BUS_SIGNAL("MachineNew", "so", 0),
876 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
880 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
881 const char *path, *result, *unit;
882 Manager *m = userdata;
891 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
893 bus_log_parse_error(r);
897 machine = hashmap_get(m->machine_units, unit);
901 if (streq_ptr(path, machine->scope_job)) {
902 free(machine->scope_job);
903 machine->scope_job = NULL;
905 if (machine->started) {
906 if (streq(result, "done"))
907 machine_send_create_reply(machine, NULL);
909 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
911 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
913 machine_send_create_reply(machine, &e);
916 machine_save(machine);
919 machine_add_to_gc_queue(machine);
923 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
924 _cleanup_free_ char *unit = NULL;
925 Manager *m = userdata;
934 path = sd_bus_message_get_path(message);
938 r = unit_name_from_dbus_path(path, &unit);
939 if (r == -EINVAL) /* not for a unit */
944 machine = hashmap_get(m->machine_units, unit);
946 machine_add_to_gc_queue(machine);
951 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
952 const char *path, *unit;
953 Manager *m = userdata;
961 r = sd_bus_message_read(message, "so", &unit, &path);
963 bus_log_parse_error(r);
967 machine = hashmap_get(m->machine_units, unit);
969 machine_add_to_gc_queue(machine);
974 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
975 Manager *m = userdata;
982 r = sd_bus_message_read(message, "b", &b);
984 bus_log_parse_error(r);
990 /* systemd finished reloading, let's recheck all our machines */
991 log_debug("System manager has been reloaded, rechecking machines...");
993 HASHMAP_FOREACH(machine, m->machines, i)
994 machine_add_to_gc_queue(machine);
999 int manager_start_scope(
1004 const char *description,
1005 sd_bus_message *more_properties,
1006 sd_bus_error *error,
1009 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1016 r = sd_bus_message_new_method_call(
1019 "org.freedesktop.systemd1",
1020 "/org/freedesktop/systemd1",
1021 "org.freedesktop.systemd1.Manager",
1022 "StartTransientUnit");
1026 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
1030 r = sd_bus_message_open_container(m, 'a', "(sv)");
1034 if (!isempty(slice)) {
1035 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1040 if (!isempty(description)) {
1041 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1046 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1050 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1054 if (more_properties) {
1055 r = sd_bus_message_copy(m, more_properties, true);
1060 r = sd_bus_message_close_container(m);
1064 r = sd_bus_message_append(m, "a(sa(sv))", 0);
1068 r = sd_bus_call(manager->bus, m, 0, error, &reply);
1076 r = sd_bus_message_read(reply, "o", &j);
1090 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
1091 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1097 r = sd_bus_call_method(
1099 "org.freedesktop.systemd1",
1100 "/org/freedesktop/systemd1",
1101 "org.freedesktop.systemd1.Manager",
1105 "ss", unit, "fail");
1107 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1108 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
1113 sd_bus_error_free(error);
1124 r = sd_bus_message_read(reply, "o", &j);
1138 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1142 return sd_bus_call_method(
1144 "org.freedesktop.systemd1",
1145 "/org/freedesktop/systemd1",
1146 "org.freedesktop.systemd1.Manager",
1150 "ssi", unit, "all", signo);
1153 int manager_unit_is_active(Manager *manager, const char *unit) {
1154 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1155 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1156 _cleanup_free_ char *path = NULL;
1163 path = unit_dbus_path_from_name(unit);
1167 r = sd_bus_get_property(
1169 "org.freedesktop.systemd1",
1171 "org.freedesktop.systemd1.Unit",
1177 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1178 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1181 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1182 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1188 r = sd_bus_message_read(reply, "s", &state);
1192 return !streq(state, "inactive") && !streq(state, "failed");
1195 int manager_job_is_active(Manager *manager, const char *path) {
1196 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1197 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1203 r = sd_bus_get_property(
1205 "org.freedesktop.systemd1",
1207 "org.freedesktop.systemd1.Job",
1213 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1214 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1217 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1223 /* We don't actually care about the state really. The fact
1224 * that we could read the job state is enough for us */
1229 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1230 _cleanup_free_ char *unit = NULL;
1238 r = cg_pid_get_unit(pid, &unit);
1240 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1242 mm = hashmap_get(m->machine_units, unit);
1251 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1257 machine = hashmap_get(m->machines, name);
1259 machine = machine_new(m, name);
1265 *_machine = machine;