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 "dbus-common.h"
29 #define BUS_MACHINE_INTERFACE \
30 " <interface name=\"org.freedesktop.machine1.Machine\">\n" \
31 " <method name=\"Terminate\"/>\n" \
32 " <method name=\"Kill\">\n" \
33 " <arg name=\"who\" type=\"s\"/>\n" \
34 " <arg name=\"signal\" type=\"s\"/>\n" \
36 " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
37 " <property name=\"Id\" type=\"ay\" access=\"read\"/>\n" \
38 " <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
39 " <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
40 " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
41 " <property name=\"Scope\" type=\"s\" access=\"read\"/>\n" \
42 " <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
43 " <property name=\"Class\" type=\"s\" access=\"read\"/>\n" \
44 " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
45 " <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>\n" \
48 #define INTROSPECTION \
49 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
51 BUS_MACHINE_INTERFACE \
52 BUS_PROPERTIES_INTERFACE \
54 BUS_INTROSPECTABLE_INTERFACE \
57 #define INTERFACES_LIST \
58 BUS_GENERIC_INTERFACES_LIST \
59 "org.freedesktop.machine1.Machine\0"
61 static int bus_machine_append_id(DBusMessageIter *i, const char *property, void *data) {
71 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
75 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &p, 16);
79 if (!dbus_message_iter_close_container(i, &sub))
85 static int bus_machine_append_state(DBusMessageIter *i, const char *property, void *data) {
93 state = machine_state_to_string(machine_get_state(m));
95 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
101 static int get_machine_for_path(Manager *m, const char *path, Machine **_machine) {
102 _cleanup_free_ char *e = NULL;
109 if (!startswith(path, "/org/freedesktop/machine1/machine/"))
112 e = bus_path_unescape(path + 34);
116 machine = hashmap_get(m->machines, e);
124 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_machine_append_class, machine_class, MachineClass);
126 static const BusProperty bus_machine_machine_properties[] = {
127 { "Name", bus_property_append_string, "s", offsetof(Machine, name), true },
128 { "Id", bus_machine_append_id, "ay", 0 },
129 { "Timestamp", bus_property_append_usec, "t", offsetof(Machine, timestamp.realtime) },
130 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Machine, timestamp.monotonic) },
131 { "Service", bus_property_append_string, "s", offsetof(Machine, service), true },
132 { "Scope", bus_property_append_string, "s", offsetof(Machine, scope), true },
133 { "Leader", bus_property_append_pid, "u", offsetof(Machine, leader) },
134 { "Class", bus_machine_append_class, "s", offsetof(Machine, class) },
135 { "State", bus_machine_append_state, "s", 0 },
136 { "RootDirectory", bus_property_append_string, "s", offsetof(Machine, root_directory), true },
140 static DBusHandlerResult machine_message_dispatch(
142 DBusConnection *connection,
143 DBusMessage *message) {
146 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
153 if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Machine", "Terminate")) {
157 return bus_send_error_reply(connection, message, NULL, r);
159 reply = dbus_message_new_method_return(message);
163 } else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Machine", "Kill")) {
168 if (!dbus_message_get_args(
171 DBUS_TYPE_STRING, &swho,
172 DBUS_TYPE_INT32, &signo,
174 return bus_send_error_reply(connection, message, &error, -EINVAL);
179 who = kill_who_from_string(swho);
181 return bus_send_error_reply(connection, message, &error, -EINVAL);
184 if (signo <= 0 || signo >= _NSIG)
185 return bus_send_error_reply(connection, message, &error, -EINVAL);
187 r = machine_kill(m, who, signo);
189 return bus_send_error_reply(connection, message, NULL, r);
191 reply = dbus_message_new_method_return(message);
196 const BusBoundProperties bps[] = {
197 { "org.freedesktop.machine1.Machine", bus_machine_machine_properties, m },
201 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
205 if (!bus_maybe_send_reply(connection, message, reply))
209 return DBUS_HANDLER_RESULT_HANDLED;
212 dbus_error_free(&error);
214 return DBUS_HANDLER_RESULT_NEED_MEMORY;
217 static DBusHandlerResult machine_message_handler(
218 DBusConnection *connection,
219 DBusMessage *message,
222 Manager *manager = userdata;
226 r = get_machine_for_path(manager, dbus_message_get_path(message), &m);
230 return DBUS_HANDLER_RESULT_NEED_MEMORY;
236 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown machine");
237 return bus_send_error_reply(connection, message, &e, r);
240 return bus_send_error_reply(connection, message, NULL, r);
243 return machine_message_dispatch(m, connection, message);
246 const DBusObjectPathVTable bus_machine_vtable = {
247 .message_function = machine_message_handler
250 char *machine_bus_path(Machine *m) {
251 _cleanup_free_ char *e = NULL;
255 e = bus_path_escape(m->name);
259 return strappend("/org/freedesktop/machine1/machine/", e);
262 int machine_send_signal(Machine *m, bool new_machine) {
263 _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
264 _cleanup_free_ char *p = NULL;
268 msg = dbus_message_new_signal("/org/freedesktop/machine1",
269 "org.freedesktop.machine1.Manager",
270 new_machine ? "MachineNew" : "MachineRemoved");
275 p = machine_bus_path(m);
279 if (!dbus_message_append_args(
281 DBUS_TYPE_STRING, &m->name,
282 DBUS_TYPE_OBJECT_PATH, &p,
286 if (!dbus_connection_send(m->manager->bus, msg, NULL))
292 int machine_send_changed(Machine *m, const char *properties) {
293 _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
294 _cleanup_free_ char *p = NULL;
301 p = machine_bus_path(m);
305 msg = bus_properties_changed_new(p, "org.freedesktop.machine1.Machine", properties);
309 if (!dbus_connection_send(m->manager->bus, msg, NULL))
315 int machine_send_create_reply(Machine *m, DBusError *error) {
316 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
320 if (!m->create_message)
326 dbus_error_init(&buffer);
328 if (!error || !dbus_error_is_set(error)) {
329 dbus_set_error_const(&buffer, DBUS_ERROR_INVALID_ARGS, "Invalid Arguments");
333 reply = dbus_message_new_error(m->create_message, error->name, error->message);
334 dbus_error_free(&buffer);
339 _cleanup_free_ char *p = NULL;
341 p = machine_bus_path(m);
345 reply = dbus_message_new_method_return(m->create_message);
349 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID))
353 /* Update the machine state file before we notify the client
354 * about the result. */
357 if (!dbus_connection_send(m->manager->bus, reply, NULL))
360 dbus_message_unref(m->create_message);
361 m->create_message = NULL;