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 <systemd/sd-id128.h>
28 #include <systemd/sd-messages.h>
31 #include "dbus-common.h"
34 #include "path-util.h"
36 #include "sleep-config.h"
37 #include "fileio-label.h"
40 #include "unit-name.h"
41 #include "bus-errors.h"
43 #include "cgroup-util.h"
45 #define BUS_MANAGER_INTERFACE \
46 " <interface name=\"org.freedesktop.machine1.Manager\">\n" \
47 " <method name=\"GetMachine\">\n" \
48 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
49 " <arg name=\"machine\" type=\"o\" direction=\"out\"/>\n" \
51 " <method name=\"GetMachineByPID\">\n" \
52 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
53 " <arg name=\"machine\" type=\"o\" direction=\"out\"/>\n" \
55 " <method name=\"ListMachines\">\n" \
56 " <arg name=\"machines\" type=\"a(ssso)\" direction=\"out\"/>\n" \
58 " <method name=\"CreateMachine\">\n" \
59 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
60 " <arg name=\"id\" type=\"ay\" direction=\"in\"/>\n" \
61 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
62 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
63 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
64 " <arg name=\"root_directory\" type=\"s\" direction=\"in\"/>\n" \
65 " <arg name=\"scope_properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
66 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
68 " <method name=\"KillMachine\">\n" \
69 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
73 " <method name=\"TerminateMachine\">\n" \
74 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
76 " <signal name=\"MachineNew\">\n" \
77 " <arg name=\"machine\" type=\"s\"/>\n" \
78 " <arg name=\"path\" type=\"o\"/>\n" \
80 " <signal name=\"MachineRemoved\">\n" \
81 " <arg name=\"machine\" type=\"s\"/>\n" \
82 " <arg name=\"path\" type=\"o\"/>\n" \
86 #define INTROSPECTION_BEGIN \
87 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
89 BUS_MANAGER_INTERFACE \
90 BUS_PROPERTIES_INTERFACE \
92 BUS_INTROSPECTABLE_INTERFACE
94 #define INTROSPECTION_END \
97 #define INTERFACES_LIST \
98 BUS_GENERIC_INTERFACES_LIST \
99 "org.freedesktop.machine1.Manager\0"
101 static bool valid_machine_name(const char *p) {
104 if (!filename_is_safe(p))
107 if (!ascii_is_valid(p))
118 static int bus_manager_create_machine(Manager *manager, DBusMessage *message) {
120 const char *name, *service, *class, *root_directory;
121 DBusMessageIter iter, sub;
132 if (!dbus_message_iter_init(message, &iter) ||
133 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
136 dbus_message_iter_get_basic(&iter, &name);
138 if (!valid_machine_name(name) ||
139 !dbus_message_iter_next(&iter) ||
140 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
141 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE)
144 dbus_message_iter_recurse(&iter, &sub);
145 dbus_message_iter_get_fixed_array(&sub, &v, &n);
154 if (!dbus_message_iter_next(&iter) ||
155 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
158 dbus_message_iter_get_basic(&iter, &service);
160 if (!dbus_message_iter_next(&iter) ||
161 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
164 dbus_message_iter_get_basic(&iter, &class);
167 c = _MACHINE_CLASS_INVALID;
169 c = machine_class_from_string(class);
174 if (!dbus_message_iter_next(&iter) ||
175 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
178 dbus_message_iter_get_basic(&iter, &leader);
179 if (!dbus_message_iter_next(&iter) ||
180 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
183 dbus_message_iter_get_basic(&iter, &root_directory);
185 if (!(isempty(root_directory) || path_is_absolute(root_directory)))
188 if (!dbus_message_iter_next(&iter) ||
189 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
190 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)
193 dbus_message_iter_recurse(&iter, &sub);
195 if (hashmap_get(manager->machines, name))
199 leader = bus_get_unix_process_id(manager->bus, dbus_message_get_sender(message), NULL);
204 r = manager_add_machine(manager, name, &m);
212 if (!isempty(service)) {
213 m->service = strdup(service);
220 if (!isempty(root_directory)) {
221 m->root_directory = strdup(root_directory);
222 if (!m->root_directory) {
228 r = machine_start(m, &sub);
232 m->create_message = dbus_message_ref(message);
238 machine_add_to_gc_queue(m);
243 static DBusHandlerResult manager_message_handler(
244 DBusConnection *connection,
245 DBusMessage *message,
248 Manager *m = userdata;
251 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
258 dbus_error_init(&error);
260 if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "GetMachine")) {
266 if (!dbus_message_get_args(
269 DBUS_TYPE_STRING, &name,
271 return bus_send_error_reply(connection, message, &error, -EINVAL);
273 machine = hashmap_get(m->machines, name);
275 return bus_send_error_reply(connection, message, &error, -ENOENT);
277 reply = dbus_message_new_method_return(message);
281 p = machine_bus_path(machine);
285 b = dbus_message_append_args(
287 DBUS_TYPE_OBJECT_PATH, &p,
294 } else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "GetMachineByPID")) {
300 if (!dbus_message_get_args(
303 DBUS_TYPE_UINT32, &pid,
305 return bus_send_error_reply(connection, message, &error, -EINVAL);
307 r = manager_get_machine_by_pid(m, pid, &machine);
309 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
311 reply = dbus_message_new_method_return(message);
315 p = machine_bus_path(machine);
319 b = dbus_message_append_args(
321 DBUS_TYPE_OBJECT_PATH, &p,
328 } else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "ListMachines")) {
331 DBusMessageIter iter, sub;
333 reply = dbus_message_new_method_return(message);
337 dbus_message_iter_init_append(reply, &iter);
339 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssso)", &sub))
342 HASHMAP_FOREACH(machine, m->machines, i) {
343 _cleanup_free_ char *p = NULL;
344 DBusMessageIter sub2;
347 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
350 p = machine_bus_path(machine);
354 class = strempty(machine_class_to_string(machine->class));
356 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &machine->name) ||
357 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &class) ||
358 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &machine->service) ||
359 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
364 if (!dbus_message_iter_close_container(&sub, &sub2))
368 if (!dbus_message_iter_close_container(&iter, &sub))
371 } else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "CreateMachine")) {
373 r = bus_manager_create_machine(m, message);
375 return bus_send_error_reply(connection, message, NULL, r);
377 } else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "KillMachine")) {
384 if (!dbus_message_get_args(
387 DBUS_TYPE_STRING, &name,
388 DBUS_TYPE_STRING, &swho,
389 DBUS_TYPE_INT32, &signo,
391 return bus_send_error_reply(connection, message, &error, -EINVAL);
396 who = kill_who_from_string(swho);
398 return bus_send_error_reply(connection, message, &error, -EINVAL);
401 if (signo <= 0 || signo >= _NSIG)
402 return bus_send_error_reply(connection, message, &error, -EINVAL);
404 machine = hashmap_get(m->machines, name);
406 return bus_send_error_reply(connection, message, &error, -ENOENT);
408 r = machine_kill(machine, who, signo);
410 return bus_send_error_reply(connection, message, NULL, r);
412 reply = dbus_message_new_method_return(message);
416 } else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Manager", "TerminateMachine")) {
420 if (!dbus_message_get_args(
423 DBUS_TYPE_STRING, &name,
425 return bus_send_error_reply(connection, message, &error, -EINVAL);
427 machine = hashmap_get(m->machines, name);
429 return bus_send_error_reply(connection, message, &error, -ENOENT);
431 r = machine_stop(machine);
433 return bus_send_error_reply(connection, message, NULL, r);
435 reply = dbus_message_new_method_return(message);
439 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
440 char *introspection = NULL;
447 reply = dbus_message_new_method_return(message);
451 /* We roll our own introspection code here, instead of
452 * relying on bus_default_message_handler() because we
453 * need to generate our introspection string
456 f = open_memstream(&introspection, &size);
460 fputs(INTROSPECTION_BEGIN, f);
462 HASHMAP_FOREACH(machine, m->machines, i) {
463 p = bus_path_escape(machine->name);
466 fprintf(f, "<node name=\"machine/%s\"/>", p);
471 fputs(INTROSPECTION_END, f);
484 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
491 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, NULL);
494 if (!bus_maybe_send_reply(connection, message, reply))
498 return DBUS_HANDLER_RESULT_HANDLED;
501 dbus_error_free(&error);
503 return DBUS_HANDLER_RESULT_NEED_MEMORY;
506 const DBusObjectPathVTable bus_manager_vtable = {
507 .message_function = manager_message_handler
510 DBusHandlerResult bus_message_filter(
511 DBusConnection *connection,
512 DBusMessage *message,
515 Manager *m = userdata;
522 dbus_error_init(&error);
524 log_debug("Got message: %s %s %s", strna(dbus_message_get_sender(message)), strna(dbus_message_get_interface(message)), strna(dbus_message_get_member(message)));
526 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
527 const char *path, *result, *unit;
531 if (!dbus_message_get_args(message, &error,
532 DBUS_TYPE_UINT32, &id,
533 DBUS_TYPE_OBJECT_PATH, &path,
534 DBUS_TYPE_STRING, &unit,
535 DBUS_TYPE_STRING, &result,
536 DBUS_TYPE_INVALID)) {
537 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
541 mm = hashmap_get(m->machine_units, unit);
543 if (streq_ptr(path, mm->scope_job)) {
545 mm->scope_job = NULL;
548 if (streq(result, "done"))
549 machine_send_create_reply(mm, NULL);
551 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
552 machine_send_create_reply(mm, &error);
558 machine_add_to_gc_queue(mm);
561 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
563 _cleanup_free_ char *unit = NULL;
566 path = dbus_message_get_path(message);
570 unit_name_from_dbus_path(path, &unit);
574 mm = hashmap_get(m->machine_units, unit);
576 machine_add_to_gc_queue(mm);
579 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
580 const char *path, *unit;
583 if (!dbus_message_get_args(message, &error,
584 DBUS_TYPE_STRING, &unit,
585 DBUS_TYPE_OBJECT_PATH, &path,
586 DBUS_TYPE_INVALID)) {
587 log_error("Failed to parse UnitRemoved message: %s", bus_error_message(&error));
591 mm = hashmap_get(m->machine_units, unit);
593 machine_add_to_gc_queue(mm);
595 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "Reloading")) {
598 if (!dbus_message_get_args(message, &error,
599 DBUS_TYPE_BOOLEAN, &b,
600 DBUS_TYPE_INVALID)) {
601 log_error("Failed to parse Reloading message: %s", bus_error_message(&error));
605 /* systemd finished reloading, let's recheck all our machines */
610 log_debug("System manager has been reloaded, rechecking machines...");
612 HASHMAP_FOREACH(mm, m->machines, i)
613 machine_add_to_gc_queue(mm);
618 dbus_error_free(&error);
620 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
623 static int copy_many_fields(DBusMessageIter *dest, DBusMessageIter *src);
625 static int copy_one_field(DBusMessageIter *dest, DBusMessageIter *src) {
628 type = dbus_message_iter_get_arg_type(src);
632 case DBUS_TYPE_STRUCT: {
633 DBusMessageIter dest_sub, src_sub;
635 dbus_message_iter_recurse(src, &src_sub);
637 if (!dbus_message_iter_open_container(dest, DBUS_TYPE_STRUCT, NULL, &dest_sub))
640 r = copy_many_fields(&dest_sub, &src_sub);
644 if (!dbus_message_iter_close_container(dest, &dest_sub))
650 case DBUS_TYPE_ARRAY: {
651 DBusMessageIter dest_sub, src_sub;
653 dbus_message_iter_recurse(src, &src_sub);
655 if (!dbus_message_iter_open_container(dest, DBUS_TYPE_ARRAY, dbus_message_iter_get_signature(&src_sub), &dest_sub))
658 r = copy_many_fields(&dest_sub, &src_sub);
662 if (!dbus_message_iter_close_container(dest, &dest_sub))
668 case DBUS_TYPE_VARIANT: {
669 DBusMessageIter dest_sub, src_sub;
671 dbus_message_iter_recurse(src, &src_sub);
673 if (!dbus_message_iter_open_container(dest, DBUS_TYPE_VARIANT, dbus_message_iter_get_signature(&src_sub), &dest_sub))
676 r = copy_one_field(&dest_sub, &src_sub);
680 if (!dbus_message_iter_close_container(dest, &dest_sub))
686 case DBUS_TYPE_STRING:
687 case DBUS_TYPE_OBJECT_PATH:
689 case DBUS_TYPE_BOOLEAN:
690 case DBUS_TYPE_UINT16:
691 case DBUS_TYPE_INT16:
692 case DBUS_TYPE_UINT32:
693 case DBUS_TYPE_INT32:
694 case DBUS_TYPE_UINT64:
695 case DBUS_TYPE_INT64:
696 case DBUS_TYPE_DOUBLE:
697 case DBUS_TYPE_SIGNATURE: {
700 dbus_message_iter_get_basic(src, &p);
701 dbus_message_iter_append_basic(dest, type, &p);
710 static int copy_many_fields(DBusMessageIter *dest, DBusMessageIter *src) {
716 while (dbus_message_iter_get_arg_type(src) != DBUS_TYPE_INVALID) {
718 r = copy_one_field(dest, src);
722 dbus_message_iter_next(src);
728 int manager_start_scope(
733 const char *description,
734 DBusMessageIter *more_properties,
738 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
739 DBusMessageIter iter, sub, sub2, sub3, sub4;
740 const char *timeout_stop_property = "TimeoutStopUSec";
741 const char *pids_property = "PIDs";
742 uint64_t timeout = 500 * USEC_PER_MSEC;
743 const char *fail = "fail";
754 m = dbus_message_new_method_call(
755 "org.freedesktop.systemd1",
756 "/org/freedesktop/systemd1",
757 "org.freedesktop.systemd1.Manager",
758 "StartTransientUnit");
762 dbus_message_iter_init_append(m, &iter);
764 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
765 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
766 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
769 if (!isempty(slice)) {
770 const char *slice_property = "Slice";
772 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
773 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
774 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
775 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
776 !dbus_message_iter_close_container(&sub2, &sub3) ||
777 !dbus_message_iter_close_container(&sub, &sub2))
781 if (!isempty(description)) {
782 const char *description_property = "Description";
784 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
785 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
786 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
787 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
788 !dbus_message_iter_close_container(&sub2, &sub3) ||
789 !dbus_message_iter_close_container(&sub, &sub2))
793 /* cgroup empty notification is not available in containers
794 * currently. To make this less problematic, let's shorten the
795 * stop timeout for sessions, so that we don't wait
798 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
799 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
800 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
801 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
802 !dbus_message_iter_close_container(&sub2, &sub3) ||
803 !dbus_message_iter_close_container(&sub, &sub2))
807 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
808 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
809 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
810 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
811 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
812 !dbus_message_iter_close_container(&sub3, &sub4) ||
813 !dbus_message_iter_close_container(&sub2, &sub3) ||
814 !dbus_message_iter_close_container(&sub, &sub2))
817 if (more_properties) {
818 r = copy_many_fields(&sub, more_properties);
823 if (!dbus_message_iter_close_container(&iter, &sub))
826 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
834 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
847 int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
848 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
849 const char *fail = "fail";
855 r = bus_method_call_with_reply(
857 "org.freedesktop.systemd1",
858 "/org/freedesktop/systemd1",
859 "org.freedesktop.systemd1.Manager",
863 DBUS_TYPE_STRING, &unit,
864 DBUS_TYPE_STRING, &fail,
867 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
868 dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
873 dbus_error_free(error);
877 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
885 if (!dbus_message_get_args(reply, error,
886 DBUS_TYPE_OBJECT_PATH, &j,
887 DBUS_TYPE_INVALID)) {
888 log_error("Failed to parse reply.");
902 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
903 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
910 w = who == KILL_LEADER ? "process" : "cgroup";
911 assert_cc(sizeof(signo) == sizeof(int32_t));
913 r = bus_method_call_with_reply(
915 "org.freedesktop.systemd1",
916 "/org/freedesktop/systemd1",
917 "org.freedesktop.systemd1.Manager",
921 DBUS_TYPE_STRING, &unit,
922 DBUS_TYPE_STRING, &w,
923 DBUS_TYPE_INT32, &signo,
926 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
933 int manager_unit_is_active(Manager *manager, const char *unit) {
935 const char *interface = "org.freedesktop.systemd1.Unit";
936 const char *property = "ActiveState";
937 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
938 _cleanup_free_ char *path = NULL;
939 DBusMessageIter iter, sub;
947 dbus_error_init(&error);
949 path = unit_dbus_path_from_name(unit);
953 r = bus_method_call_with_reply(
955 "org.freedesktop.systemd1",
957 "org.freedesktop.DBus.Properties",
961 DBUS_TYPE_STRING, &interface,
962 DBUS_TYPE_STRING, &property,
965 if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY) ||
966 dbus_error_has_name(&error, DBUS_ERROR_DISCONNECTED)) {
967 dbus_error_free(&error);
971 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
972 dbus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) {
973 dbus_error_free(&error);
977 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
978 dbus_error_free(&error);
982 if (!dbus_message_iter_init(reply, &iter) ||
983 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
984 log_error("Failed to parse reply.");
988 dbus_message_iter_recurse(&iter, &sub);
989 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
990 log_error("Failed to parse reply.");
994 dbus_message_iter_get_basic(&sub, &state);
996 return !streq(state, "inactive") && !streq(state, "failed");
999 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1005 machine = hashmap_get(m->machines, name);
1008 *_machine = machine;
1013 machine = machine_new(m, name);
1018 *_machine = machine;
1023 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1024 _cleanup_free_ char *unit = NULL;
1032 r = cg_pid_get_unit(pid, &unit);
1036 mm = hashmap_get(m->machine_units, unit);