]> git.proxmox.com Git - systemd.git/blob - src/machine/machine-dbus.c
Imported Upstream version 208
[systemd.git] / src / machine / 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 "machined.h"
26 #include "machine.h"
27 #include "dbus-common.h"
28
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" \
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=\"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" \
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.machine1.Machine\0"
60
61 static int bus_machine_append_id(DBusMessageIter *i, const char *property, void *data) {
62 DBusMessageIter sub;
63 Machine *m = data;
64 dbus_bool_t b;
65 void *p;
66
67 assert(i);
68 assert(property);
69 assert(m);
70
71 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
72 return -ENOMEM;
73
74 p = &m->id;
75 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &p, 16);
76 if (!b)
77 return -ENOMEM;
78
79 if (!dbus_message_iter_close_container(i, &sub))
80 return -ENOMEM;
81
82 return 0;
83 }
84
85 static int bus_machine_append_state(DBusMessageIter *i, const char *property, void *data) {
86 Machine *m = data;
87 const char *state;
88
89 assert(i);
90 assert(property);
91 assert(m);
92
93 state = machine_state_to_string(machine_get_state(m));
94
95 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
96 return -ENOMEM;
97
98 return 0;
99 }
100
101 static int get_machine_for_path(Manager *m, const char *path, Machine **_machine) {
102 _cleanup_free_ char *e = NULL;
103 Machine *machine;
104
105 assert(m);
106 assert(path);
107 assert(_machine);
108
109 if (!startswith(path, "/org/freedesktop/machine1/machine/"))
110 return -EINVAL;
111
112 e = bus_path_unescape(path + 34);
113 if (!e)
114 return -ENOMEM;
115
116 machine = hashmap_get(m->machines, e);
117 if (!machine)
118 return -ENOENT;
119
120 *_machine = machine;
121 return 0;
122 }
123
124 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_machine_append_class, machine_class, MachineClass);
125
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 },
137 { NULL, }
138 };
139
140 static DBusHandlerResult machine_message_dispatch(
141 Machine *m,
142 DBusConnection *connection,
143 DBusMessage *message) {
144
145 DBusError error;
146 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
147 int r;
148
149 assert(m);
150 assert(connection);
151 assert(message);
152
153 if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Machine", "Terminate")) {
154
155 r = machine_stop(m);
156 if (r < 0)
157 return bus_send_error_reply(connection, message, NULL, r);
158
159 reply = dbus_message_new_method_return(message);
160 if (!reply)
161 goto oom;
162
163 } else if (dbus_message_is_method_call(message, "org.freedesktop.machine1.Machine", "Kill")) {
164 const char *swho;
165 int32_t signo;
166 KillWho who;
167
168 if (!dbus_message_get_args(
169 message,
170 &error,
171 DBUS_TYPE_STRING, &swho,
172 DBUS_TYPE_INT32, &signo,
173 DBUS_TYPE_INVALID))
174 return bus_send_error_reply(connection, message, &error, -EINVAL);
175
176 if (isempty(swho))
177 who = KILL_ALL;
178 else {
179 who = kill_who_from_string(swho);
180 if (who < 0)
181 return bus_send_error_reply(connection, message, &error, -EINVAL);
182 }
183
184 if (signo <= 0 || signo >= _NSIG)
185 return bus_send_error_reply(connection, message, &error, -EINVAL);
186
187 r = machine_kill(m, who, signo);
188 if (r < 0)
189 return bus_send_error_reply(connection, message, NULL, r);
190
191 reply = dbus_message_new_method_return(message);
192 if (!reply)
193 goto oom;
194
195 } else {
196 const BusBoundProperties bps[] = {
197 { "org.freedesktop.machine1.Machine", bus_machine_machine_properties, m },
198 { NULL, }
199 };
200
201 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
202 }
203
204 if (reply) {
205 if (!bus_maybe_send_reply(connection, message, reply))
206 goto oom;
207 }
208
209 return DBUS_HANDLER_RESULT_HANDLED;
210
211 oom:
212 dbus_error_free(&error);
213
214 return DBUS_HANDLER_RESULT_NEED_MEMORY;
215 }
216
217 static DBusHandlerResult machine_message_handler(
218 DBusConnection *connection,
219 DBusMessage *message,
220 void *userdata) {
221
222 Manager *manager = userdata;
223 Machine *m;
224 int r;
225
226 r = get_machine_for_path(manager, dbus_message_get_path(message), &m);
227 if (r < 0) {
228
229 if (r == -ENOMEM)
230 return DBUS_HANDLER_RESULT_NEED_MEMORY;
231
232 if (r == -ENOENT) {
233 DBusError e;
234
235 dbus_error_init(&e);
236 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown machine");
237 return bus_send_error_reply(connection, message, &e, r);
238 }
239
240 return bus_send_error_reply(connection, message, NULL, r);
241 }
242
243 return machine_message_dispatch(m, connection, message);
244 }
245
246 const DBusObjectPathVTable bus_machine_vtable = {
247 .message_function = machine_message_handler
248 };
249
250 char *machine_bus_path(Machine *m) {
251 _cleanup_free_ char *e = NULL;
252
253 assert(m);
254
255 e = bus_path_escape(m->name);
256 if (!e)
257 return NULL;
258
259 return strappend("/org/freedesktop/machine1/machine/", e);
260 }
261
262 int machine_send_signal(Machine *m, bool new_machine) {
263 _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
264 _cleanup_free_ char *p = NULL;
265
266 assert(m);
267
268 msg = dbus_message_new_signal("/org/freedesktop/machine1",
269 "org.freedesktop.machine1.Manager",
270 new_machine ? "MachineNew" : "MachineRemoved");
271
272 if (!m)
273 return -ENOMEM;
274
275 p = machine_bus_path(m);
276 if (!p)
277 return -ENOMEM;
278
279 if (!dbus_message_append_args(
280 msg,
281 DBUS_TYPE_STRING, &m->name,
282 DBUS_TYPE_OBJECT_PATH, &p,
283 DBUS_TYPE_INVALID))
284 return -ENOMEM;
285
286 if (!dbus_connection_send(m->manager->bus, msg, NULL))
287 return -ENOMEM;
288
289 return 0;
290 }
291
292 int machine_send_changed(Machine *m, const char *properties) {
293 _cleanup_dbus_message_unref_ DBusMessage *msg = NULL;
294 _cleanup_free_ char *p = NULL;
295
296 assert(m);
297
298 if (!m->started)
299 return 0;
300
301 p = machine_bus_path(m);
302 if (!p)
303 return -ENOMEM;
304
305 msg = bus_properties_changed_new(p, "org.freedesktop.machine1.Machine", properties);
306 if (!msg)
307 return -ENOMEM;
308
309 if (!dbus_connection_send(m->manager->bus, msg, NULL))
310 return -ENOMEM;
311
312 return 0;
313 }
314
315 int machine_send_create_reply(Machine *m, DBusError *error) {
316 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
317
318 assert(m);
319
320 if (!m->create_message)
321 return 0;
322
323 if (error) {
324 DBusError buffer;
325
326 dbus_error_init(&buffer);
327
328 if (!error || !dbus_error_is_set(error)) {
329 dbus_set_error_const(&buffer, DBUS_ERROR_INVALID_ARGS, "Invalid Arguments");
330 error = &buffer;
331 }
332
333 reply = dbus_message_new_error(m->create_message, error->name, error->message);
334 dbus_error_free(&buffer);
335
336 if (!reply)
337 return log_oom();
338 } else {
339 _cleanup_free_ char *p = NULL;
340
341 p = machine_bus_path(m);
342 if (!p)
343 return log_oom();
344
345 reply = dbus_message_new_method_return(m->create_message);
346 if (!reply)
347 return log_oom();
348
349 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID))
350 return log_oom();
351 }
352
353 /* Update the machine state file before we notify the client
354 * about the result. */
355 machine_save(m);
356
357 if (!dbus_connection_send(m->manager->bus, reply, NULL))
358 return log_oom();
359
360 dbus_message_unref(m->create_message);
361 m->create_message = NULL;
362
363 return 0;
364 }