]>
Commit | Line | Data |
---|---|---|
ea430986 LP |
1 | /*-*- Mode: C; c-basic-offset: 8 -*-*/ |
2 | ||
3 | #include <errno.h> | |
4 | ||
5 | #include "dbus.h" | |
6 | #include "log.h" | |
7 | ||
8 | static 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 | ||
43 | static 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 | ||
60 | static 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 | ||
77 | static 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 | ||
94 | static 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 |
111 | static 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 | ||
128 | static 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 | ||
145 | static 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 |
193 | static 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 | ||
269 | oom: | |
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 | ||
278 | static 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 | ||
306 | const DBusObjectPathVTable bus_unit_vtable = { | |
307 | .message_function = bus_unit_message_handler | |
308 | }; |