]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-unit.c
build-sys: prefer using ln --relative -s where appropriate
[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);
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
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
df2d202e 487 return sd_bus_reply_method_return(message, NULL);
718db961 488}
2cccbca4 489
718db961
LP
490const sd_bus_vtable bus_unit_vtable[] = {
491 SD_BUS_VTABLE_START(0),
492
556089dc
LP
493 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
494 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
718db961 495 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
556089dc
LP
496 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
497 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
498 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
499 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
500 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
501 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
502 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
503 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
504 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
505 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
506 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
507 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
508 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
509 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
510 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
511 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
512 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
513 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
514 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
515 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
516 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
517 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
518 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
519 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
520 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
521 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
522 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
523 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
524 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
525 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
526 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
527 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
528 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
529 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
530 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
531 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
532 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
533 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
534 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
535 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
718db961 536 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
537 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
538 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
539 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
540 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
541 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
542 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
543 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
544 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
545 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
546 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
547 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
548 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
549 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0),
556089dc
LP
550 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
551 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
552
553 SD_BUS_METHOD("Start", "s", "o", method_start, 0),
554 SD_BUS_METHOD("Stop", "s", "o", method_stop, 0),
555 SD_BUS_METHOD("Reload", "s", "o", method_reload, 0),
556 SD_BUS_METHOD("Restart", "s", "o", method_restart, 0),
557 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0),
558 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0),
559 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0),
560 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0),
561 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0),
562 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0),
563
564 SD_BUS_VTABLE_END
565};
2cccbca4 566
718db961
LP
567static int property_get_slice(
568 sd_bus *bus,
569 const char *path,
570 const char *interface,
571 const char *property,
572 sd_bus_message *reply,
ebcf1f97
LP
573 void *userdata,
574 sd_bus_error *error) {
2cccbca4 575
718db961 576 Unit *u = userdata;
2cccbca4 577
718db961
LP
578 assert(bus);
579 assert(reply);
580 assert(u);
2cccbca4 581
718db961
LP
582 return sd_bus_message_append(reply, "s", unit_slice_name(u));
583}
2cccbca4 584
718db961
LP
585const sd_bus_vtable bus_unit_cgroup_vtable[] = {
586 SD_BUS_VTABLE_START(0),
587 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
588 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
589 SD_BUS_VTABLE_END
590};
2cccbca4 591
8f8f05a9 592static int send_new_signal(sd_bus *bus, void *userdata) {
718db961
LP
593 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
594 _cleanup_free_ char *p = NULL;
595 Unit *u = userdata;
596 int r;
2cccbca4 597
718db961
LP
598 assert(bus);
599 assert(u);
2cccbca4 600
718db961
LP
601 p = unit_dbus_path(u);
602 if (!u)
603 return -ENOMEM;
2cccbca4 604
718db961
LP
605 r = sd_bus_message_new_signal(
606 bus,
151b9b96 607 &m,
718db961
LP
608 "/org/freedesktop/systemd1",
609 "org.freedesktop.systemd1.Manager",
151b9b96 610 "UnitNew");
718db961
LP
611 if (r < 0)
612 return r;
2cccbca4 613
718db961
LP
614 r = sd_bus_message_append(m, "so", u->id, p);
615 if (r < 0)
616 return r;
2cccbca4 617
8f8f05a9 618 return sd_bus_send(bus, m, NULL);
718db961 619}
2cccbca4 620
8f8f05a9 621static int send_changed_signal(sd_bus *bus, void *userdata) {
718db961
LP
622 _cleanup_free_ char *p = NULL;
623 Unit *u = userdata;
624 int r;
2cccbca4 625
718db961
LP
626 assert(bus);
627 assert(u);
2cccbca4 628
718db961 629 p = unit_dbus_path(u);
9ceefc81 630 if (!p)
718db961 631 return -ENOMEM;
2cccbca4 632
718db961
LP
633 /* Send a properties changed signal. First for the specific
634 * type, then for the generic unit. The clients may rely on
635 * this order to get atomic behavior if needed. */
ea430986 636
aec8de63
LP
637 r = sd_bus_emit_properties_changed_strv(
638 bus, p,
639 UNIT_VTABLE(u)->bus_interface,
640 NULL);
641 if (r < 0) {
642 log_warning("Failed to send out specific PropertiesChanged signal for %s: %s", u->id, strerror(-r));
643 return r;
718db961 644 }
80fbf05e 645
aec8de63 646 r = sd_bus_emit_properties_changed_strv(
718db961
LP
647 bus, p,
648 "org.freedesktop.systemd1.Unit",
718db961 649 NULL);
aec8de63
LP
650 if (r < 0) {
651 log_warning("Failed to send out generic PropertiesChanged signal for %s: %s", u->id, strerror(-r));
652 return r;
653 }
654
655 return 0;
ea430986
LP
656}
657
c1e1601e 658void bus_unit_send_change_signal(Unit *u) {
b170dd80 659 int r;
c1e1601e 660 assert(u);
c1e1601e 661
ac155bb8 662 if (u->in_dbus_queue) {
71fda00f 663 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
ac155bb8 664 u->in_dbus_queue = false;
c0bd0cf7 665 }
c1e1601e 666
ac155bb8 667 if (!u->id)
04ade7d2
LP
668 return;
669
8f8f05a9 670 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
718db961 671 if (r < 0)
39abcaee 672 log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
c1e1601e 673
718db961
LP
674 u->sent_dbus_new_signal = true;
675}
c4e2ceae 676
8f8f05a9 677static int send_removed_signal(sd_bus *bus, void *userdata) {
718db961
LP
678 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
679 _cleanup_free_ char *p = NULL;
680 Unit *u = userdata;
681 int r;
c4e2ceae 682
718db961
LP
683 assert(bus);
684 assert(u);
c1e1601e 685
718db961
LP
686 p = unit_dbus_path(u);
687 if (!u)
688 return -ENOMEM;
c1e1601e 689
718db961
LP
690 r = sd_bus_message_new_signal(
691 bus,
151b9b96 692 &m,
718db961
LP
693 "/org/freedesktop/systemd1",
694 "org.freedesktop.systemd1.Manager",
151b9b96 695 "UnitRemoved");
718db961
LP
696 if (r < 0)
697 return r;
c1e1601e 698
718db961
LP
699 r = sd_bus_message_append(m, "so", u->id, p);
700 if (r < 0)
701 return r;
c1e1601e 702
8f8f05a9 703 return sd_bus_send(bus, m, NULL);
c1e1601e
LP
704}
705
706void bus_unit_send_removed_signal(Unit *u) {
718db961 707 int r;
c1e1601e
LP
708 assert(u);
709
ac155bb8 710 if (!u->sent_dbus_new_signal)
7535cc78
LP
711 bus_unit_send_change_signal(u);
712
ac155bb8 713 if (!u->id)
04ade7d2
LP
714 return;
715
8f8f05a9 716 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
718db961 717 if (r < 0)
39abcaee 718 log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r));
c1e1601e 719}
e2110e5d 720
718db961
LP
721int bus_unit_queue_job(
722 sd_bus *bus,
723 sd_bus_message *message,
cad45ba1
LP
724 Unit *u,
725 JobType type,
726 JobMode mode,
ebcf1f97
LP
727 bool reload_if_possible,
728 sd_bus_error *error) {
cad45ba1 729
cad45ba1
LP
730 _cleanup_free_ char *path = NULL;
731 Job *j;
cad45ba1
LP
732 int r;
733
718db961 734 assert(bus);
cad45ba1
LP
735 assert(message);
736 assert(u);
737 assert(type >= 0 && type < _JOB_TYPE_MAX);
738 assert(mode >= 0 && mode < _JOB_MODE_MAX);
739
cad45ba1
LP
740 if (reload_if_possible && unit_can_reload(u)) {
741 if (type == JOB_RESTART)
742 type = JOB_RELOAD_OR_START;
743 else if (type == JOB_TRY_RESTART)
744 type = JOB_RELOAD;
745 }
746
ebcf1f97
LP
747 r = selinux_unit_access_check(
748 u, bus, message,
749 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
750 type == JOB_STOP ? "stop" : "reload", error);
751 if (r < 0)
752 return r;
cad45ba1 753
718db961
LP
754 if (type == JOB_STOP &&
755 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
756 unit_active_state(u) == UNIT_INACTIVE)
ebcf1f97 757 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
cad45ba1
LP
758
759 if ((type == JOB_START && u->refuse_manual_start) ||
760 (type == JOB_STOP && u->refuse_manual_stop) ||
718db961 761 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
ebcf1f97 762 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
cad45ba1 763
ebcf1f97 764 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
cad45ba1 765 if (r < 0)
ebcf1f97 766 return r;
cad45ba1 767
8f8f05a9
LP
768 if (bus == u->manager->api_bus) {
769 if (!j->subscribed) {
770 r = sd_bus_track_new(bus, &j->subscribed, NULL, NULL);
771 if (r < 0)
772 return r;
773 }
774
775 r = sd_bus_track_add_sender(j->subscribed, message);
776 if (r < 0)
777 return r;
778 }
cad45ba1
LP
779
780 path = job_dbus_path(j);
781 if (!path)
6ce270b1 782 return -ENOMEM;
cad45ba1 783
df2d202e 784 return sd_bus_reply_method_return(message, "o", path);
cad45ba1
LP
785}
786
9f2e86af
LP
787static int bus_unit_set_transient_property(
788 Unit *u,
789 const char *name,
718db961 790 sd_bus_message *message,
9f2e86af 791 UnitSetPropertiesMode mode,
718db961 792 sd_bus_error *error) {
9f2e86af
LP
793
794 int r;
795
796 assert(u);
797 assert(name);
718db961 798 assert(message);
9f2e86af
LP
799
800 if (streq(name, "Description")) {
718db961 801 const char *d;
9f2e86af 802
718db961
LP
803 r = sd_bus_message_read(message, "s", &d);
804 if (r < 0)
805 return r;
8aec412f 806
718db961
LP
807 if (mode != UNIT_CHECK) {
808 r = unit_set_description(u, d);
8aec412f
LP
809 if (r < 0)
810 return r;
b9316fb0 811
718db961 812 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
8aec412f 813 }
9f2e86af
LP
814
815 return 1;
c221420b
LP
816
817 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
818 const char *s;
c221420b 819
718db961
LP
820 r = sd_bus_message_read(message, "s", &s);
821 if (r < 0)
822 return r;
c221420b 823
f78e6385 824 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
718db961 825 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
c221420b 826
8aec412f 827 if (isempty(s)) {
b9ec9359 828 if (mode != UNIT_CHECK) {
8aec412f 829 unit_ref_unset(&u->slice);
b9ec9359
LP
830 unit_remove_drop_in(u, mode, name);
831 }
8aec412f 832 } else {
b9ec9359 833 Unit *slice;
b9316fb0 834
8aec412f
LP
835 r = manager_load_unit(u->manager, s, NULL, error, &slice);
836 if (r < 0)
837 return r;
c221420b 838
8aec412f
LP
839 if (slice->type != UNIT_SLICE)
840 return -EINVAL;
c221420b 841
b9ec9359 842 if (mode != UNIT_CHECK) {
8aec412f 843 unit_ref_set(&u->slice, slice);
b9ec9359
LP
844 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
845 }
8aec412f 846 }
b9ec9359 847
c221420b 848 return 1;
7fb3ee51
LP
849
850 } else if (streq(name, "Requires") ||
851 streq(name, "RequiresOverridable") ||
852 streq(name, "Requisite") ||
853 streq(name, "RequisiteOverridable") ||
854 streq(name, "Wants") ||
855 streq(name, "BindsTo") ||
856 streq(name, "Conflicts") ||
857 streq(name, "Before") ||
858 streq(name, "After") ||
859 streq(name, "OnFailure") ||
860 streq(name, "PropagatesReloadTo") ||
861 streq(name, "ReloadPropagatedFrom") ||
862 streq(name, "PartOf")) {
863
864 UnitDependency d;
718db961 865 const char *other;
7fb3ee51
LP
866
867 d = unit_dependency_from_string(name);
868 if (d < 0)
869 return -EINVAL;
870
718db961
LP
871 r = sd_bus_message_enter_container(message, 'a', "s");
872 if (r < 0)
873 return r;
7fb3ee51 874
718db961 875 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
f78e6385 876 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
718db961 877 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
7fb3ee51
LP
878
879 if (mode != UNIT_CHECK) {
b9ec9359 880 _cleanup_free_ char *label = NULL;
7fb3ee51
LP
881
882 r = unit_add_dependency_by_name(u, d, other, NULL, true);
883 if (r < 0)
884 return r;
885
886 label = strjoin(name, "-", other, NULL);
887 if (!label)
888 return -ENOMEM;
889
b9ec9359 890 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
7fb3ee51
LP
891 }
892
7fb3ee51 893 }
718db961
LP
894 if (r < 0)
895 return r;
7fb3ee51 896
6ce270b1
LP
897 r = sd_bus_message_exit_container(message);
898 if (r < 0)
899 return r;
900
7fb3ee51 901 return 1;
9f2e86af
LP
902 }
903
904 return 0;
905}
906
c2756a68
LP
907int bus_unit_set_properties(
908 Unit *u,
718db961 909 sd_bus_message *message,
c2756a68
LP
910 UnitSetPropertiesMode mode,
911 bool commit,
718db961 912 sd_bus_error *error) {
c2756a68 913
8e2af478 914 bool for_real = false;
8e2af478
LP
915 unsigned n = 0;
916 int r;
917
918 assert(u);
718db961 919 assert(message);
8e2af478
LP
920
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;
6ce270b1 944
8e2af478
LP
945 for_real = true;
946 continue;
947 }
948
718db961
LP
949 r = sd_bus_message_read(message, "s", &name);
950 if (r < 0)
951 return r;
8e2af478 952
718db961
LP
953 if (!UNIT_VTABLE(u)->bus_set_property)
954 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
8e2af478 955
718db961
LP
956 r = sd_bus_message_enter_container(message, 'v', NULL);
957 if (r < 0)
958 return r;
8e2af478 959
718db961 960 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
9f2e86af 961 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
718db961
LP
962 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
963 if (r < 0)
964 return r;
965 if (r == 0)
966 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
967
968 r = sd_bus_message_exit_container(message);
8e2af478
LP
969 if (r < 0)
970 return r;
8e2af478 971
718db961
LP
972 r = sd_bus_message_exit_container(message);
973 if (r < 0)
974 return r;
8e2af478
LP
975
976 n += for_real;
977 }
978
6ce270b1
LP
979 r = sd_bus_message_exit_container(message);
980 if (r < 0)
981 return r;
982
c2756a68 983 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
8e2af478
LP
984 UNIT_VTABLE(u)->bus_commit_properties(u);
985
241da328 986 return n;
8e2af478 987}