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