]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-machine-dbus.c
scope: fix state string table
[thirdparty/systemd.git] / src / login / logind-machine-dbus.c
CommitLineData
9444b1f2
LP
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
61static 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
79static 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
103static 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
126static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_machine_append_class, machine_class, MachineClass);
127
128static 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
142static 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
213oom:
214 dbus_error_free(&error);
215
216 return DBUS_HANDLER_RESULT_NEED_MEMORY;
217}
218
219static 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
248const DBusObjectPathVTable bus_machine_vtable = {
249 .message_function = machine_message_handler
250};
251
252char *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
264int 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
294int 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}