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