]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-unit.c
condition: add more test cases
[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
718db961 22#include "sd-bus.h"
ea430986 23#include "log.h"
e2417e41 24#include "selinux-access.h"
246aa6dd
LP
25#include "cgroup-util.h"
26#include "strv.h"
27#include "path-util.h"
a5c32cff 28#include "fileio.h"
718db961 29#include "bus-errors.h"
8f8f05a9
LP
30#include "dbus.h"
31#include "dbus-manager.h"
32#include "dbus-unit.h"
718db961
LP
33
34static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
d420282b 35static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
f189ab18 36static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
718db961
LP
37
38static int property_get_names(
39 sd_bus *bus,
40 const char *path,
41 const char *interface,
42 const char *property,
43 sd_bus_message *reply,
ebcf1f97
LP
44 void *userdata,
45 sd_bus_error *error) {
718db961
LP
46
47 Unit *u = userdata;
48 Iterator i;
49 const char *t;
50 int r;
ea430986 51
718db961
LP
52 assert(bus);
53 assert(reply);
54 assert(u);
4139c1b2 55
718db961
LP
56 r = sd_bus_message_open_container(reply, 'a', "s");
57 if (r < 0)
58 return r;
4139c1b2 59
718db961
LP
60 SET_FOREACH(t, u->names, i) {
61 r = sd_bus_message_append(reply, "s", t);
62 if (r < 0)
63 return r;
64 }
4139c1b2 65
718db961 66 return sd_bus_message_close_container(reply);
4139c1b2
LP
67}
68
718db961
LP
69static int property_get_following(
70 sd_bus *bus,
71 const char *path,
72 const char *interface,
73 const char *property,
74 sd_bus_message *reply,
ebcf1f97
LP
75 void *userdata,
76 sd_bus_error *error) {
718db961
LP
77
78 Unit *u = userdata, *f;
8fe914ec 79
718db961
LP
80 assert(bus);
81 assert(reply);
8fe914ec
LP
82 assert(u);
83
a7f241db 84 f = unit_following(u);
718db961 85 return sd_bus_message_append(reply, "s", f ? f->id : "");
8fe914ec
LP
86}
87
718db961
LP
88static int property_get_dependencies(
89 sd_bus *bus,
90 const char *path,
91 const char *interface,
92 const char *property,
93 sd_bus_message *reply,
ebcf1f97
LP
94 void *userdata,
95 sd_bus_error *error) {
4ec9a8a4 96
718db961 97 Set *s = *(Set**) userdata;
5301be81 98 Iterator j;
718db961
LP
99 Unit *u;
100 int r;
5301be81 101
718db961
LP
102 assert(bus);
103 assert(reply);
5301be81 104
718db961
LP
105 r = sd_bus_message_open_container(reply, 'a', "s");
106 if (r < 0)
107 return r;
5301be81 108
718db961
LP
109 SET_FOREACH(u, s, j) {
110 r = sd_bus_message_append(reply, "s", u->id);
111 if (r < 0)
112 return r;
113 }
5301be81 114
718db961 115 return sd_bus_message_close_container(reply);
5301be81
LP
116}
117
718db961
LP
118static int property_get_description(
119 sd_bus *bus,
120 const char *path,
121 const char *interface,
122 const char *property,
123 sd_bus_message *reply,
ebcf1f97
LP
124 void *userdata,
125 sd_bus_error *error) {
ea430986 126
718db961 127 Unit *u = userdata;
ea430986 128
718db961
LP
129 assert(bus);
130 assert(reply);
131 assert(u);
ea430986 132
718db961 133 return sd_bus_message_append(reply, "s", unit_description(u));
ea430986
LP
134}
135
718db961
LP
136static int property_get_active_state(
137 sd_bus *bus,
138 const char *path,
139 const char *interface,
140 const char *property,
141 sd_bus_message *reply,
ebcf1f97
LP
142 void *userdata,
143 sd_bus_error *error) {
ea430986 144
718db961 145 Unit *u = userdata;
ea430986 146
718db961
LP
147 assert(bus);
148 assert(reply);
ea430986
LP
149 assert(u);
150
718db961 151 return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
ea430986
LP
152}
153
718db961
LP
154static int property_get_sub_state(
155 sd_bus *bus,
156 const char *path,
157 const char *interface,
158 const char *property,
159 sd_bus_message *reply,
ebcf1f97
LP
160 void *userdata,
161 sd_bus_error *error) {
10a94420 162
718db961 163 Unit *u = userdata;
10a94420 164
718db961
LP
165 assert(bus);
166 assert(reply);
167 assert(u);
10a94420 168
718db961 169 return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
10a94420
LP
170}
171
718db961
LP
172static int property_get_unit_file_state(
173 sd_bus *bus,
174 const char *path,
175 const char *interface,
176 const char *property,
177 sd_bus_message *reply,
ebcf1f97
LP
178 void *userdata,
179 sd_bus_error *error) {
a4375746 180
718db961 181 Unit *u = userdata;
a4375746 182
718db961
LP
183 assert(bus);
184 assert(reply);
185 assert(u);
a4375746 186
718db961 187 return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
a4375746
LP
188}
189
718db961
LP
190static int property_get_can_start(
191 sd_bus *bus,
192 const char *path,
193 const char *interface,
194 const char *property,
195 sd_bus_message *reply,
ebcf1f97
LP
196 void *userdata,
197 sd_bus_error *error) {
38131695 198
718db961 199 Unit *u = userdata;
b5e9dba8 200
718db961
LP
201 assert(bus);
202 assert(reply);
203 assert(u);
b5e9dba8 204
718db961 205 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
b5e9dba8
LP
206}
207
718db961
LP
208static int property_get_can_stop(
209 sd_bus *bus,
210 const char *path,
211 const char *interface,
212 const char *property,
213 sd_bus_message *reply,
ebcf1f97
LP
214 void *userdata,
215 sd_bus_error *error) {
718db961
LP
216
217 Unit *u = userdata;
b5e9dba8 218
718db961
LP
219 assert(bus);
220 assert(reply);
b5e9dba8
LP
221 assert(u);
222
223 /* On the lower levels we assume that every unit we can start
224 * we can also stop */
225
718db961 226 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
38131695
LP
227}
228
718db961
LP
229static int property_get_can_reload(
230 sd_bus *bus,
231 const char *path,
232 const char *interface,
233 const char *property,
234 sd_bus_message *reply,
ebcf1f97
LP
235 void *userdata,
236 sd_bus_error *error) {
38131695 237
718db961 238 Unit *u = userdata;
38131695 239
718db961
LP
240 assert(bus);
241 assert(reply);
242 assert(u);
38131695 243
718db961 244 return sd_bus_message_append(reply, "b", unit_can_reload(u));
38131695
LP
245}
246
718db961
LP
247static int property_get_can_isolate(
248 sd_bus *bus,
249 const char *path,
250 const char *interface,
251 const char *property,
252 sd_bus_message *reply,
ebcf1f97
LP
253 void *userdata,
254 sd_bus_error *error) {
2528a7a6 255
718db961 256 Unit *u = userdata;
2528a7a6 257
718db961
LP
258 assert(bus);
259 assert(reply);
260 assert(u);
2528a7a6 261
718db961 262 return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
2528a7a6
LP
263}
264
718db961
LP
265static int property_get_job(
266 sd_bus *bus,
267 const char *path,
268 const char *interface,
269 const char *property,
270 sd_bus_message *reply,
ebcf1f97
LP
271 void *userdata,
272 sd_bus_error *error) {
718db961 273
f93891f3 274 _cleanup_free_ char *p = NULL;
718db961 275 Unit *u = userdata;
38131695 276
718db961
LP
277 assert(bus);
278 assert(reply);
38131695
LP
279 assert(u);
280
718db961
LP
281 if (!u->job)
282 return sd_bus_message_append(reply, "(uo)", 0, "/");
38131695 283
718db961
LP
284 p = job_dbus_path(u->job);
285 if (!p)
286 return -ENOMEM;
38131695 287
718db961
LP
288 return sd_bus_message_append(reply, "(uo)", u->job->id, p);
289}
38131695 290
718db961
LP
291static int property_get_need_daemon_reload(
292 sd_bus *bus,
293 const char *path,
294 const char *interface,
295 const char *property,
296 sd_bus_message *reply,
ebcf1f97
LP
297 void *userdata,
298 sd_bus_error *error) {
38131695 299
718db961 300 Unit *u = userdata;
38131695 301
718db961
LP
302 assert(bus);
303 assert(reply);
304 assert(u);
38131695 305
718db961 306 return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
38131695
LP
307}
308
718db961
LP
309static int property_get_conditions(
310 sd_bus *bus,
311 const char *path,
312 const char *interface,
313 const char *property,
314 sd_bus_message *reply,
ebcf1f97
LP
315 void *userdata,
316 sd_bus_error *error) {
45fb0699 317
718db961
LP
318 Unit *u = userdata;
319 Condition *c;
320 int r;
45fb0699 321
718db961
LP
322 assert(bus);
323 assert(reply);
324 assert(u);
45fb0699 325
718db961
LP
326 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
327 if (r < 0)
328 return r;
45fb0699 329
718db961 330 LIST_FOREACH(conditions, c, u->conditions) {
2c7e050f
LP
331 r = sd_bus_message_append(reply, "(sbbsi)",
332 condition_type_to_string(c->type),
333 c->trigger, c->negate,
334 c->parameter, c->state);
718db961
LP
335 if (r < 0)
336 return r;
45fb0699 337
718db961 338 }
52990c2e 339
718db961 340 return sd_bus_message_close_container(reply);
52990c2e
ZJS
341}
342
718db961
LP
343static int property_get_load_error(
344 sd_bus *bus,
345 const char *path,
346 const char *interface,
347 const char *property,
348 sd_bus_message *reply,
ebcf1f97
LP
349 void *userdata,
350 sd_bus_error *error) {
52990c2e 351
718db961
LP
352 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
353 Unit *u = userdata;
52990c2e 354
718db961
LP
355 assert(bus);
356 assert(reply);
357 assert(u);
52990c2e 358
718db961
LP
359 if (u->load_error != 0)
360 sd_bus_error_set_errno(&e, u->load_error);
52990c2e 361
718db961 362 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
52990c2e
ZJS
363}
364
ebcf1f97 365int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
718db961
LP
366 const char *smode;
367 JobMode mode;
368 int r;
9f39404c 369
718db961
LP
370 assert(bus);
371 assert(message);
9f39404c 372 assert(u);
718db961 373 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
9f39404c 374
718db961
LP
375 r = sd_bus_message_read(message, "s", &smode);
376 if (r < 0)
ebcf1f97 377 return r;
9f39404c 378
718db961
LP
379 mode = job_mode_from_string(smode);
380 if (mode < 0)
ebcf1f97 381 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
9f39404c 382
ebcf1f97 383 return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
9f39404c
LP
384}
385
ebcf1f97
LP
386static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
387 return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
718db961 388}
b548631a 389
ebcf1f97
LP
390static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
391 return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
718db961
LP
392}
393
ebcf1f97
LP
394static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
395 return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
718db961 396}
0a524ba7 397
ebcf1f97
LP
398static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
399 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
718db961 400}
8a0867d6 401
ebcf1f97
LP
402static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
403 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
718db961 404}
cad45ba1 405
ebcf1f97
LP
406static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
407 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
718db961 408}
8a0867d6 409
ebcf1f97
LP
410static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
411 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
718db961 412}
8a0867d6 413
ebcf1f97 414int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
415 Unit *u = userdata;
416 const char *swho;
417 int32_t signo;
418 KillWho who;
419 int r;
5632e374 420
718db961
LP
421 assert(bus);
422 assert(message);
423 assert(u);
cad45ba1 424
283868e1
SW
425 r = bus_verify_manage_unit_async_for_kill(u->manager, message, error);
426 if (r < 0)
427 return r;
428 if (r == 0)
429 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
430
718db961
LP
431 r = sd_bus_message_read(message, "si", &swho, &signo);
432 if (r < 0)
ebcf1f97 433 return r;
718db961
LP
434
435 if (isempty(swho))
436 who = KILL_ALL;
437 else {
438 who = kill_who_from_string(swho);
439 if (who < 0)
ebcf1f97 440 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
718db961 441 }
5632e374 442
718db961 443 if (signo <= 0 || signo >= _NSIG)
ebcf1f97 444 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
8e2af478 445
8a188de9 446 r = mac_selinux_unit_access_check(u, message, "stop", error);
ebcf1f97
LP
447 if (r < 0)
448 return r;
8e2af478 449
ebcf1f97 450 r = unit_kill(u, who, signo, error);
718db961 451 if (r < 0)
ebcf1f97 452 return r;
8e2af478 453
df2d202e 454 return sd_bus_reply_method_return(message, NULL);
718db961 455}
8e2af478 456
ebcf1f97 457int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 458 Unit *u = userdata;
ebcf1f97 459 int r;
b548631a 460
718db961
LP
461 assert(bus);
462 assert(message);
463 assert(u);
b548631a 464
283868e1
SW
465 r = bus_verify_manage_unit_async(u->manager, message, error);
466 if (r < 0)
467 return r;
468 if (r == 0)
469 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
470
8a188de9 471 r = mac_selinux_unit_access_check(u, message, "reload", error);
ebcf1f97
LP
472 if (r < 0)
473 return r;
b548631a 474
718db961 475 unit_reset_failed(u);
b548631a 476
df2d202e 477 return sd_bus_reply_method_return(message, NULL);
ea430986
LP
478}
479
ebcf1f97 480int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
481 Unit *u = userdata;
482 int runtime, r;
ea430986 483
718db961 484 assert(bus);
ea430986 485 assert(message);
718db961 486 assert(u);
80fbf05e 487
283868e1
SW
488 r = bus_verify_manage_unit_async(u->manager, message, error);
489 if (r < 0)
490 return r;
491 if (r == 0)
492 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
493
718db961
LP
494 r = sd_bus_message_read(message, "b", &runtime);
495 if (r < 0)
ebcf1f97 496 return r;
2cccbca4 497
8a188de9 498 r = mac_selinux_unit_access_check(u, message, "start", error);
ebcf1f97
LP
499 if (r < 0)
500 return r;
cad45ba1 501
ebcf1f97 502 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
718db961 503 if (r < 0)
ebcf1f97 504 return r;
2cccbca4 505
df2d202e 506 return sd_bus_reply_method_return(message, NULL);
718db961 507}
2cccbca4 508
718db961
LP
509const sd_bus_vtable bus_unit_vtable[] = {
510 SD_BUS_VTABLE_START(0),
511
556089dc
LP
512 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
513 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
718db961 514 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
556089dc
LP
515 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
516 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
517 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
518 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
519 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
520 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
521 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
522 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
523 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
524 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
525 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
526 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
527 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
528 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
529 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
530 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
531 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
532 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
533 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
534 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
535 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
536 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
537 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
538 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
539 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
540 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
541 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
542 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
543 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
544 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
545 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
546 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
547 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
548 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
549 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
550 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
551 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
552 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
553 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
554 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
718db961 555 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
556 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
557 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
558 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
559 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
560 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
561 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
562 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
563 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
564 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
565 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
f189ab18
LP
566 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
567 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
568 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
569 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
570 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0),
556089dc
LP
571 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
572 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
573
574 SD_BUS_METHOD("Start", "s", "o", method_start, 0),
575 SD_BUS_METHOD("Stop", "s", "o", method_stop, 0),
576 SD_BUS_METHOD("Reload", "s", "o", method_reload, 0),
577 SD_BUS_METHOD("Restart", "s", "o", method_restart, 0),
578 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0),
579 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0),
580 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0),
581 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0),
582 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0),
583 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0),
584
585 SD_BUS_VTABLE_END
586};
2cccbca4 587
718db961
LP
588static int property_get_slice(
589 sd_bus *bus,
590 const char *path,
591 const char *interface,
592 const char *property,
593 sd_bus_message *reply,
ebcf1f97
LP
594 void *userdata,
595 sd_bus_error *error) {
2cccbca4 596
718db961 597 Unit *u = userdata;
2cccbca4 598
718db961
LP
599 assert(bus);
600 assert(reply);
601 assert(u);
2cccbca4 602
718db961
LP
603 return sd_bus_message_append(reply, "s", unit_slice_name(u));
604}
2cccbca4 605
718db961
LP
606const sd_bus_vtable bus_unit_cgroup_vtable[] = {
607 SD_BUS_VTABLE_START(0),
608 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
609 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
610 SD_BUS_VTABLE_END
611};
2cccbca4 612
8f8f05a9 613static int send_new_signal(sd_bus *bus, void *userdata) {
718db961
LP
614 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
615 _cleanup_free_ char *p = NULL;
616 Unit *u = userdata;
617 int r;
2cccbca4 618
718db961
LP
619 assert(bus);
620 assert(u);
2cccbca4 621
718db961
LP
622 p = unit_dbus_path(u);
623 if (!u)
624 return -ENOMEM;
2cccbca4 625
718db961
LP
626 r = sd_bus_message_new_signal(
627 bus,
151b9b96 628 &m,
718db961
LP
629 "/org/freedesktop/systemd1",
630 "org.freedesktop.systemd1.Manager",
151b9b96 631 "UnitNew");
718db961
LP
632 if (r < 0)
633 return r;
2cccbca4 634
718db961
LP
635 r = sd_bus_message_append(m, "so", u->id, p);
636 if (r < 0)
637 return r;
2cccbca4 638
8f8f05a9 639 return sd_bus_send(bus, m, NULL);
718db961 640}
2cccbca4 641
8f8f05a9 642static int send_changed_signal(sd_bus *bus, void *userdata) {
718db961
LP
643 _cleanup_free_ char *p = NULL;
644 Unit *u = userdata;
645 int r;
2cccbca4 646
718db961
LP
647 assert(bus);
648 assert(u);
2cccbca4 649
718db961 650 p = unit_dbus_path(u);
9ceefc81 651 if (!p)
718db961 652 return -ENOMEM;
2cccbca4 653
718db961
LP
654 /* Send a properties changed signal. First for the specific
655 * type, then for the generic unit. The clients may rely on
656 * this order to get atomic behavior if needed. */
ea430986 657
aec8de63
LP
658 r = sd_bus_emit_properties_changed_strv(
659 bus, p,
660 UNIT_VTABLE(u)->bus_interface,
661 NULL);
fe7f06f1 662 if (r < 0)
aec8de63 663 return r;
80fbf05e 664
fe7f06f1 665 return sd_bus_emit_properties_changed_strv(
718db961
LP
666 bus, p,
667 "org.freedesktop.systemd1.Unit",
718db961 668 NULL);
ea430986
LP
669}
670
c1e1601e 671void bus_unit_send_change_signal(Unit *u) {
b170dd80 672 int r;
c1e1601e 673 assert(u);
c1e1601e 674
ac155bb8 675 if (u->in_dbus_queue) {
71fda00f 676 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
ac155bb8 677 u->in_dbus_queue = false;
c0bd0cf7 678 }
c1e1601e 679
ac155bb8 680 if (!u->id)
04ade7d2
LP
681 return;
682
8f8f05a9 683 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
718db961 684 if (r < 0)
39abcaee 685 log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
c1e1601e 686
718db961
LP
687 u->sent_dbus_new_signal = true;
688}
c4e2ceae 689
8f8f05a9 690static int send_removed_signal(sd_bus *bus, void *userdata) {
718db961
LP
691 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
692 _cleanup_free_ char *p = NULL;
693 Unit *u = userdata;
694 int r;
c4e2ceae 695
718db961
LP
696 assert(bus);
697 assert(u);
c1e1601e 698
718db961
LP
699 p = unit_dbus_path(u);
700 if (!u)
701 return -ENOMEM;
c1e1601e 702
718db961
LP
703 r = sd_bus_message_new_signal(
704 bus,
151b9b96 705 &m,
718db961
LP
706 "/org/freedesktop/systemd1",
707 "org.freedesktop.systemd1.Manager",
151b9b96 708 "UnitRemoved");
718db961
LP
709 if (r < 0)
710 return r;
c1e1601e 711
718db961
LP
712 r = sd_bus_message_append(m, "so", u->id, p);
713 if (r < 0)
714 return r;
c1e1601e 715
8f8f05a9 716 return sd_bus_send(bus, m, NULL);
c1e1601e
LP
717}
718
719void bus_unit_send_removed_signal(Unit *u) {
718db961 720 int r;
c1e1601e
LP
721 assert(u);
722
ac155bb8 723 if (!u->sent_dbus_new_signal)
7535cc78
LP
724 bus_unit_send_change_signal(u);
725
ac155bb8 726 if (!u->id)
04ade7d2
LP
727 return;
728
8f8f05a9 729 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
718db961 730 if (r < 0)
39abcaee 731 log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r));
c1e1601e 732}
e2110e5d 733
718db961
LP
734int bus_unit_queue_job(
735 sd_bus *bus,
736 sd_bus_message *message,
cad45ba1
LP
737 Unit *u,
738 JobType type,
739 JobMode mode,
ebcf1f97
LP
740 bool reload_if_possible,
741 sd_bus_error *error) {
cad45ba1 742
cad45ba1
LP
743 _cleanup_free_ char *path = NULL;
744 Job *j;
cad45ba1
LP
745 int r;
746
718db961 747 assert(bus);
cad45ba1
LP
748 assert(message);
749 assert(u);
750 assert(type >= 0 && type < _JOB_TYPE_MAX);
751 assert(mode >= 0 && mode < _JOB_MODE_MAX);
752
cad45ba1
LP
753 if (reload_if_possible && unit_can_reload(u)) {
754 if (type == JOB_RESTART)
755 type = JOB_RELOAD_OR_START;
756 else if (type == JOB_TRY_RESTART)
757 type = JOB_RELOAD;
758 }
759
8a188de9 760 r = mac_selinux_unit_access_check(
4f4f7036 761 u, message,
ebcf1f97
LP
762 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
763 type == JOB_STOP ? "stop" : "reload", error);
764 if (r < 0)
765 return r;
cad45ba1 766
718db961
LP
767 if (type == JOB_STOP &&
768 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
769 unit_active_state(u) == UNIT_INACTIVE)
ebcf1f97 770 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
cad45ba1
LP
771
772 if ((type == JOB_START && u->refuse_manual_start) ||
773 (type == JOB_STOP && u->refuse_manual_stop) ||
718db961 774 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
ebcf1f97 775 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
cad45ba1 776
ebcf1f97 777 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
cad45ba1 778 if (r < 0)
ebcf1f97 779 return r;
cad45ba1 780
8f8f05a9 781 if (bus == u->manager->api_bus) {
b39a2770
SW
782 if (!j->clients) {
783 r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
8f8f05a9
LP
784 if (r < 0)
785 return r;
786 }
787
b39a2770 788 r = sd_bus_track_add_sender(j->clients, message);
8f8f05a9
LP
789 if (r < 0)
790 return r;
791 }
cad45ba1
LP
792
793 path = job_dbus_path(j);
794 if (!path)
6ce270b1 795 return -ENOMEM;
cad45ba1 796
df2d202e 797 return sd_bus_reply_method_return(message, "o", path);
cad45ba1
LP
798}
799
9f2e86af
LP
800static int bus_unit_set_transient_property(
801 Unit *u,
802 const char *name,
718db961 803 sd_bus_message *message,
9f2e86af 804 UnitSetPropertiesMode mode,
718db961 805 sd_bus_error *error) {
9f2e86af
LP
806
807 int r;
808
809 assert(u);
810 assert(name);
718db961 811 assert(message);
9f2e86af
LP
812
813 if (streq(name, "Description")) {
718db961 814 const char *d;
9f2e86af 815
718db961
LP
816 r = sd_bus_message_read(message, "s", &d);
817 if (r < 0)
818 return r;
8aec412f 819
718db961
LP
820 if (mode != UNIT_CHECK) {
821 r = unit_set_description(u, d);
8aec412f
LP
822 if (r < 0)
823 return r;
b9316fb0 824
718db961 825 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
8aec412f 826 }
9f2e86af
LP
827
828 return 1;
c221420b
LP
829
830 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
831 const char *s;
c221420b 832
718db961
LP
833 r = sd_bus_message_read(message, "s", &s);
834 if (r < 0)
835 return r;
c221420b 836
f78e6385 837 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
718db961 838 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
c221420b 839
8aec412f 840 if (isempty(s)) {
b9ec9359 841 if (mode != UNIT_CHECK) {
8aec412f 842 unit_ref_unset(&u->slice);
b9ec9359
LP
843 unit_remove_drop_in(u, mode, name);
844 }
8aec412f 845 } else {
b9ec9359 846 Unit *slice;
b9316fb0 847
8aec412f
LP
848 r = manager_load_unit(u->manager, s, NULL, error, &slice);
849 if (r < 0)
850 return r;
c221420b 851
8aec412f
LP
852 if (slice->type != UNIT_SLICE)
853 return -EINVAL;
c221420b 854
b9ec9359 855 if (mode != UNIT_CHECK) {
8aec412f 856 unit_ref_set(&u->slice, slice);
b9ec9359
LP
857 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
858 }
8aec412f 859 }
b9ec9359 860
c221420b 861 return 1;
311f6cf3
WC
862 } else if (STR_IN_SET(name,
863 "Requires", "RequiresOverridable",
864 "Requisite", "RequisiteOverridable",
865 "Wants",
866 "BindsTo",
867 "Conflicts",
868 "Before", "After",
869 "OnFailure",
870 "PropagatesReloadTo", "ReloadPropagatedFrom",
871 "PartOf")) {
7fb3ee51
LP
872
873 UnitDependency d;
718db961 874 const char *other;
7fb3ee51
LP
875
876 d = unit_dependency_from_string(name);
877 if (d < 0)
878 return -EINVAL;
879
718db961
LP
880 r = sd_bus_message_enter_container(message, 'a', "s");
881 if (r < 0)
882 return r;
7fb3ee51 883
718db961 884 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
f78e6385 885 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
718db961 886 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
7fb3ee51
LP
887
888 if (mode != UNIT_CHECK) {
b9ec9359 889 _cleanup_free_ char *label = NULL;
7fb3ee51
LP
890
891 r = unit_add_dependency_by_name(u, d, other, NULL, true);
892 if (r < 0)
893 return r;
894
895 label = strjoin(name, "-", other, NULL);
896 if (!label)
897 return -ENOMEM;
898
b9ec9359 899 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
7fb3ee51
LP
900 }
901
7fb3ee51 902 }
718db961
LP
903 if (r < 0)
904 return r;
7fb3ee51 905
6ce270b1
LP
906 r = sd_bus_message_exit_container(message);
907 if (r < 0)
908 return r;
909
7fb3ee51 910 return 1;
9f2e86af
LP
911 }
912
913 return 0;
914}
915
c2756a68
LP
916int bus_unit_set_properties(
917 Unit *u,
718db961 918 sd_bus_message *message,
c2756a68
LP
919 UnitSetPropertiesMode mode,
920 bool commit,
718db961 921 sd_bus_error *error) {
c2756a68 922
8e2af478 923 bool for_real = false;
8e2af478
LP
924 unsigned n = 0;
925 int r;
926
927 assert(u);
718db961 928 assert(message);
8e2af478
LP
929
930 /* We iterate through the array twice. First run we just check
931 * if all passed data is valid, second run actually applies
932 * it. This is to implement transaction-like behaviour without
933 * actually providing full transactions. */
934
718db961
LP
935 r = sd_bus_message_enter_container(message, 'a', "(sv)");
936 if (r < 0)
937 return r;
8e2af478 938
8e2af478 939 for (;;) {
8e2af478
LP
940 const char *name;
941
718db961
LP
942 r = sd_bus_message_enter_container(message, 'r', "sv");
943 if (r < 0)
944 return r;
945 if (r == 0) {
a255a7f1 946 if (for_real || mode == UNIT_CHECK)
8e2af478
LP
947 break;
948
949 /* Reached EOF. Let's try again, and this time for realz... */
718db961
LP
950 r = sd_bus_message_rewind(message, false);
951 if (r < 0)
952 return r;
6ce270b1 953
8e2af478
LP
954 for_real = true;
955 continue;
956 }
957
718db961
LP
958 r = sd_bus_message_read(message, "s", &name);
959 if (r < 0)
960 return r;
8e2af478 961
718db961
LP
962 if (!UNIT_VTABLE(u)->bus_set_property)
963 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
8e2af478 964
718db961
LP
965 r = sd_bus_message_enter_container(message, 'v', NULL);
966 if (r < 0)
967 return r;
8e2af478 968
718db961 969 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
9f2e86af 970 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
718db961
LP
971 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
972 if (r < 0)
973 return r;
974 if (r == 0)
975 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
976
977 r = sd_bus_message_exit_container(message);
8e2af478
LP
978 if (r < 0)
979 return r;
8e2af478 980
718db961
LP
981 r = sd_bus_message_exit_container(message);
982 if (r < 0)
983 return r;
8e2af478
LP
984
985 n += for_real;
986 }
987
6ce270b1
LP
988 r = sd_bus_message_exit_container(message);
989 if (r < 0)
990 return r;
991
c2756a68 992 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
8e2af478
LP
993 UNIT_VTABLE(u)->bus_commit_properties(u);
994
241da328 995 return n;
8e2af478 996}