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