chiark / gitweb /
keymap: remove non-existing driver string matches
[elogind.git] / src / login / logind-machine-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <errno.h>
23 #include <string.h>
24
25 #include "logind.h"
26 #include "logind-machine.h"
27 #include "dbus-common.h"
28
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"                        \
35         "  </method>\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" \
46         " </interface>\n"
47
48 #define INTROSPECTION                                                   \
49         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
50         "<node>\n"                                                      \
51         BUS_MACHINE_INTERFACE                                           \
52         BUS_PROPERTIES_INTERFACE                                        \
53         BUS_PEER_INTERFACE                                              \
54         BUS_INTROSPECTABLE_INTERFACE                                    \
55         "</node>\n"
56
57 #define INTERFACES_LIST                              \
58         BUS_GENERIC_INTERFACES_LIST                  \
59         "org.freedesktop.login1.Machine\0"
60
61 static int bus_machine_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
62         _cleanup_free_ char *t = NULL;
63         Machine *m = data;
64         int r;
65         bool success;
66
67         assert(i);
68         assert(property);
69         assert(m);
70
71         r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &t);
72         if (r < 0)
73                 return r;
74
75         success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
76         return success ? 0 : -ENOMEM;
77 }
78
79 static int bus_machine_append_id(DBusMessageIter *i, const char *property, void *data) {
80         DBusMessageIter sub;
81         Machine *m = data;
82         dbus_bool_t b;
83         void *p;
84
85         assert(i);
86         assert(property);
87         assert(m);
88
89         if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
90                 return -ENOMEM;
91
92         p = &m->id;
93         b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &p, 16);
94         if (!b)
95                 return -ENOMEM;
96
97         if (!dbus_message_iter_close_container(i, &sub))
98                 return -ENOMEM;
99
100         return 0;
101 }
102
103 static int get_machine_for_path(Manager *m, const char *path, Machine **_machine) {
104         _cleanup_free_ char *e = NULL;
105         Machine *machine;
106
107         assert(m);
108         assert(path);
109         assert(_machine);
110
111         if (!startswith(path, "/org/freedesktop/login1/machine/"))
112                 return -EINVAL;
113
114         e = bus_path_unescape(path + 32);
115         if (!e)
116                 return -ENOMEM;
117
118         machine = hashmap_get(m->machines, e);
119         if (!machine)
120                 return -ENOENT;
121
122         *_machine = machine;
123         return 0;
124 }
125
126 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_machine_append_class, machine_class, MachineClass);
127
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 },
139         { NULL, }
140 };
141
142 static DBusHandlerResult machine_message_dispatch(
143                 Machine *m,
144                 DBusConnection *connection,
145                 DBusMessage *message) {
146
147         DBusError error;
148         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
149         int r;
150
151         assert(m);
152         assert(connection);
153         assert(message);
154
155         if (dbus_message_is_method_call(message, "org.freedesktop.login1.Machine", "Terminate")) {
156
157                 r = machine_stop(m);
158                 if (r < 0)
159                         return bus_send_error_reply(connection, message, NULL, r);
160
161                 reply = dbus_message_new_method_return(message);
162                 if (!reply)
163                         goto oom;
164
165         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Machine", "Kill")) {
166                 const char *swho;
167                 int32_t signo;
168                 KillWho who;
169
170                 if (!dbus_message_get_args(
171                                     message,
172                                     &error,
173                                     DBUS_TYPE_STRING, &swho,
174                                     DBUS_TYPE_INT32, &signo,
175                                     DBUS_TYPE_INVALID))
176                         return bus_send_error_reply(connection, message, &error, -EINVAL);
177
178                 if (isempty(swho))
179                         who = KILL_ALL;
180                 else {
181                         who = kill_who_from_string(swho);
182                         if (who < 0)
183                                 return bus_send_error_reply(connection, message, &error, -EINVAL);
184                 }
185
186                 if (signo <= 0 || signo >= _NSIG)
187                         return bus_send_error_reply(connection, message, &error, -EINVAL);
188
189                 r = machine_kill(m, who, signo);
190                 if (r < 0)
191                         return bus_send_error_reply(connection, message, NULL, r);
192
193                 reply = dbus_message_new_method_return(message);
194                 if (!reply)
195                         goto oom;
196
197         } else {
198                 const BusBoundProperties bps[] = {
199                         { "org.freedesktop.login1.Machine", bus_login_machine_properties, m },
200                         { NULL, }
201                 };
202
203                 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
204         }
205
206         if (reply) {
207                 if (!bus_maybe_send_reply(connection, message, reply))
208                         goto oom;
209         }
210
211         return DBUS_HANDLER_RESULT_HANDLED;
212
213 oom:
214         dbus_error_free(&error);
215
216         return DBUS_HANDLER_RESULT_NEED_MEMORY;
217 }
218
219 static DBusHandlerResult machine_message_handler(
220                 DBusConnection *connection,
221                 DBusMessage *message,
222                 void *userdata) {
223
224         Manager *manager = userdata;
225         Machine *m;
226         int r;
227
228         r = get_machine_for_path(manager, dbus_message_get_path(message), &m);
229         if (r < 0) {
230
231                 if (r == -ENOMEM)
232                         return DBUS_HANDLER_RESULT_NEED_MEMORY;
233
234                 if (r == -ENOENT) {
235                         DBusError e;
236
237                         dbus_error_init(&e);
238                         dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown machine");
239                         return bus_send_error_reply(connection, message, &e, r);
240                 }
241
242                 return bus_send_error_reply(connection, message, NULL, r);
243         }
244
245         return machine_message_dispatch(m, connection, message);
246 }
247
248 const DBusObjectPathVTable bus_machine_vtable = {
249         .message_function = machine_message_handler
250 };
251
252 char *machine_bus_path(Machine *m) {
253         _cleanup_free_ char *e = NULL;
254
255         assert(m);
256
257         e = bus_path_escape(m->name);
258         if (!e)
259                 return NULL;
260
261         return strappend("/org/freedesktop/login1/machine/", e);
262 }
263
264 int machine_send_signal(Machine *m, bool new_machine) {
265         _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
266         _cleanup_free_ char *p = NULL;
267
268         assert(m);
269
270         msg = dbus_message_new_signal("/org/freedesktop/login1",
271                                     "org.freedesktop.login1.Manager",
272                                     new_machine ? "MachineNew" : "MachineRemoved");
273
274         if (!m)
275                 return -ENOMEM;
276
277         p = machine_bus_path(m);
278         if (!p)
279                 return -ENOMEM;
280
281         if (!dbus_message_append_args(
282                             msg,
283                             DBUS_TYPE_STRING, &m->name,
284                             DBUS_TYPE_OBJECT_PATH, &p,
285                             DBUS_TYPE_INVALID))
286                 return -ENOMEM;
287
288         if (!dbus_connection_send(m->manager->bus, msg, NULL))
289                 return -ENOMEM;
290
291         return 0;
292 }
293
294 int machine_send_changed(Machine *m, const char *properties) {
295         _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
296         _cleanup_free_ char *p = NULL;
297
298         assert(m);
299
300         if (!m->started)
301                 return 0;
302
303         p = machine_bus_path(m);
304         if (!p)
305                 return -ENOMEM;
306
307         msg = bus_properties_changed_new(p, "org.freedesktop.login1.Machine", properties);
308         if (!msg)
309                 return -ENOMEM;
310
311         if (!dbus_connection_send(m->manager->bus, msg, NULL))
312                 return -ENOMEM;
313
314         return 0;
315 }