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 "sd-messages.h"
31 #include "path-util.h"
33 #include "fileio-label.h"
36 #include "unit-name.h"
38 #include "bus-common-errors.h"
39 #include "time-util.h"
40 #include "cgroup-util.h"
41 #include "machine-image.h"
42 #include "image-dbus.h"
44 #include "machine-dbus.h"
46 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
47 _cleanup_free_ char *p = NULL;
48 Manager *m = userdata;
57 r = sd_bus_message_read(message, "s", &name);
61 machine = hashmap_get(m->machines, name);
63 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
65 p = machine_bus_path(machine);
69 return sd_bus_reply_method_return(message, "o", p);
72 static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
73 _cleanup_free_ char *p = NULL;
74 Manager *m = userdata;
82 r = sd_bus_message_read(message, "s", &name);
86 r = image_find(name, NULL);
88 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
92 p = image_bus_path(name);
96 return sd_bus_reply_method_return(message, "o", p);
99 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
100 _cleanup_free_ char *p = NULL;
101 Manager *m = userdata;
102 Machine *machine = NULL;
110 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
112 r = sd_bus_message_read(message, "u", &pid);
117 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
119 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
123 r = sd_bus_creds_get_pid(creds, &pid);
128 r = manager_get_machine_by_pid(m, pid, &machine);
132 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
134 p = machine_bus_path(machine);
138 return sd_bus_reply_method_return(message, "o", p);
141 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
142 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
143 Manager *m = userdata;
152 r = sd_bus_message_new_method_return(message, &reply);
154 return sd_bus_error_set_errno(error, r);
156 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
158 return sd_bus_error_set_errno(error, r);
160 HASHMAP_FOREACH(machine, m->machines, i) {
161 _cleanup_free_ char *p = NULL;
163 p = machine_bus_path(machine);
167 r = sd_bus_message_append(reply, "(ssso)",
169 strempty(machine_class_to_string(machine->class)),
173 return sd_bus_error_set_errno(error, r);
176 r = sd_bus_message_close_container(reply);
178 return sd_bus_error_set_errno(error, r);
180 return sd_bus_send(bus, reply, NULL);
183 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
184 const char *name, *service, *class, *root_directory;
185 const int32_t *netif = NULL;
191 size_t n, n_netif = 0;
198 r = sd_bus_message_read(message, "s", &name);
201 if (!machine_name_is_valid(name))
202 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
204 r = sd_bus_message_read_array(message, 'y', &v, &n);
212 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
214 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
221 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
225 n_netif /= sizeof(int32_t);
227 for (i = 0; i < n_netif; i++) {
229 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
234 c = _MACHINE_CLASS_INVALID;
236 c = machine_class_from_string(class);
238 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
242 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
244 if (!isempty(root_directory) && !path_is_absolute(root_directory))
245 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
248 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
250 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
254 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
256 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
261 if (hashmap_get(manager->machines, name))
262 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
264 r = manager_add_machine(manager, name, &m);
272 if (!isempty(service)) {
273 m->service = strdup(service);
280 if (!isempty(root_directory)) {
281 m->root_directory = strdup(root_directory);
282 if (!m->root_directory) {
289 assert_cc(sizeof(int32_t) == sizeof(int));
290 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
296 m->n_netif = n_netif;
304 machine_add_to_gc_queue(m);
308 static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
309 Manager *manager = userdata;
313 r = method_create_or_register_machine(manager, message, read_network, &m, error);
317 r = sd_bus_message_enter_container(message, 'a', "(sv)");
321 r = machine_start(m, message, error);
325 m->create_message = sd_bus_message_ref(message);
329 machine_add_to_gc_queue(m);
333 static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
334 return method_create_machine_internal(bus, message, true, userdata, error);
337 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
338 return method_create_machine_internal(bus, message, false, userdata, error);
341 static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
342 Manager *manager = userdata;
343 _cleanup_free_ char *p = NULL;
347 r = method_create_or_register_machine(manager, message, read_network, &m, error);
351 r = cg_pid_get_unit(m->leader, &m->unit);
353 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
357 m->registered = true;
359 r = machine_start(m, NULL, error);
363 p = machine_bus_path(m);
369 return sd_bus_reply_method_return(message, "o", p);
372 machine_add_to_gc_queue(m);
376 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
377 return method_register_machine_internal(bus, message, true, userdata, error);
380 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
381 return method_register_machine_internal(bus, message, false, userdata, error);
384 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
385 Manager *m = userdata;
394 r = sd_bus_message_read(message, "s", &name);
396 return sd_bus_error_set_errno(error, r);
398 machine = hashmap_get(m->machines, name);
400 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
402 return bus_machine_method_terminate(bus, message, machine, error);
405 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
406 Manager *m = userdata;
415 r = sd_bus_message_read(message, "s", &name);
417 return sd_bus_error_set_errno(error, r);
419 machine = hashmap_get(m->machines, name);
421 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
423 return bus_machine_method_kill(bus, message, machine, error);
426 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
427 Manager *m = userdata;
436 r = sd_bus_message_read(message, "s", &name);
438 return sd_bus_error_set_errno(error, r);
440 machine = hashmap_get(m->machines, name);
442 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
444 return bus_machine_method_get_addresses(bus, message, machine, error);
447 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
448 Manager *m = userdata;
457 r = sd_bus_message_read(message, "s", &name);
459 return sd_bus_error_set_errno(error, r);
461 machine = hashmap_get(m->machines, name);
463 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
465 return bus_machine_method_get_os_release(bus, message, machine, error);
468 static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
469 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
470 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
471 Manager *m = userdata;
480 images = hashmap_new(&string_hash_ops);
484 r = image_discover(images);
488 r = sd_bus_message_new_method_return(message, &reply);
492 r = sd_bus_message_open_container(reply, 'a', "(ssbtto)");
496 HASHMAP_FOREACH(image, images, i) {
497 _cleanup_free_ char *p = NULL;
499 p = image_bus_path(image->name);
503 r = sd_bus_message_append(reply, "(ssbtto)",
505 image_type_to_string(image->type),
514 r = sd_bus_message_close_container(reply);
518 return sd_bus_send(bus, reply, NULL);
521 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
522 Manager *m = userdata;
531 r = sd_bus_message_read(message, "s", &name);
533 return sd_bus_error_set_errno(error, r);
535 machine = hashmap_get(m->machines, name);
537 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
539 return bus_machine_method_open_pty(bus, message, machine, error);
542 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
543 Manager *m = userdata;
552 r = sd_bus_message_read(message, "s", &name);
556 machine = hashmap_get(m->machines, name);
558 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
560 return bus_machine_method_open_login(bus, message, machine, error);
563 static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
564 _cleanup_(image_unrefp) Image* i = NULL;
571 r = sd_bus_message_read(message, "s", &name);
575 if (!image_name_is_valid(name))
576 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
578 r = image_find(name, &i);
582 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
588 return sd_bus_reply_method_return(message, NULL);
591 static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
592 _cleanup_(image_unrefp) Image* i = NULL;
593 const char *old_name, *new_name;
599 r = sd_bus_message_read(message, "ss", &old_name, &new_name);
603 if (!image_name_is_valid(old_name))
604 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
605 if (!image_name_is_valid(new_name))
606 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
608 r = image_find(old_name, &i);
612 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
614 r = image_rename(i, new_name);
618 return sd_bus_reply_method_return(message, NULL);
621 static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
622 _cleanup_(image_unrefp) Image *i = NULL;
623 const char *old_name, *new_name;
627 r = sd_bus_message_read(message, "ssb", &old_name, &new_name, &read_only);
631 if (!image_name_is_valid(old_name))
632 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
633 if (!image_name_is_valid(new_name))
634 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
636 r = image_find(old_name, &i);
640 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
642 r = image_clone(i, new_name, read_only);
646 return sd_bus_reply_method_return(message, NULL);
649 static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
650 _cleanup_(image_unrefp) Image *i = NULL;
655 r = sd_bus_message_read(message, "sb", &name, &read_only);
659 if (!image_name_is_valid(name))
660 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
662 r = image_find(name, &i);
666 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
668 r = image_read_only(i, read_only);
672 return sd_bus_reply_method_return(message, NULL);
675 const sd_bus_vtable manager_vtable[] = {
676 SD_BUS_VTABLE_START(0),
677 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
678 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
679 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
680 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
681 SD_BUS_METHOD("ListImages", NULL, "a(ssbtto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
682 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
683 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
684 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
685 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
686 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
687 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
688 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
689 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
690 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
691 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
692 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
693 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
694 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
695 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
696 SD_BUS_SIGNAL("MachineNew", "so", 0),
697 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
701 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
702 const char *path, *result, *unit;
703 Manager *m = userdata;
712 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
714 bus_log_parse_error(r);
718 machine = hashmap_get(m->machine_units, unit);
722 if (streq_ptr(path, machine->scope_job)) {
723 free(machine->scope_job);
724 machine->scope_job = NULL;
726 if (machine->started) {
727 if (streq(result, "done"))
728 machine_send_create_reply(machine, NULL);
730 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
732 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
734 machine_send_create_reply(machine, &e);
737 machine_save(machine);
740 machine_add_to_gc_queue(machine);
744 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
745 _cleanup_free_ char *unit = NULL;
746 Manager *m = userdata;
755 path = sd_bus_message_get_path(message);
759 r = unit_name_from_dbus_path(path, &unit);
763 machine = hashmap_get(m->machine_units, unit);
765 machine_add_to_gc_queue(machine);
770 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
771 const char *path, *unit;
772 Manager *m = userdata;
780 r = sd_bus_message_read(message, "so", &unit, &path);
782 bus_log_parse_error(r);
786 machine = hashmap_get(m->machine_units, unit);
788 machine_add_to_gc_queue(machine);
793 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
794 Manager *m = userdata;
801 r = sd_bus_message_read(message, "b", &b);
803 bus_log_parse_error(r);
809 /* systemd finished reloading, let's recheck all our machines */
810 log_debug("System manager has been reloaded, rechecking machines...");
812 HASHMAP_FOREACH(machine, m->machines, i)
813 machine_add_to_gc_queue(machine);
818 int manager_start_scope(
823 const char *description,
824 sd_bus_message *more_properties,
828 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
835 r = sd_bus_message_new_method_call(
838 "org.freedesktop.systemd1",
839 "/org/freedesktop/systemd1",
840 "org.freedesktop.systemd1.Manager",
841 "StartTransientUnit");
845 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
849 r = sd_bus_message_open_container(m, 'a', "(sv)");
853 if (!isempty(slice)) {
854 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
859 if (!isempty(description)) {
860 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
865 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
869 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
873 if (more_properties) {
874 r = sd_bus_message_copy(m, more_properties, true);
879 r = sd_bus_message_close_container(m);
883 r = sd_bus_message_append(m, "a(sa(sv))", 0);
887 r = sd_bus_call(manager->bus, m, 0, error, &reply);
895 r = sd_bus_message_read(reply, "o", &j);
909 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
910 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
916 r = sd_bus_call_method(
918 "org.freedesktop.systemd1",
919 "/org/freedesktop/systemd1",
920 "org.freedesktop.systemd1.Manager",
926 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
927 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
932 sd_bus_error_free(error);
943 r = sd_bus_message_read(reply, "o", &j);
957 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
961 return sd_bus_call_method(
963 "org.freedesktop.systemd1",
964 "/org/freedesktop/systemd1",
965 "org.freedesktop.systemd1.Manager",
969 "ssi", unit, "all", signo);
972 int manager_unit_is_active(Manager *manager, const char *unit) {
973 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
974 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
975 _cleanup_free_ char *path = NULL;
982 path = unit_dbus_path_from_name(unit);
986 r = sd_bus_get_property(
988 "org.freedesktop.systemd1",
990 "org.freedesktop.systemd1.Unit",
996 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
997 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1000 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1001 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1007 r = sd_bus_message_read(reply, "s", &state);
1011 return !streq(state, "inactive") && !streq(state, "failed");
1014 int manager_job_is_active(Manager *manager, const char *path) {
1015 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1016 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1022 r = sd_bus_get_property(
1024 "org.freedesktop.systemd1",
1026 "org.freedesktop.systemd1.Job",
1032 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1033 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1036 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1042 /* We don't actually care about the state really. The fact
1043 * that we could read the job state is enough for us */
1048 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1049 _cleanup_free_ char *unit = NULL;
1057 r = cg_pid_get_unit(pid, &unit);
1059 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1061 mm = hashmap_get(m->machine_units, unit);
1070 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1076 machine = hashmap_get(m->machines, name);
1078 machine = machine_new(m, name);
1084 *_machine = machine;