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 + 32);
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 { "Class", bus_machine_append_class, "s", offsetof(Machine, class) },
134 { "State", bus_machine_append_state, "s", 0 },
135 { "RootDirectory", bus_property_append_string, "s", offsetof(Machine, root_directory), true },
139 static DBusHandlerResult machine_message_dispatch(
141 DBusConnection *connection,
142 DBusMessage *message) {
145 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
152 if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Machine", "Terminate")) {
156 return bus_send_error_reply(connection, message, NULL, r);
158 reply = dbus_message_new_method_return(message);
162 } else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Machine", "Kill")) {
167 if (!dbus_message_get_args(
170 DBUS_TYPE_STRING, &swho,
171 DBUS_TYPE_INT32, &signo,
173 return bus_send_error_reply(connection, message, &error, -EINVAL);
178 who = kill_who_from_string(swho);
180 return bus_send_error_reply(connection, message, &error, -EINVAL);
183 if (signo <= 0 || signo >= _NSIG)
184 return bus_send_error_reply(connection, message, &error, -EINVAL);
186 r = machine_kill(m, who, signo);
188 return bus_send_error_reply(connection, message, NULL, r);
190 reply = dbus_message_new_method_return(message);
195 const BusBoundProperties bps[] = {
196 { "org.freedesktop.machine1.Machine", bus_machine_machine_properties, m },
200 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
204 if (!bus_maybe_send_reply(connection, message, reply))
208 return DBUS_HANDLER_RESULT_HANDLED;
211 dbus_error_free(&error);
213 return DBUS_HANDLER_RESULT_NEED_MEMORY;
216 static DBusHandlerResult machine_message_handler(
217 DBusConnection *connection,
218 DBusMessage *message,
221 Manager *manager = userdata;
225 r = get_machine_for_path(manager, dbus_message_get_path(message), &m);
229 return DBUS_HANDLER_RESULT_NEED_MEMORY;
235 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown machine");
236 return bus_send_error_reply(connection, message, &e, r);
239 return bus_send_error_reply(connection, message, NULL, r);
242 return machine_message_dispatch(m, connection, message);
245 const DBusObjectPathVTable bus_machine_vtable = {
246 .message_function = machine_message_handler
249 char *machine_bus_path(Machine *m) {
250 _cleanup_free_ char *e = NULL;
254 e = bus_path_escape(m->name);
258 return strappend("/org/freedesktop/machine1/machine/", e);
261 int machine_send_signal(Machine *m, bool new_machine) {
262 _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
263 _cleanup_free_ char *p = NULL;
267 msg = dbus_message_new_signal("/org/freedesktop/machine1",
268 "org.freedesktop.machine1.Manager",
269 new_machine ? "MachineNew" : "MachineRemoved");
274 p = machine_bus_path(m);
278 if (!dbus_message_append_args(
280 DBUS_TYPE_STRING, &m->name,
281 DBUS_TYPE_OBJECT_PATH, &p,
285 if (!dbus_connection_send(m->manager->bus, msg, NULL))
291 int machine_send_changed(Machine *m, const char *properties) {
292 _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
293 _cleanup_free_ char *p = NULL;
300 p = machine_bus_path(m);
304 msg = bus_properties_changed_new(p, "org.freedesktop.machine1.Machine", properties);
308 if (!dbus_connection_send(m->manager->bus, msg, NULL))
314 int machine_send_create_reply(Machine *m, DBusError *error) {
315 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
319 if (!m->create_message)
325 dbus_error_init(&buffer);
327 if (!error || !dbus_error_is_set(error)) {
328 dbus_set_error_const(&buffer, DBUS_ERROR_INVALID_ARGS, "Invalid Arguments");
332 reply = dbus_message_new_error(m->create_message, error->name, error->message);
333 dbus_error_free(&buffer);
338 _cleanup_free_ char *p = NULL;
340 p = machine_bus_path(m);
344 reply = dbus_message_new_method_return(m->create_message);
348 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID))
352 if (!dbus_connection_send(m->manager->bus, reply, NULL))
355 dbus_message_unref(m->create_message);
356 m->create_message = NULL;