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/>.
26 #include "logind-machine.h"
27 #include "dbus-common.h"
29 #define BUS_MACHINE_INTERFACE \
30 " <interface name=\"org.freedesktop.login1.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=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
41 " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
42 " <property name=\"Slice\" type=\"s\" access=\"read\"/>\n" \
43 " <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
44 " <property name=\"Class\" 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.login1.Machine\0"
61 static int bus_machine_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
62 _cleanup_free_ char *t = NULL;
71 r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &t);
75 success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
76 return success ? 0 : -ENOMEM;
79 static int bus_machine_append_id(DBusMessageIter *i, const char *property, void *data) {
89 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
93 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &p, 16);
97 if (!dbus_message_iter_close_container(i, &sub))
103 static int get_machine_for_path(Manager *m, const char *path, Machine **_machine) {
104 _cleanup_free_ char *e = NULL;
111 if (!startswith(path, "/org/freedesktop/login1/machine/"))
114 e = bus_path_unescape(path + 32);
118 machine = hashmap_get(m->machines, e);
126 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_machine_append_class, machine_class, MachineClass);
128 static const BusProperty bus_login_machine_properties[] = {
129 { "Name", bus_property_append_string, "s", offsetof(Machine, name), true },
130 { "Id", bus_machine_append_id, "ay", 0 },
131 { "Timestamp", bus_property_append_usec, "t", offsetof(Machine, timestamp.realtime) },
132 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Machine, timestamp.monotonic) },
133 { "DefaultControlGroup", bus_machine_append_default_cgroup, "s", 0 },
134 { "Service", bus_property_append_string, "s", offsetof(Machine, service), true },
135 { "Slice", bus_property_append_string, "s", offsetof(Machine, slice), true },
136 { "Leader", bus_property_append_pid, "u", offsetof(Session, leader) },
137 { "Class", bus_machine_append_class, "s", offsetof(Machine, class) },
138 { "RootDirectory", bus_property_append_string, "s", offsetof(Machine, root_directory), true },
142 static DBusHandlerResult machine_message_dispatch(
144 DBusConnection *connection,
145 DBusMessage *message) {
148 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
155 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Machine", "Terminate")) {
159 return bus_send_error_reply(connection, message, NULL, r);
161 reply = dbus_message_new_method_return(message);
165 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Machine", "Kill")) {
170 if (!dbus_message_get_args(
173 DBUS_TYPE_STRING, &swho,
174 DBUS_TYPE_INT32, &signo,
176 return bus_send_error_reply(connection, message, &error, -EINVAL);
181 who = kill_who_from_string(swho);
183 return bus_send_error_reply(connection, message, &error, -EINVAL);
186 if (signo <= 0 || signo >= _NSIG)
187 return bus_send_error_reply(connection, message, &error, -EINVAL);
189 r = machine_kill(m, who, signo);
191 return bus_send_error_reply(connection, message, NULL, r);
193 reply = dbus_message_new_method_return(message);
198 const BusBoundProperties bps[] = {
199 { "org.freedesktop.login1.Machine", bus_login_machine_properties, m },
203 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
207 if (!bus_maybe_send_reply(connection, message, reply))
211 return DBUS_HANDLER_RESULT_HANDLED;
214 dbus_error_free(&error);
216 return DBUS_HANDLER_RESULT_NEED_MEMORY;
219 static DBusHandlerResult machine_message_handler(
220 DBusConnection *connection,
221 DBusMessage *message,
224 Manager *manager = userdata;
228 r = get_machine_for_path(manager, dbus_message_get_path(message), &m);
232 return DBUS_HANDLER_RESULT_NEED_MEMORY;
238 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown machine");
239 return bus_send_error_reply(connection, message, &e, r);
242 return bus_send_error_reply(connection, message, NULL, r);
245 return machine_message_dispatch(m, connection, message);
248 const DBusObjectPathVTable bus_machine_vtable = {
249 .message_function = machine_message_handler
252 char *machine_bus_path(Machine *m) {
253 _cleanup_free_ char *e = NULL;
257 e = bus_path_escape(m->name);
261 return strappend("/org/freedesktop/login1/machine/", e);
264 int machine_send_signal(Machine *m, bool new_machine) {
265 _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
266 _cleanup_free_ char *p = NULL;
270 msg = dbus_message_new_signal("/org/freedesktop/login1",
271 "org.freedesktop.login1.Manager",
272 new_machine ? "MachineNew" : "MachineRemoved");
277 p = machine_bus_path(m);
281 if (!dbus_message_append_args(
283 DBUS_TYPE_STRING, &m->name,
284 DBUS_TYPE_OBJECT_PATH, &p,
288 if (!dbus_connection_send(m->manager->bus, msg, NULL))
294 int machine_send_changed(Machine *m, const char *properties) {
295 _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
296 _cleanup_free_ char *p = NULL;
303 p = machine_bus_path(m);
307 msg = bus_properties_changed_new(p, "org.freedesktop.login1.Machine", properties);
311 if (!dbus_connection_send(m->manager->bus, msg, NULL))