]>
Commit | Line | Data |
---|---|---|
d6c9574f | 1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
ea430986 | 2 | |
a7334b09 LP |
3 | /*** |
4 | This file is part of systemd. | |
5 | ||
6 | Copyright 2010 Lennart Poettering | |
7 | ||
8 | systemd is free software; you can redistribute it and/or modify it | |
5430f7f2 LP |
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 | |
a7334b09 LP |
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 | |
5430f7f2 | 16 | Lesser General Public License for more details. |
a7334b09 | 17 | |
5430f7f2 | 18 | You should have received a copy of the GNU Lesser General Public License |
a7334b09 LP |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
20 | ***/ | |
21 | ||
ea430986 LP |
22 | #include <errno.h> |
23 | ||
24 | #include "dbus.h" | |
25 | #include "log.h" | |
4139c1b2 | 26 | #include "dbus-unit.h" |
398ef8ba | 27 | #include "bus-errors.h" |
bfebab7f | 28 | #include "dbus-common.h" |
e2417e41 | 29 | #include "selinux-access.h" |
246aa6dd LP |
30 | #include "cgroup-util.h" |
31 | #include "strv.h" | |
32 | #include "path-util.h" | |
ea430986 | 33 | |
9a60da28 | 34 | const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE; |
4288f619 | 35 | |
c4e2ceae LP |
36 | #define INVALIDATING_PROPERTIES \ |
37 | "LoadState\0" \ | |
38 | "ActiveState\0" \ | |
39 | "SubState\0" \ | |
40 | "InactiveExitTimestamp\0" \ | |
41 | "ActiveEnterTimestamp\0" \ | |
42 | "ActiveExitTimestamp\0" \ | |
43 | "InactiveEnterTimestamp\0" \ | |
44 | "Job\0" \ | |
34df5a34 | 45 | "NeedDaemonReload\0" |
c4e2ceae | 46 | |
e2110e5d | 47 | static int bus_unit_append_names(DBusMessageIter *i, const char *property, void *data) { |
4139c1b2 LP |
48 | char *t; |
49 | Iterator j; | |
50 | DBusMessageIter sub; | |
51 | Unit *u = data; | |
52 | ||
53 | if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) | |
54 | return -ENOMEM; | |
55 | ||
ac155bb8 | 56 | SET_FOREACH(t, u->names, j) |
4139c1b2 LP |
57 | if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t)) |
58 | return -ENOMEM; | |
59 | ||
60 | if (!dbus_message_iter_close_container(i, &sub)) | |
61 | return -ENOMEM; | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
e2110e5d | 66 | static int bus_unit_append_following(DBusMessageIter *i, const char *property, void *data) { |
a7f241db | 67 | Unit *u = data, *f; |
8fe914ec LP |
68 | const char *d; |
69 | ||
8fe914ec LP |
70 | assert(i); |
71 | assert(property); | |
72 | assert(u); | |
73 | ||
a7f241db | 74 | f = unit_following(u); |
ac155bb8 | 75 | d = f ? f->id : ""; |
8fe914ec LP |
76 | |
77 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) | |
78 | return -ENOMEM; | |
79 | ||
80 | return 0; | |
81 | } | |
82 | ||
e2110e5d | 83 | static int bus_unit_append_dependencies(DBusMessageIter *i, const char *property, void *data) { |
5301be81 LP |
84 | Unit *u; |
85 | Iterator j; | |
86 | DBusMessageIter sub; | |
87 | Set *s = data; | |
88 | ||
89 | if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) | |
90 | return -ENOMEM; | |
91 | ||
92 | SET_FOREACH(u, s, j) | |
ac155bb8 | 93 | if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &u->id)) |
5301be81 LP |
94 | return -ENOMEM; |
95 | ||
96 | if (!dbus_message_iter_close_container(i, &sub)) | |
97 | return -ENOMEM; | |
98 | ||
99 | return 0; | |
100 | } | |
101 | ||
e2110e5d | 102 | static int bus_unit_append_description(DBusMessageIter *i, const char *property, void *data) { |
ea430986 LP |
103 | Unit *u = data; |
104 | const char *d; | |
105 | ||
ea430986 LP |
106 | assert(i); |
107 | assert(property); | |
108 | assert(u); | |
109 | ||
110 | d = unit_description(u); | |
111 | ||
112 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) | |
113 | return -ENOMEM; | |
114 | ||
115 | return 0; | |
116 | } | |
117 | ||
e2110e5d | 118 | static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState); |
ea430986 | 119 | |
e2110e5d | 120 | static int bus_unit_append_active_state(DBusMessageIter *i, const char *property, void *data) { |
ea430986 LP |
121 | Unit *u = data; |
122 | const char *state; | |
123 | ||
ea430986 LP |
124 | assert(i); |
125 | assert(property); | |
126 | assert(u); | |
127 | ||
128 | state = unit_active_state_to_string(unit_active_state(u)); | |
129 | ||
130 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) | |
131 | return -ENOMEM; | |
132 | ||
133 | return 0; | |
134 | } | |
135 | ||
e2110e5d | 136 | static int bus_unit_append_sub_state(DBusMessageIter *i, const char *property, void *data) { |
10a94420 LP |
137 | Unit *u = data; |
138 | const char *state; | |
139 | ||
10a94420 LP |
140 | assert(i); |
141 | assert(property); | |
142 | assert(u); | |
143 | ||
144 | state = unit_sub_state_to_string(u); | |
145 | ||
146 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) | |
147 | return -ENOMEM; | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
e2110e5d | 152 | static int bus_unit_append_file_state(DBusMessageIter *i, const char *property, void *data) { |
a4375746 LP |
153 | Unit *u = data; |
154 | const char *state; | |
155 | ||
156 | assert(i); | |
157 | assert(property); | |
158 | assert(u); | |
159 | ||
160 | state = strempty(unit_file_state_to_string(unit_get_unit_file_state(u))); | |
161 | ||
162 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) | |
163 | return -ENOMEM; | |
164 | ||
165 | return 0; | |
166 | } | |
167 | ||
e2110e5d | 168 | static int bus_unit_append_can_start(DBusMessageIter *i, const char *property, void *data) { |
38131695 LP |
169 | Unit *u = data; |
170 | dbus_bool_t b; | |
171 | ||
38131695 LP |
172 | assert(i); |
173 | assert(property); | |
174 | assert(u); | |
175 | ||
064f51fa | 176 | b = unit_can_start(u) && |
ac155bb8 | 177 | !u->refuse_manual_start; |
b5e9dba8 LP |
178 | |
179 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) | |
180 | return -ENOMEM; | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
e2110e5d | 185 | static int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, void *data) { |
b5e9dba8 LP |
186 | Unit *u = data; |
187 | dbus_bool_t b; | |
188 | ||
b5e9dba8 LP |
189 | assert(i); |
190 | assert(property); | |
191 | assert(u); | |
192 | ||
193 | /* On the lower levels we assume that every unit we can start | |
194 | * we can also stop */ | |
195 | ||
196 | b = unit_can_start(u) && | |
ac155bb8 | 197 | !u->refuse_manual_stop; |
38131695 LP |
198 | |
199 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) | |
200 | return -ENOMEM; | |
201 | ||
202 | return 0; | |
203 | } | |
204 | ||
e2110e5d | 205 | static int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data) { |
38131695 LP |
206 | Unit *u = data; |
207 | dbus_bool_t b; | |
208 | ||
38131695 LP |
209 | assert(i); |
210 | assert(property); | |
211 | assert(u); | |
212 | ||
4139c1b2 | 213 | b = unit_can_reload(u); |
38131695 LP |
214 | |
215 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) | |
216 | return -ENOMEM; | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
e2110e5d | 221 | static int bus_unit_append_can_isolate(DBusMessageIter *i, const char *property, void *data) { |
2528a7a6 LP |
222 | Unit *u = data; |
223 | dbus_bool_t b; | |
224 | ||
2528a7a6 LP |
225 | assert(i); |
226 | assert(property); | |
227 | assert(u); | |
228 | ||
229 | b = unit_can_isolate(u) && | |
ac155bb8 | 230 | !u->refuse_manual_start; |
2528a7a6 LP |
231 | |
232 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) | |
233 | return -ENOMEM; | |
234 | ||
235 | return 0; | |
236 | } | |
237 | ||
e2110e5d | 238 | static int bus_unit_append_job(DBusMessageIter *i, const char *property, void *data) { |
38131695 LP |
239 | Unit *u = data; |
240 | DBusMessageIter sub; | |
f93891f3 | 241 | _cleanup_free_ char *p = NULL; |
38131695 | 242 | |
38131695 LP |
243 | assert(i); |
244 | assert(property); | |
245 | assert(u); | |
246 | ||
247 | if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub)) | |
248 | return -ENOMEM; | |
249 | ||
ac155bb8 | 250 | if (u->job) { |
38131695 | 251 | |
f93891f3 ZJS |
252 | p = job_dbus_path(u->job); |
253 | if (!p) | |
38131695 LP |
254 | return -ENOMEM; |
255 | ||
ac155bb8 | 256 | if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->job->id) || |
f93891f3 | 257 | !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) |
38131695 | 258 | return -ENOMEM; |
38131695 LP |
259 | } else { |
260 | uint32_t id = 0; | |
261 | ||
262 | /* No job, so let's fill in some placeholder | |
263 | * data. Since we need to fill in a valid path we | |
264 | * simple point to ourselves. */ | |
265 | ||
f93891f3 ZJS |
266 | p = unit_dbus_path(u); |
267 | if (!p) | |
38131695 LP |
268 | return -ENOMEM; |
269 | ||
270 | if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) || | |
f93891f3 | 271 | !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) |
38131695 | 272 | return -ENOMEM; |
38131695 LP |
273 | } |
274 | ||
38131695 LP |
275 | if (!dbus_message_iter_close_container(i, &sub)) |
276 | return -ENOMEM; | |
277 | ||
278 | return 0; | |
279 | } | |
280 | ||
e2110e5d | 281 | static int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) { |
4139c1b2 LP |
282 | Unit *u = data; |
283 | char *t; | |
284 | CGroupBonding *cgb; | |
285 | bool success; | |
ea430986 | 286 | |
4139c1b2 LP |
287 | assert(i); |
288 | assert(property); | |
289 | assert(u); | |
290 | ||
f93891f3 ZJS |
291 | cgb = unit_get_default_cgroup(u); |
292 | if (cgb) { | |
293 | t = cgroup_bonding_to_string(cgb); | |
294 | if (!t) | |
4139c1b2 LP |
295 | return -ENOMEM; |
296 | } else | |
297 | t = (char*) ""; | |
ea430986 | 298 | |
4139c1b2 LP |
299 | success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t); |
300 | ||
301 | if (cgb) | |
302 | free(t); | |
303 | ||
304 | return success ? 0 : -ENOMEM; | |
305 | } | |
306 | ||
e2110e5d | 307 | static int bus_unit_append_cgroups(DBusMessageIter *i, const char *property, void *data) { |
4139c1b2 LP |
308 | Unit *u = data; |
309 | CGroupBonding *cgb; | |
310 | DBusMessageIter sub; | |
311 | ||
312 | if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) | |
313 | return -ENOMEM; | |
314 | ||
ac155bb8 | 315 | LIST_FOREACH(by_unit, cgb, u->cgroup_bondings) { |
f93891f3 | 316 | char _cleanup_free_ *t = NULL; |
4139c1b2 LP |
317 | bool success; |
318 | ||
f93891f3 ZJS |
319 | t = cgroup_bonding_to_string(cgb); |
320 | if (!t) | |
4139c1b2 LP |
321 | return -ENOMEM; |
322 | ||
323 | success = dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t); | |
4139c1b2 LP |
324 | if (!success) |
325 | return -ENOMEM; | |
326 | } | |
327 | ||
328 | if (!dbus_message_iter_close_container(i, &sub)) | |
329 | return -ENOMEM; | |
330 | ||
331 | return 0; | |
332 | } | |
333 | ||
e2110e5d | 334 | static int bus_unit_append_cgroup_attrs(DBusMessageIter *i, const char *property, void *data) { |
d8bbda91 LP |
335 | Unit *u = data; |
336 | CGroupAttribute *a; | |
337 | DBusMessageIter sub, sub2; | |
338 | ||
339 | if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sss)", &sub)) | |
340 | return -ENOMEM; | |
341 | ||
ac155bb8 | 342 | LIST_FOREACH(by_unit, a, u->cgroup_attributes) { |
f93891f3 | 343 | char _cleanup_free_ *v = NULL; |
d8bbda91 LP |
344 | bool success; |
345 | ||
346 | if (a->map_callback) | |
347 | a->map_callback(a->controller, a->name, a->value, &v); | |
348 | ||
349 | success = | |
350 | dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) && | |
351 | dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->controller) && | |
352 | dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->name) && | |
353 | dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, v ? &v : &a->value) && | |
354 | dbus_message_iter_close_container(&sub, &sub2); | |
d8bbda91 LP |
355 | if (!success) |
356 | return -ENOMEM; | |
357 | } | |
358 | ||
359 | if (!dbus_message_iter_close_container(i, &sub)) | |
360 | return -ENOMEM; | |
361 | ||
362 | return 0; | |
363 | } | |
364 | ||
e2110e5d | 365 | static int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data) { |
45fb0699 LP |
366 | Unit *u = data; |
367 | dbus_bool_t b; | |
368 | ||
45fb0699 LP |
369 | assert(i); |
370 | assert(property); | |
371 | assert(u); | |
372 | ||
373 | b = unit_need_daemon_reload(u); | |
374 | ||
375 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) | |
376 | return -ENOMEM; | |
377 | ||
378 | return 0; | |
379 | } | |
380 | ||
e2110e5d | 381 | static int bus_unit_append_load_error(DBusMessageIter *i, const char *property, void *data) { |
9f39404c LP |
382 | Unit *u = data; |
383 | const char *name, *message; | |
384 | DBusMessageIter sub; | |
385 | ||
386 | assert(i); | |
387 | assert(property); | |
388 | assert(u); | |
389 | ||
ac155bb8 MS |
390 | if (u->load_error != 0) { |
391 | name = bus_errno_to_dbus(u->load_error); | |
392 | message = strempty(strerror(-u->load_error)); | |
9f39404c LP |
393 | } else |
394 | name = message = ""; | |
395 | ||
396 | if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub) || | |
397 | !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &name) || | |
398 | !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &message) || | |
399 | !dbus_message_iter_close_container(i, &sub)) | |
400 | return -ENOMEM; | |
401 | ||
402 | return 0; | |
403 | } | |
404 | ||
5e8d1c9a | 405 | static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *connection, DBusMessage *message) { |
cad45ba1 | 406 | _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; |
b548631a LP |
407 | DBusError error; |
408 | JobType job_type = _JOB_TYPE_INVALID; | |
6f28c033 | 409 | bool reload_if_possible = false; |
e2417e41 | 410 | int r; |
b548631a LP |
411 | |
412 | dbus_error_init(&error); | |
413 | ||
414 | if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Start")) | |
415 | job_type = JOB_START; | |
416 | else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Stop")) | |
417 | job_type = JOB_STOP; | |
418 | else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Reload")) | |
419 | job_type = JOB_RELOAD; | |
420 | else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Restart")) | |
421 | job_type = JOB_RESTART; | |
9a1ac7b9 LP |
422 | else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "TryRestart")) |
423 | job_type = JOB_TRY_RESTART; | |
6f28c033 LP |
424 | else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrRestart")) { |
425 | reload_if_possible = true; | |
426 | job_type = JOB_RESTART; | |
427 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) { | |
428 | reload_if_possible = true; | |
429 | job_type = JOB_TRY_RESTART; | |
8a0867d6 | 430 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Kill")) { |
c74f17d9 | 431 | const char *swho; |
8a0867d6 | 432 | int32_t signo; |
8a0867d6 | 433 | KillWho who; |
8a0867d6 LP |
434 | |
435 | if (!dbus_message_get_args( | |
436 | message, | |
437 | &error, | |
438 | DBUS_TYPE_STRING, &swho, | |
8a0867d6 LP |
439 | DBUS_TYPE_INT32, &signo, |
440 | DBUS_TYPE_INVALID)) | |
bfebab7f | 441 | return bus_send_error_reply(connection, message, &error, -EINVAL); |
8a0867d6 | 442 | |
0a524ba7 LP |
443 | if (isempty(swho)) |
444 | who = KILL_ALL; | |
445 | else { | |
446 | who = kill_who_from_string(swho); | |
447 | if (who < 0) | |
448 | return bus_send_error_reply(connection, message, &error, -EINVAL); | |
449 | } | |
450 | ||
0a524ba7 | 451 | if (signo <= 0 || signo >= _NSIG) |
bfebab7f | 452 | return bus_send_error_reply(connection, message, &error, -EINVAL); |
8a0867d6 | 453 | |
cad45ba1 LP |
454 | SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); |
455 | ||
c74f17d9 LP |
456 | r = unit_kill(u, who, signo, &error); |
457 | if (r < 0) | |
bfebab7f | 458 | return bus_send_error_reply(connection, message, &error, r); |
8a0867d6 | 459 | |
c74f17d9 LP |
460 | reply = dbus_message_new_method_return(message); |
461 | if (!reply) | |
8a0867d6 LP |
462 | goto oom; |
463 | ||
fdf20a31 | 464 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ResetFailed")) { |
5632e374 | 465 | |
cad45ba1 LP |
466 | SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload"); |
467 | ||
fdf20a31 | 468 | unit_reset_failed(u); |
5632e374 | 469 | |
cad45ba1 LP |
470 | reply = dbus_message_new_method_return(message); |
471 | if (!reply) | |
5632e374 LP |
472 | goto oom; |
473 | ||
246aa6dd LP |
474 | } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroups")) { |
475 | DBusMessageIter iter; | |
476 | ||
477 | SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start"); | |
478 | ||
479 | if (!dbus_message_iter_init(message, &iter)) | |
480 | goto oom; | |
481 | ||
482 | r = bus_unit_cgroup_set(u, &iter); | |
483 | if (r < 0) | |
484 | return bus_send_error_reply(connection, message, NULL, r); | |
485 | ||
486 | reply = dbus_message_new_method_return(message); | |
487 | if (!reply) | |
488 | goto oom; | |
489 | ||
490 | } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroups")) { | |
491 | DBusMessageIter iter; | |
492 | ||
493 | SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); | |
494 | ||
495 | if (!dbus_message_iter_init(message, &iter)) | |
496 | goto oom; | |
497 | ||
498 | r = bus_unit_cgroup_set(u, &iter); | |
499 | if (r < 0) | |
500 | return bus_send_error_reply(connection, message, NULL, r); | |
501 | ||
502 | reply = dbus_message_new_method_return(message); | |
503 | if (!reply) | |
504 | goto oom; | |
505 | } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroupAttributes")) { | |
506 | DBusMessageIter iter; | |
507 | ||
508 | SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start"); | |
509 | ||
510 | if (!dbus_message_iter_init(message, &iter)) | |
511 | goto oom; | |
512 | ||
513 | r = bus_unit_cgroup_attribute_set(u, &iter); | |
514 | if (r < 0) | |
515 | return bus_send_error_reply(connection, message, NULL, r); | |
516 | ||
517 | reply = dbus_message_new_method_return(message); | |
518 | if (!reply) | |
519 | goto oom; | |
520 | ||
521 | } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroupAttributes")) { | |
522 | DBusMessageIter iter; | |
523 | ||
524 | SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); | |
525 | ||
526 | if (!dbus_message_iter_init(message, &iter)) | |
527 | goto oom; | |
528 | ||
529 | r = bus_unit_cgroup_attribute_unset(u, &iter); | |
530 | if (r < 0) | |
531 | return bus_send_error_reply(connection, message, NULL, r); | |
532 | ||
533 | reply = dbus_message_new_method_return(message); | |
534 | if (!reply) | |
535 | goto oom; | |
536 | ||
6f28c033 | 537 | } else if (UNIT_VTABLE(u)->bus_message_handler) |
5e8d1c9a | 538 | return UNIT_VTABLE(u)->bus_message_handler(u, connection, message); |
b548631a | 539 | else |
4139c1b2 | 540 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
b548631a LP |
541 | |
542 | if (job_type != _JOB_TYPE_INVALID) { | |
543 | const char *smode; | |
544 | JobMode mode; | |
bc0f8771 | 545 | |
b548631a LP |
546 | if (!dbus_message_get_args( |
547 | message, | |
548 | &error, | |
549 | DBUS_TYPE_STRING, &smode, | |
550 | DBUS_TYPE_INVALID)) | |
bfebab7f | 551 | return bus_send_error_reply(connection, message, &error, -EINVAL); |
b548631a | 552 | |
cad45ba1 LP |
553 | mode = job_mode_from_string(smode); |
554 | if (mode < 0) { | |
398ef8ba | 555 | dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); |
bfebab7f | 556 | return bus_send_error_reply(connection, message, &error, -EINVAL); |
398ef8ba | 557 | } |
b548631a | 558 | |
cad45ba1 | 559 | return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible); |
b548631a LP |
560 | } |
561 | ||
cad45ba1 | 562 | if (reply) |
5e8d1c9a | 563 | if (!dbus_connection_send(connection, reply, NULL)) |
b548631a LP |
564 | goto oom; |
565 | ||
b548631a LP |
566 | return DBUS_HANDLER_RESULT_HANDLED; |
567 | ||
568 | oom: | |
b548631a | 569 | dbus_error_free(&error); |
b548631a | 570 | return DBUS_HANDLER_RESULT_NEED_MEMORY; |
ea430986 LP |
571 | } |
572 | ||
5e8d1c9a | 573 | static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DBusMessage *message, void *data) { |
ea430986 LP |
574 | Manager *m = data; |
575 | Unit *u; | |
576 | int r; | |
cad45ba1 | 577 | _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; |
80fbf05e | 578 | DBusError error; |
ea430986 LP |
579 | |
580 | assert(connection); | |
581 | assert(message); | |
582 | assert(m); | |
583 | ||
80fbf05e MS |
584 | dbus_error_init(&error); |
585 | ||
2cccbca4 LP |
586 | if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/unit")) { |
587 | /* Be nice to gdbus and return introspection data for our mid-level paths */ | |
588 | ||
ffc227c9 | 589 | SELINUX_ACCESS_CHECK(connection, message, "status"); |
cad45ba1 | 590 | |
2cccbca4 LP |
591 | if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { |
592 | char *introspection = NULL; | |
593 | FILE *f; | |
594 | Iterator i; | |
595 | const char *k; | |
596 | size_t size; | |
597 | ||
cad45ba1 LP |
598 | reply = dbus_message_new_method_return(message); |
599 | if (!reply) | |
2cccbca4 LP |
600 | goto oom; |
601 | ||
602 | /* We roll our own introspection code here, instead of | |
603 | * relying on bus_default_message_handler() because we | |
604 | * need to generate our introspection string | |
605 | * dynamically. */ | |
606 | ||
cad45ba1 LP |
607 | f = open_memstream(&introspection, &size); |
608 | if (!f) | |
2cccbca4 LP |
609 | goto oom; |
610 | ||
611 | fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE | |
612 | "<node>\n", f); | |
613 | ||
614 | fputs(BUS_INTROSPECTABLE_INTERFACE, f); | |
615 | fputs(BUS_PEER_INTERFACE, f); | |
616 | ||
617 | HASHMAP_FOREACH_KEY(u, k, m->units, i) { | |
618 | char *p; | |
619 | ||
ac155bb8 | 620 | if (k != u->id) |
2cccbca4 LP |
621 | continue; |
622 | ||
cad45ba1 LP |
623 | p = bus_path_escape(k); |
624 | if (!p) { | |
2cccbca4 LP |
625 | fclose(f); |
626 | free(introspection); | |
627 | goto oom; | |
628 | } | |
629 | ||
630 | fprintf(f, "<node name=\"%s\"/>", p); | |
631 | free(p); | |
632 | } | |
633 | ||
634 | fputs("</node>\n", f); | |
635 | ||
636 | if (ferror(f)) { | |
637 | fclose(f); | |
638 | free(introspection); | |
639 | goto oom; | |
640 | } | |
641 | ||
642 | fclose(f); | |
643 | ||
644 | if (!introspection) | |
645 | goto oom; | |
646 | ||
647 | if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { | |
648 | free(introspection); | |
649 | goto oom; | |
650 | } | |
651 | ||
652 | free(introspection); | |
653 | ||
654 | if (!dbus_connection_send(connection, reply, NULL)) | |
655 | goto oom; | |
656 | ||
2cccbca4 LP |
657 | return DBUS_HANDLER_RESULT_HANDLED; |
658 | } | |
659 | ||
660 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | |
661 | } | |
662 | ||
80fbf05e | 663 | r = manager_load_unit_from_dbus_path(m, dbus_message_get_path(message), &error, &u); |
cad45ba1 LP |
664 | if (r == -ENOMEM) |
665 | goto oom; | |
666 | if (r < 0) | |
80fbf05e | 667 | return bus_send_error_reply(connection, message, &error, r); |
ea430986 | 668 | |
5e8d1c9a | 669 | return bus_unit_message_dispatch(u, connection, message); |
2cccbca4 LP |
670 | |
671 | oom: | |
80fbf05e MS |
672 | dbus_error_free(&error); |
673 | ||
2cccbca4 | 674 | return DBUS_HANDLER_RESULT_NEED_MEMORY; |
ea430986 LP |
675 | } |
676 | ||
677 | const DBusObjectPathVTable bus_unit_vtable = { | |
678 | .message_function = bus_unit_message_handler | |
679 | }; | |
c1e1601e LP |
680 | |
681 | void bus_unit_send_change_signal(Unit *u) { | |
f93891f3 ZJS |
682 | _cleanup_free_ char *p = NULL; |
683 | _cleanup_dbus_message_unref_ DBusMessage *m = NULL; | |
c1e1601e LP |
684 | |
685 | assert(u); | |
c1e1601e | 686 | |
ac155bb8 MS |
687 | if (u->in_dbus_queue) { |
688 | LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u); | |
689 | u->in_dbus_queue = false; | |
c0bd0cf7 | 690 | } |
c1e1601e | 691 | |
ac155bb8 | 692 | if (!u->id) |
04ade7d2 LP |
693 | return; |
694 | ||
ac155bb8 MS |
695 | if (!bus_has_subscriber(u->manager)) { |
696 | u->sent_dbus_new_signal = true; | |
c1e1601e | 697 | return; |
94b6dfa2 | 698 | } |
c1e1601e | 699 | |
f93891f3 ZJS |
700 | p = unit_dbus_path(u); |
701 | if (!p) | |
c1e1601e LP |
702 | goto oom; |
703 | ||
ac155bb8 | 704 | if (u->sent_dbus_new_signal) { |
c4e2ceae LP |
705 | /* Send a properties changed signal. First for the |
706 | * specific type, then for the generic unit. The | |
707 | * clients may rely on this order to get atomic | |
c5315881 | 708 | * behavior if needed. */ |
c4e2ceae LP |
709 | |
710 | if (UNIT_VTABLE(u)->bus_invalidating_properties) { | |
711 | ||
f93891f3 ZJS |
712 | m = bus_properties_changed_new(p, |
713 | UNIT_VTABLE(u)->bus_interface, | |
714 | UNIT_VTABLE(u)->bus_invalidating_properties); | |
715 | if (!m) | |
c4e2ceae LP |
716 | goto oom; |
717 | ||
ac155bb8 | 718 | if (bus_broadcast(u->manager, m) < 0) |
c4e2ceae | 719 | goto oom; |
c1e1601e | 720 | |
c4e2ceae LP |
721 | dbus_message_unref(m); |
722 | } | |
723 | ||
f93891f3 ZJS |
724 | m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Unit", |
725 | INVALIDATING_PROPERTIES); | |
726 | if (!m) | |
c1e1601e | 727 | goto oom; |
c4e2ceae | 728 | |
c1e1601e | 729 | } else { |
c1e1601e LP |
730 | /* Send a new signal */ |
731 | ||
f93891f3 ZJS |
732 | m = dbus_message_new_signal("/org/freedesktop/systemd1", |
733 | "org.freedesktop.systemd1.Manager", | |
734 | "UnitNew"); | |
735 | if (!m) | |
c1e1601e LP |
736 | goto oom; |
737 | ||
c1e1601e | 738 | if (!dbus_message_append_args(m, |
ac155bb8 | 739 | DBUS_TYPE_STRING, &u->id, |
c1e1601e LP |
740 | DBUS_TYPE_OBJECT_PATH, &p, |
741 | DBUS_TYPE_INVALID)) | |
742 | goto oom; | |
743 | } | |
744 | ||
ac155bb8 | 745 | if (bus_broadcast(u->manager, m) < 0) |
c1e1601e LP |
746 | goto oom; |
747 | ||
ac155bb8 | 748 | u->sent_dbus_new_signal = true; |
c1e1601e LP |
749 | |
750 | return; | |
751 | ||
752 | oom: | |
f93891f3 | 753 | log_oom(); |
c1e1601e LP |
754 | } |
755 | ||
756 | void bus_unit_send_removed_signal(Unit *u) { | |
f93891f3 ZJS |
757 | _cleanup_free_ char *p = NULL; |
758 | _cleanup_dbus_message_unref_ DBusMessage *m = NULL; | |
c1e1601e LP |
759 | |
760 | assert(u); | |
761 | ||
ac155bb8 | 762 | if (!bus_has_subscriber(u->manager)) |
c1e1601e LP |
763 | return; |
764 | ||
ac155bb8 | 765 | if (!u->sent_dbus_new_signal) |
7535cc78 LP |
766 | bus_unit_send_change_signal(u); |
767 | ||
ac155bb8 | 768 | if (!u->id) |
04ade7d2 LP |
769 | return; |
770 | ||
f93891f3 ZJS |
771 | p = unit_dbus_path(u); |
772 | if (!p) | |
c1e1601e LP |
773 | goto oom; |
774 | ||
f93891f3 ZJS |
775 | m = dbus_message_new_signal("/org/freedesktop/systemd1", |
776 | "org.freedesktop.systemd1.Manager", | |
777 | "UnitRemoved"); | |
778 | if (!m) | |
c1e1601e LP |
779 | goto oom; |
780 | ||
c1e1601e | 781 | if (!dbus_message_append_args(m, |
ac155bb8 | 782 | DBUS_TYPE_STRING, &u->id, |
c1e1601e LP |
783 | DBUS_TYPE_OBJECT_PATH, &p, |
784 | DBUS_TYPE_INVALID)) | |
785 | goto oom; | |
786 | ||
ac155bb8 | 787 | if (bus_broadcast(u->manager, m) < 0) |
c1e1601e LP |
788 | goto oom; |
789 | ||
c1e1601e LP |
790 | return; |
791 | ||
792 | oom: | |
f93891f3 | 793 | log_oom(); |
c1e1601e | 794 | } |
e2110e5d | 795 | |
cad45ba1 LP |
796 | DBusHandlerResult bus_unit_queue_job( |
797 | DBusConnection *connection, | |
798 | DBusMessage *message, | |
799 | Unit *u, | |
800 | JobType type, | |
801 | JobMode mode, | |
802 | bool reload_if_possible) { | |
803 | ||
804 | _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; | |
805 | _cleanup_free_ char *path = NULL; | |
806 | Job *j; | |
807 | JobBusClient *cl; | |
808 | DBusError error; | |
809 | int r; | |
810 | ||
811 | assert(connection); | |
812 | assert(message); | |
813 | assert(u); | |
814 | assert(type >= 0 && type < _JOB_TYPE_MAX); | |
815 | assert(mode >= 0 && mode < _JOB_MODE_MAX); | |
816 | ||
817 | dbus_error_init(&error); | |
818 | ||
819 | if (reload_if_possible && unit_can_reload(u)) { | |
820 | if (type == JOB_RESTART) | |
821 | type = JOB_RELOAD_OR_START; | |
822 | else if (type == JOB_TRY_RESTART) | |
823 | type = JOB_RELOAD; | |
824 | } | |
825 | ||
826 | SELINUX_UNIT_ACCESS_CHECK(u, connection, message, | |
827 | (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" : | |
828 | type == JOB_STOP ? "stop" : "reload"); | |
829 | ||
830 | if (type == JOB_STOP && u->load_state == UNIT_ERROR && unit_active_state(u) == UNIT_INACTIVE) { | |
831 | dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); | |
832 | return bus_send_error_reply(connection, message, &error, -EPERM); | |
833 | } | |
834 | ||
835 | if ((type == JOB_START && u->refuse_manual_start) || | |
836 | (type == JOB_STOP && u->refuse_manual_stop) || | |
837 | ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop))) { | |
f93891f3 ZJS |
838 | dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, |
839 | "Operation refused, unit %s may be requested by dependency only.", u->id); | |
cad45ba1 LP |
840 | return bus_send_error_reply(connection, message, &error, -EPERM); |
841 | } | |
842 | ||
843 | r = manager_add_job(u->manager, type, u, mode, true, &error, &j); | |
844 | if (r < 0) | |
845 | return bus_send_error_reply(connection, message, &error, r); | |
846 | ||
847 | cl = job_bus_client_new(connection, bus_message_get_sender_with_fallback(message)); | |
848 | if (!cl) | |
849 | goto oom; | |
850 | ||
851 | LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl); | |
852 | ||
853 | reply = dbus_message_new_method_return(message); | |
854 | if (!reply) | |
855 | goto oom; | |
856 | ||
857 | path = job_dbus_path(j); | |
858 | if (!path) | |
859 | goto oom; | |
860 | ||
861 | if (!dbus_message_append_args( | |
862 | reply, | |
863 | DBUS_TYPE_OBJECT_PATH, &path, | |
864 | DBUS_TYPE_INVALID)) | |
865 | goto oom; | |
866 | ||
867 | if (!dbus_connection_send(connection, reply, NULL)) | |
868 | goto oom; | |
869 | ||
870 | return DBUS_HANDLER_RESULT_HANDLED; | |
871 | ||
872 | oom: | |
873 | dbus_error_free(&error); | |
874 | ||
875 | return DBUS_HANDLER_RESULT_NEED_MEMORY; | |
876 | } | |
877 | ||
246aa6dd LP |
878 | int bus_unit_cgroup_set(Unit *u, DBusMessageIter *iter) { |
879 | int r; | |
880 | _cleanup_strv_free_ char **a = NULL; | |
881 | char **name; | |
882 | ||
883 | assert(u); | |
884 | assert(iter); | |
885 | ||
886 | if (!unit_get_exec_context(u)) | |
887 | return -EINVAL; | |
888 | ||
889 | r = bus_parse_strv_iter(iter, &a); | |
890 | if (r < 0) | |
891 | return r; | |
892 | ||
893 | STRV_FOREACH(name, a) { | |
894 | _cleanup_free_ char *controller = NULL, *old_path = NULL, *new_path = NULL; | |
895 | CGroupBonding *b; | |
896 | ||
897 | r = cg_split_spec(*name, &controller, &new_path); | |
898 | if (r < 0) | |
899 | return r; | |
900 | ||
901 | b = cgroup_bonding_find_list(u->cgroup_bondings, controller); | |
902 | if (b) { | |
903 | old_path = strdup(b->path); | |
904 | if (!old_path) | |
905 | return -ENOMEM; | |
906 | } | |
907 | ||
908 | r = unit_add_cgroup_from_text(u, *name, true, &b); | |
909 | if (r < 0) | |
910 | return r; | |
911 | ||
912 | if (r > 0) { | |
913 | /* Try to move things to the new place, and clean up the old place */ | |
914 | cgroup_bonding_realize(b); | |
915 | cgroup_bonding_migrate(b, u->cgroup_bondings); | |
916 | ||
917 | if (old_path) | |
918 | cg_trim(controller, old_path, true); | |
919 | } | |
920 | } | |
921 | ||
922 | return 0; | |
923 | } | |
924 | ||
925 | int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) { | |
926 | _cleanup_strv_free_ char **a = NULL; | |
927 | char **name; | |
928 | int r; | |
929 | ||
930 | assert(u); | |
931 | assert(iter); | |
932 | ||
933 | if (!unit_get_exec_context(u)) | |
934 | return -EINVAL; | |
935 | ||
936 | r = bus_parse_strv_iter(iter, &a); | |
937 | if (r < 0) | |
938 | return r; | |
939 | ||
940 | STRV_FOREACH(name, a) { | |
941 | _cleanup_free_ char *controller = NULL, *path = NULL, *target = NULL; | |
942 | CGroupBonding *b; | |
943 | ||
944 | r = cg_split_spec(*name, &controller, &path); | |
945 | if (r < 0) | |
946 | return r; | |
947 | ||
948 | b = cgroup_bonding_find_list(u->cgroup_bondings, controller); | |
949 | if (!b) | |
950 | continue; | |
951 | ||
952 | if (path && !path_equal(path, b->path)) | |
953 | continue; | |
954 | ||
955 | if (b->essential) | |
956 | return -EINVAL; | |
957 | ||
958 | /* Try to migrate the old group away */ | |
959 | if (cg_get_by_pid(controller, 0, &target) >= 0) | |
960 | cgroup_bonding_migrate_to(u->cgroup_bondings, target, false); | |
961 | ||
962 | cgroup_bonding_free(b, true); | |
963 | } | |
964 | ||
965 | return 0; | |
966 | } | |
967 | ||
968 | int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) { | |
969 | DBusMessageIter sub, sub2; | |
970 | int r; | |
971 | ||
972 | assert(u); | |
973 | assert(iter); | |
974 | ||
975 | if (!unit_get_exec_context(u)) | |
976 | return -EINVAL; | |
977 | ||
978 | if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || | |
979 | dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRUCT) | |
980 | return -EINVAL; | |
981 | ||
982 | dbus_message_iter_recurse(iter, &sub); | |
983 | ||
984 | while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { | |
985 | const char *name, *value; | |
986 | CGroupAttribute *a; | |
987 | ||
988 | assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT); | |
989 | ||
990 | dbus_message_iter_recurse(&sub, &sub2); | |
991 | ||
992 | if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 || | |
993 | bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) < 0) | |
994 | return -EINVAL; | |
995 | ||
996 | dbus_message_iter_next(&sub); | |
997 | ||
998 | r = unit_add_cgroup_attribute(u, NULL, name, value, NULL, &a); | |
999 | if (r < 0) | |
1000 | return r; | |
1001 | ||
1002 | if (r > 0) { | |
1003 | CGroupBonding *b; | |
1004 | ||
1005 | b = cgroup_bonding_find_list(u->cgroup_bondings, a->controller); | |
1006 | if (!b) { | |
1007 | /* Doesn't exist yet? Then let's add it */ | |
1008 | r = unit_add_cgroup_from_text(u, a->controller, false, &b); | |
1009 | if (r < 0) | |
1010 | return r; | |
1011 | ||
1012 | if (r > 0) { | |
1013 | cgroup_bonding_realize(b); | |
1014 | cgroup_bonding_migrate(b, u->cgroup_bondings); | |
1015 | } | |
1016 | } | |
1017 | ||
1018 | /* Make it count */ | |
1019 | cgroup_attribute_apply(a, u->cgroup_bondings); | |
1020 | } | |
1021 | } | |
1022 | ||
1023 | return 0; | |
1024 | } | |
1025 | ||
1026 | int bus_unit_cgroup_attribute_unset(Unit *u, DBusMessageIter *iter) { | |
1027 | _cleanup_strv_free_ char **l = NULL; | |
1028 | char **name; | |
1029 | int r; | |
1030 | ||
1031 | assert(u); | |
1032 | assert(iter); | |
1033 | ||
1034 | if (!unit_get_exec_context(u)) | |
1035 | return -EINVAL; | |
1036 | ||
1037 | r = bus_parse_strv_iter(iter, &l); | |
1038 | if (r < 0) | |
1039 | return r; | |
1040 | ||
1041 | STRV_FOREACH(name, l) { | |
1042 | CGroupAttribute *a; | |
1043 | ||
1044 | a = cgroup_attribute_find_list(u->cgroup_attributes, NULL, *name); | |
1045 | if (a) | |
1046 | cgroup_attribute_free(a); | |
1047 | } | |
1048 | ||
1049 | return 0; | |
1050 | } | |
1051 | ||
e2110e5d MS |
1052 | const BusProperty bus_unit_properties[] = { |
1053 | { "Id", bus_property_append_string, "s", offsetof(Unit, id), true }, | |
1054 | { "Names", bus_unit_append_names, "as", 0 }, | |
1055 | { "Following", bus_unit_append_following, "s", 0 }, | |
1056 | { "Requires", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRES]), true }, | |
1057 | { "RequiresOverridable", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), true }, | |
1058 | { "Requisite", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUISITE]), true }, | |
1059 | { "RequisiteOverridable", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), true }, | |
1060 | { "Wants", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_WANTS]), true }, | |
7f2cddae | 1061 | { "BindsTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BINDS_TO]), true }, |
b05afff1 | 1062 | { "PartOf", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PART_OF]), true }, |
e2110e5d MS |
1063 | { "RequiredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), true }, |
1064 | { "RequiredByOverridable",bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), true }, | |
1065 | { "WantedBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_WANTED_BY]), true }, | |
1066 | { "BoundBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BOUND_BY]), true }, | |
b05afff1 | 1067 | { "ConsistsOf", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), true }, |
e2110e5d MS |
1068 | { "Conflicts", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_CONFLICTS]), true }, |
1069 | { "ConflictedBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), true }, | |
1070 | { "Before", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BEFORE]), true }, | |
1071 | { "After", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_AFTER]), true }, | |
1072 | { "OnFailure", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_ON_FAILURE]), true }, | |
1073 | { "Triggers", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERS]), true }, | |
1074 | { "TriggeredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), true }, | |
7f2cddae LP |
1075 | { "PropagatesReloadTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), true }, |
1076 | { "ReloadPropagatedFrom", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), true }, | |
7c8fa05c | 1077 | { "RequiresMountsFor", bus_property_append_strv, "as", offsetof(Unit, requires_mounts_for), true }, |
49dbfa7b | 1078 | { "Documentation", bus_property_append_strv, "as", offsetof(Unit, documentation), true }, |
e2110e5d MS |
1079 | { "Description", bus_unit_append_description, "s", 0 }, |
1080 | { "LoadState", bus_unit_append_load_state, "s", offsetof(Unit, load_state) }, | |
1081 | { "ActiveState", bus_unit_append_active_state, "s", 0 }, | |
1082 | { "SubState", bus_unit_append_sub_state, "s", 0 }, | |
1083 | { "FragmentPath", bus_property_append_string, "s", offsetof(Unit, fragment_path), true }, | |
1b64d026 | 1084 | { "SourcePath", bus_property_append_string, "s", offsetof(Unit, source_path), true }, |
e2110e5d MS |
1085 | { "UnitFileState", bus_unit_append_file_state, "s", 0 }, |
1086 | { "InactiveExitTimestamp",bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.realtime) }, | |
1087 | { "InactiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.monotonic) }, | |
1088 | { "ActiveEnterTimestamp", bus_property_append_usec, "t", offsetof(Unit, active_enter_timestamp.realtime) }, | |
1089 | { "ActiveEnterTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, active_enter_timestamp.monotonic) }, | |
1090 | { "ActiveExitTimestamp", bus_property_append_usec, "t", offsetof(Unit, active_exit_timestamp.realtime) }, | |
1091 | { "ActiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, active_exit_timestamp.monotonic) }, | |
1092 | { "InactiveEnterTimestamp", bus_property_append_usec, "t", offsetof(Unit, inactive_enter_timestamp.realtime) }, | |
1093 | { "InactiveEnterTimestampMonotonic",bus_property_append_usec, "t", offsetof(Unit, inactive_enter_timestamp.monotonic) }, | |
1094 | { "CanStart", bus_unit_append_can_start, "b", 0 }, | |
1095 | { "CanStop", bus_unit_append_can_stop, "b", 0 }, | |
1096 | { "CanReload", bus_unit_append_can_reload, "b", 0 }, | |
1097 | { "CanIsolate", bus_unit_append_can_isolate, "b", 0 }, | |
1098 | { "Job", bus_unit_append_job, "(uo)", 0 }, | |
1099 | { "StopWhenUnneeded", bus_property_append_bool, "b", offsetof(Unit, stop_when_unneeded) }, | |
1100 | { "RefuseManualStart", bus_property_append_bool, "b", offsetof(Unit, refuse_manual_start) }, | |
1101 | { "RefuseManualStop", bus_property_append_bool, "b", offsetof(Unit, refuse_manual_stop) }, | |
1102 | { "AllowIsolate", bus_property_append_bool, "b", offsetof(Unit, allow_isolate) }, | |
1103 | { "DefaultDependencies", bus_property_append_bool, "b", offsetof(Unit, default_dependencies) }, | |
1104 | { "OnFailureIsolate", bus_property_append_bool, "b", offsetof(Unit, on_failure_isolate) }, | |
1105 | { "IgnoreOnIsolate", bus_property_append_bool, "b", offsetof(Unit, ignore_on_isolate) }, | |
1106 | { "IgnoreOnSnapshot", bus_property_append_bool, "b", offsetof(Unit, ignore_on_snapshot) }, | |
e2110e5d MS |
1107 | { "NeedDaemonReload", bus_unit_append_need_daemon_reload, "b", 0 }, |
1108 | { "JobTimeoutUSec", bus_property_append_usec, "t", offsetof(Unit, job_timeout) }, | |
1109 | { "ConditionTimestamp", bus_property_append_usec, "t", offsetof(Unit, condition_timestamp.realtime) }, | |
1110 | { "ConditionTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, condition_timestamp.monotonic) }, | |
1111 | { "ConditionResult", bus_property_append_bool, "b", offsetof(Unit, condition_result) }, | |
1112 | { "LoadError", bus_unit_append_load_error, "(ss)", 0 }, | |
1113 | { NULL, } | |
1114 | }; | |
246aa6dd LP |
1115 | |
1116 | const BusProperty bus_unit_cgroup_properties[] = { | |
1117 | { "DefaultControlGroup", bus_unit_append_default_cgroup, "s", 0 }, | |
1118 | { "ControlGroups", bus_unit_append_cgroups, "as", 0 }, | |
1119 | { "ControlGroupAttributes", bus_unit_append_cgroup_attrs, "a(sss)", 0 }, | |
1120 | { NULL, } | |
1121 | }; |