]> git.ipfire.org Git - people/ms/systemd.git/blame - dbus-unit.c
dbus: implement start/stop/restart/reload/cancel D-Bus calls
[people/ms/systemd.git] / dbus-unit.c
CommitLineData
ea430986
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3#include <errno.h>
4
5#include "dbus.h"
6#include "log.h"
7
8static const char introspection[] =
9 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
10 "<node>"
ea430986 11 " <interface name=\"org.freedesktop.systemd1.Unit\">"
b548631a
LP
12 " <method name=\"Start\">"
13 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>"
14 " <arg name=\"job\" type=\"o\" direction=\"out\"/>"
15 " </method>"
16 " <method name=\"Stop\">"
17 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>"
18 " <arg name=\"job\" type=\"o\" direction=\"out\"/>"
19 " </method>"
20 " <method name=\"Restart\">"
21 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>"
22 " <arg name=\"job\" type=\"o\" direction=\"out\"/>"
23 " </method>"
24 " <method name=\"Reload\">"
25 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>"
26 " <arg name=\"job\" type=\"o\" direction=\"out\"/>"
27 " </method>"
ea430986
LP
28 " <property name=\"Id\" type=\"s\" access=\"read\"/>"
29 " <property name=\"Description\" type=\"s\" access=\"read\"/>"
30 " <property name=\"LoadState\" type=\"s\" access=\"read\"/>"
31 " <property name=\"ActiveState\" type=\"s\" access=\"read\"/>"
38131695
LP
32 " <property name=\"LoadPath\" type=\"s\" access=\"read\"/>"
33 " <property name=\"ActiveEnterTimestamp\" type=\"t\" access=\"read\"/>"
34 " <property name=\"ActiveExitTimestamp\" type=\"t\" access=\"read\"/>"
35 " <property name=\"CanReload\" type=\"b\" access=\"read\"/>"
36 " <property name=\"CanStart\" type=\"b\" access=\"read\"/>"
37 " <property name=\"Job\" type=\"(uo)\" access=\"read\"/>"
ea430986
LP
38 " </interface>"
39 BUS_PROPERTIES_INTERFACE
40 BUS_INTROSPECTABLE_INTERFACE
41 "</node>";
42
43static int bus_unit_append_id(Manager *m, DBusMessageIter *i, const char *property, void *data) {
44 Unit *u = data;
45 const char *id;
46
47 assert(m);
48 assert(i);
49 assert(property);
50 assert(u);
51
52 id = unit_id(u);
53
c401a1e0 54 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
ea430986
LP
55 return -ENOMEM;
56
57 return 0;
58}
59
60static int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data) {
61 Unit *u = data;
62 const char *d;
63
64 assert(m);
65 assert(i);
66 assert(property);
67 assert(u);
68
69 d = unit_description(u);
70
71 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
72 return -ENOMEM;
73
74 return 0;
75}
76
77static int bus_unit_append_load_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
78 Unit *u = data;
79 const char *state;
80
81 assert(m);
82 assert(i);
83 assert(property);
84 assert(u);
85
86 state = unit_load_state_to_string(u->meta.load_state);
87
88 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
89 return -ENOMEM;
90
91 return 0;
92}
93
94static int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
95 Unit *u = data;
96 const char *state;
97
98 assert(m);
99 assert(i);
100 assert(property);
101 assert(u);
102
103 state = unit_active_state_to_string(unit_active_state(u));
104
105 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
106 return -ENOMEM;
107
108 return 0;
109}
110
38131695
LP
111static int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data) {
112 Unit *u = data;
113 dbus_bool_t b;
114
115 assert(m);
116 assert(i);
117 assert(property);
118 assert(u);
119
120 b = unit_can_reload(u);
121
122 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
123 return -ENOMEM;
124
125 return 0;
126}
127
128static int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data) {
129 Unit *u = data;
130 dbus_bool_t b;
131
132 assert(m);
133 assert(i);
134 assert(property);
135 assert(u);
136
137 b = unit_can_start(u);
138
139 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
140 return -ENOMEM;
141
142 return 0;
143}
144
145static int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data) {
146 Unit *u = data;
147 DBusMessageIter sub;
148 char *p;
149
150 assert(m);
151 assert(i);
152 assert(property);
153 assert(u);
154
155 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
156 return -ENOMEM;
157
158 if (u->meta.job) {
159
160 if (!(p = job_dbus_path(u->meta.job)))
161 return -ENOMEM;
162
163 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->meta.job->id) ||
86ad3bc1 164 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
38131695
LP
165 free(p);
166 return -ENOMEM;
167 }
168 } else {
169 uint32_t id = 0;
170
171 /* No job, so let's fill in some placeholder
172 * data. Since we need to fill in a valid path we
173 * simple point to ourselves. */
174
175 if (!(p = unit_dbus_path(u)))
176 return -ENOMEM;
177
178 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) ||
86ad3bc1 179 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
38131695
LP
180 free(p);
181 return -ENOMEM;
182 }
183 }
184
185 free(p);
186
187 if (!dbus_message_iter_close_container(i, &sub))
188 return -ENOMEM;
189
190 return 0;
191}
192
ea430986
LP
193static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusMessage *message) {
194
195 const BusProperty properties[] = {
38131695
LP
196 { "org.freedesktop.systemd1.Unit", "Id", bus_unit_append_id, "s", u },
197 { "org.freedesktop.systemd1.Unit", "Description", bus_unit_append_description, "s", u },
198 { "org.freedesktop.systemd1.Unit", "LoadState", bus_unit_append_load_state, "s", u },
199 { "org.freedesktop.systemd1.Unit", "ActiveState", bus_unit_append_active_state, "s", u },
200 { "org.freedesktop.systemd1.Unit", "LoadPath", bus_property_append_string, "s", u->meta.load_path },
201 { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestamp", bus_property_append_uint64, "t", &u->meta.active_enter_timestamp },
202 { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp", bus_property_append_uint64, "t", &u->meta.active_exit_timestamp },
203 { "org.freedesktop.systemd1.Unit", "CanReload", bus_unit_append_can_reload, "b", u },
204 { "org.freedesktop.systemd1.Unit", "CanStart", bus_unit_append_can_start, "b", u },
86ad3bc1 205 { "org.freedesktop.systemd1.Unit", "Job", bus_unit_append_job, "(uo)", u },
ea430986
LP
206 { NULL, NULL, NULL, NULL, NULL }
207 };
208
b548631a
LP
209 DBusMessage *reply = NULL;
210 Manager *m = u->meta.manager;
211 DBusError error;
212 JobType job_type = _JOB_TYPE_INVALID;
213
214 dbus_error_init(&error);
215
216 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Start"))
217 job_type = JOB_START;
218 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Stop"))
219 job_type = JOB_STOP;
220 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Reload"))
221 job_type = JOB_RELOAD;
222 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Restart"))
223 job_type = JOB_RESTART;
224 else
225 return bus_default_message_handler(u->meta.manager, message, introspection, properties);
226
227 if (job_type != _JOB_TYPE_INVALID) {
228 const char *smode;
229 JobMode mode;
230 Job *j;
231 int r;
232 char *path;
233
234 if (!dbus_message_get_args(
235 message,
236 &error,
237 DBUS_TYPE_STRING, &smode,
238 DBUS_TYPE_INVALID))
239 return bus_send_error_reply(m, message, &error, -EINVAL);
240
241 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID)
242 return bus_send_error_reply(m, message, NULL, -EINVAL);
243
244 if ((r = manager_add_job(m, job_type, u, mode, true, &j)) < 0)
245 return bus_send_error_reply(m, message, NULL, r);
246
247 if (!(reply = dbus_message_new_method_return(message)))
248 goto oom;
249
250 if (!(path = job_dbus_path(j)))
251 goto oom;
252
253 if (!dbus_message_append_args(
254 reply,
255 DBUS_TYPE_OBJECT_PATH, &path,
256 DBUS_TYPE_INVALID))
257 goto oom;
258 }
259
260 if (reply) {
261 if (!dbus_connection_send(m->bus, reply, NULL))
262 goto oom;
263
264 dbus_message_unref(reply);
265 }
266
267 return DBUS_HANDLER_RESULT_HANDLED;
268
269oom:
270 if (reply)
271 dbus_message_unref(reply);
272
273 dbus_error_free(&error);
274
275 return DBUS_HANDLER_RESULT_NEED_MEMORY;
ea430986
LP
276}
277
278static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
279 Manager *m = data;
280 Unit *u;
281 int r;
282
283 assert(connection);
284 assert(message);
285 assert(m);
286
287 log_debug("Got D-Bus request: %s.%s() on %s",
288 dbus_message_get_interface(message),
289 dbus_message_get_member(message),
290 dbus_message_get_path(message));
291
292 if ((r = manager_get_unit_from_dbus_path(m, dbus_message_get_path(message), &u)) < 0) {
293
294 if (r == -ENOMEM)
295 return DBUS_HANDLER_RESULT_NEED_MEMORY;
296
297 if (r == -ENOENT)
298 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
299
300 return bus_send_error_reply(m, message, NULL, r);
301 }
302
303 return bus_unit_message_dispatch(u, message);
304}
305
306const DBusObjectPathVTable bus_unit_vtable = {
307 .message_function = bus_unit_message_handler
308};