]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-unit.c
core: no need to pass bus object to selinux access check calls anymore
[thirdparty/systemd.git] / src / core / dbus-unit.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "sd-bus.h"
23 #include "log.h"
24 #include "selinux-access.h"
25 #include "cgroup-util.h"
26 #include "strv.h"
27 #include "path-util.h"
28 #include "fileio.h"
29 #include "bus-errors.h"
30 #include "dbus.h"
31 #include "dbus-manager.h"
32 #include "dbus-unit.h"
33
34 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
35 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
36
37 static 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,
43 void *userdata,
44 sd_bus_error *error) {
45
46 Unit *u = userdata;
47 Iterator i;
48 const char *t;
49 int r;
50
51 assert(bus);
52 assert(reply);
53 assert(u);
54
55 r = sd_bus_message_open_container(reply, 'a', "s");
56 if (r < 0)
57 return r;
58
59 SET_FOREACH(t, u->names, i) {
60 r = sd_bus_message_append(reply, "s", t);
61 if (r < 0)
62 return r;
63 }
64
65 return sd_bus_message_close_container(reply);
66 }
67
68 static 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,
74 void *userdata,
75 sd_bus_error *error) {
76
77 Unit *u = userdata, *f;
78
79 assert(bus);
80 assert(reply);
81 assert(u);
82
83 f = unit_following(u);
84 return sd_bus_message_append(reply, "s", f ? f->id : "");
85 }
86
87 static 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,
93 void *userdata,
94 sd_bus_error *error) {
95
96 Set *s = *(Set**) userdata;
97 Iterator j;
98 Unit *u;
99 int r;
100
101 assert(bus);
102 assert(reply);
103
104 r = sd_bus_message_open_container(reply, 'a', "s");
105 if (r < 0)
106 return r;
107
108 SET_FOREACH(u, s, j) {
109 r = sd_bus_message_append(reply, "s", u->id);
110 if (r < 0)
111 return r;
112 }
113
114 return sd_bus_message_close_container(reply);
115 }
116
117 static 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,
123 void *userdata,
124 sd_bus_error *error) {
125
126 Unit *u = userdata;
127
128 assert(bus);
129 assert(reply);
130 assert(u);
131
132 return sd_bus_message_append(reply, "s", unit_description(u));
133 }
134
135 static 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,
141 void *userdata,
142 sd_bus_error *error) {
143
144 Unit *u = userdata;
145
146 assert(bus);
147 assert(reply);
148 assert(u);
149
150 return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
151 }
152
153 static 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,
159 void *userdata,
160 sd_bus_error *error) {
161
162 Unit *u = userdata;
163
164 assert(bus);
165 assert(reply);
166 assert(u);
167
168 return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
169 }
170
171 static 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,
177 void *userdata,
178 sd_bus_error *error) {
179
180 Unit *u = userdata;
181
182 assert(bus);
183 assert(reply);
184 assert(u);
185
186 return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
187 }
188
189 static 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,
195 void *userdata,
196 sd_bus_error *error) {
197
198 Unit *u = userdata;
199
200 assert(bus);
201 assert(reply);
202 assert(u);
203
204 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
205 }
206
207 static 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,
213 void *userdata,
214 sd_bus_error *error) {
215
216 Unit *u = userdata;
217
218 assert(bus);
219 assert(reply);
220 assert(u);
221
222 /* On the lower levels we assume that every unit we can start
223 * we can also stop */
224
225 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
226 }
227
228 static 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,
234 void *userdata,
235 sd_bus_error *error) {
236
237 Unit *u = userdata;
238
239 assert(bus);
240 assert(reply);
241 assert(u);
242
243 return sd_bus_message_append(reply, "b", unit_can_reload(u));
244 }
245
246 static 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,
252 void *userdata,
253 sd_bus_error *error) {
254
255 Unit *u = userdata;
256
257 assert(bus);
258 assert(reply);
259 assert(u);
260
261 return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
262 }
263
264 static 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,
270 void *userdata,
271 sd_bus_error *error) {
272
273 _cleanup_free_ char *p = NULL;
274 Unit *u = userdata;
275
276 assert(bus);
277 assert(reply);
278 assert(u);
279
280 if (!u->job)
281 return sd_bus_message_append(reply, "(uo)", 0, "/");
282
283 p = job_dbus_path(u->job);
284 if (!p)
285 return -ENOMEM;
286
287 return sd_bus_message_append(reply, "(uo)", u->job->id, p);
288 }
289
290 static 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,
296 void *userdata,
297 sd_bus_error *error) {
298
299 Unit *u = userdata;
300
301 assert(bus);
302 assert(reply);
303 assert(u);
304
305 return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
306 }
307
308 static 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,
314 void *userdata,
315 sd_bus_error *error) {
316
317 Unit *u = userdata;
318 Condition *c;
319 int r;
320
321 assert(bus);
322 assert(reply);
323 assert(u);
324
325 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
326 if (r < 0)
327 return r;
328
329 LIST_FOREACH(conditions, c, u->conditions) {
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);
334 if (r < 0)
335 return r;
336
337 }
338
339 return sd_bus_message_close_container(reply);
340 }
341
342 static 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,
348 void *userdata,
349 sd_bus_error *error) {
350
351 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
352 Unit *u = userdata;
353
354 assert(bus);
355 assert(reply);
356 assert(u);
357
358 if (u->load_error != 0)
359 sd_bus_error_set_errno(&e, u->load_error);
360
361 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
362 }
363
364 int 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) {
365 const char *smode;
366 JobMode mode;
367 int r;
368
369 assert(bus);
370 assert(message);
371 assert(u);
372 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
373
374 r = sd_bus_message_read(message, "s", &smode);
375 if (r < 0)
376 return r;
377
378 mode = job_mode_from_string(smode);
379 if (mode < 0)
380 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
381
382 return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
383 }
384
385 static 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);
387 }
388
389 static 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);
391 }
392
393 static 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);
395 }
396
397 static 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);
399 }
400
401 static 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);
403 }
404
405 static 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);
407 }
408
409 static 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);
411 }
412
413 int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
414 Unit *u = userdata;
415 const char *swho;
416 int32_t signo;
417 KillWho who;
418 int r;
419
420 assert(bus);
421 assert(message);
422 assert(u);
423
424 r = sd_bus_message_read(message, "si", &swho, &signo);
425 if (r < 0)
426 return r;
427
428 if (isempty(swho))
429 who = KILL_ALL;
430 else {
431 who = kill_who_from_string(swho);
432 if (who < 0)
433 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
434 }
435
436 if (signo <= 0 || signo >= _NSIG)
437 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
438
439 r = selinux_unit_access_check(u, message, "stop", error);
440 if (r < 0)
441 return r;
442
443 r = unit_kill(u, who, signo, error);
444 if (r < 0)
445 return r;
446
447 return sd_bus_reply_method_return(message, NULL);
448 }
449
450 int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
451 Unit *u = userdata;
452 int r;
453
454 assert(bus);
455 assert(message);
456 assert(u);
457
458 r = selinux_unit_access_check(u, message, "reload", error);
459 if (r < 0)
460 return r;
461
462 unit_reset_failed(u);
463
464 return sd_bus_reply_method_return(message, NULL);
465 }
466
467 int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
468 Unit *u = userdata;
469 int runtime, r;
470
471 assert(bus);
472 assert(message);
473 assert(u);
474
475 r = sd_bus_message_read(message, "b", &runtime);
476 if (r < 0)
477 return r;
478
479 r = selinux_unit_access_check(u, message, "start", error);
480 if (r < 0)
481 return r;
482
483 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
484 if (r < 0)
485 return r;
486
487 return sd_bus_reply_method_return(message, NULL);
488 }
489
490 const sd_bus_vtable bus_unit_vtable[] = {
491 SD_BUS_VTABLE_START(0),
492
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),
495 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
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),
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),
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),
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),
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),
536 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
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),
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),
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),
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 };
566
567 static 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,
573 void *userdata,
574 sd_bus_error *error) {
575
576 Unit *u = userdata;
577
578 assert(bus);
579 assert(reply);
580 assert(u);
581
582 return sd_bus_message_append(reply, "s", unit_slice_name(u));
583 }
584
585 const 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 };
591
592 static int send_new_signal(sd_bus *bus, void *userdata) {
593 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
594 _cleanup_free_ char *p = NULL;
595 Unit *u = userdata;
596 int r;
597
598 assert(bus);
599 assert(u);
600
601 p = unit_dbus_path(u);
602 if (!u)
603 return -ENOMEM;
604
605 r = sd_bus_message_new_signal(
606 bus,
607 &m,
608 "/org/freedesktop/systemd1",
609 "org.freedesktop.systemd1.Manager",
610 "UnitNew");
611 if (r < 0)
612 return r;
613
614 r = sd_bus_message_append(m, "so", u->id, p);
615 if (r < 0)
616 return r;
617
618 return sd_bus_send(bus, m, NULL);
619 }
620
621 static int send_changed_signal(sd_bus *bus, void *userdata) {
622 _cleanup_free_ char *p = NULL;
623 Unit *u = userdata;
624 int r;
625
626 assert(bus);
627 assert(u);
628
629 p = unit_dbus_path(u);
630 if (!p)
631 return -ENOMEM;
632
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. */
636
637 r = sd_bus_emit_properties_changed_strv(
638 bus, p,
639 UNIT_VTABLE(u)->bus_interface,
640 NULL);
641 if (r < 0)
642 return r;
643
644 return sd_bus_emit_properties_changed_strv(
645 bus, p,
646 "org.freedesktop.systemd1.Unit",
647 NULL);
648 }
649
650 void bus_unit_send_change_signal(Unit *u) {
651 int r;
652 assert(u);
653
654 if (u->in_dbus_queue) {
655 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
656 u->in_dbus_queue = false;
657 }
658
659 if (!u->id)
660 return;
661
662 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
663 if (r < 0)
664 log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
665
666 u->sent_dbus_new_signal = true;
667 }
668
669 static int send_removed_signal(sd_bus *bus, void *userdata) {
670 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
671 _cleanup_free_ char *p = NULL;
672 Unit *u = userdata;
673 int r;
674
675 assert(bus);
676 assert(u);
677
678 p = unit_dbus_path(u);
679 if (!u)
680 return -ENOMEM;
681
682 r = sd_bus_message_new_signal(
683 bus,
684 &m,
685 "/org/freedesktop/systemd1",
686 "org.freedesktop.systemd1.Manager",
687 "UnitRemoved");
688 if (r < 0)
689 return r;
690
691 r = sd_bus_message_append(m, "so", u->id, p);
692 if (r < 0)
693 return r;
694
695 return sd_bus_send(bus, m, NULL);
696 }
697
698 void bus_unit_send_removed_signal(Unit *u) {
699 int r;
700 assert(u);
701
702 if (!u->sent_dbus_new_signal)
703 bus_unit_send_change_signal(u);
704
705 if (!u->id)
706 return;
707
708 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
709 if (r < 0)
710 log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r));
711 }
712
713 int bus_unit_queue_job(
714 sd_bus *bus,
715 sd_bus_message *message,
716 Unit *u,
717 JobType type,
718 JobMode mode,
719 bool reload_if_possible,
720 sd_bus_error *error) {
721
722 _cleanup_free_ char *path = NULL;
723 Job *j;
724 int r;
725
726 assert(bus);
727 assert(message);
728 assert(u);
729 assert(type >= 0 && type < _JOB_TYPE_MAX);
730 assert(mode >= 0 && mode < _JOB_MODE_MAX);
731
732 if (reload_if_possible && unit_can_reload(u)) {
733 if (type == JOB_RESTART)
734 type = JOB_RELOAD_OR_START;
735 else if (type == JOB_TRY_RESTART)
736 type = JOB_RELOAD;
737 }
738
739 r = selinux_unit_access_check(
740 u, message,
741 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
742 type == JOB_STOP ? "stop" : "reload", error);
743 if (r < 0)
744 return r;
745
746 if (type == JOB_STOP &&
747 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
748 unit_active_state(u) == UNIT_INACTIVE)
749 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
750
751 if ((type == JOB_START && u->refuse_manual_start) ||
752 (type == JOB_STOP && u->refuse_manual_stop) ||
753 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
754 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
755
756 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
757 if (r < 0)
758 return r;
759
760 if (bus == u->manager->api_bus) {
761 if (!j->subscribed) {
762 r = sd_bus_track_new(bus, &j->subscribed, NULL, NULL);
763 if (r < 0)
764 return r;
765 }
766
767 r = sd_bus_track_add_sender(j->subscribed, message);
768 if (r < 0)
769 return r;
770 }
771
772 path = job_dbus_path(j);
773 if (!path)
774 return -ENOMEM;
775
776 return sd_bus_reply_method_return(message, "o", path);
777 }
778
779 static int bus_unit_set_transient_property(
780 Unit *u,
781 const char *name,
782 sd_bus_message *message,
783 UnitSetPropertiesMode mode,
784 sd_bus_error *error) {
785
786 int r;
787
788 assert(u);
789 assert(name);
790 assert(message);
791
792 if (streq(name, "Description")) {
793 const char *d;
794
795 r = sd_bus_message_read(message, "s", &d);
796 if (r < 0)
797 return r;
798
799 if (mode != UNIT_CHECK) {
800 r = unit_set_description(u, d);
801 if (r < 0)
802 return r;
803
804 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
805 }
806
807 return 1;
808
809 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
810 const char *s;
811
812 r = sd_bus_message_read(message, "s", &s);
813 if (r < 0)
814 return r;
815
816 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
817 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
818
819 if (isempty(s)) {
820 if (mode != UNIT_CHECK) {
821 unit_ref_unset(&u->slice);
822 unit_remove_drop_in(u, mode, name);
823 }
824 } else {
825 Unit *slice;
826
827 r = manager_load_unit(u->manager, s, NULL, error, &slice);
828 if (r < 0)
829 return r;
830
831 if (slice->type != UNIT_SLICE)
832 return -EINVAL;
833
834 if (mode != UNIT_CHECK) {
835 unit_ref_set(&u->slice, slice);
836 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
837 }
838 }
839
840 return 1;
841
842 } else if (streq(name, "Requires") ||
843 streq(name, "RequiresOverridable") ||
844 streq(name, "Requisite") ||
845 streq(name, "RequisiteOverridable") ||
846 streq(name, "Wants") ||
847 streq(name, "BindsTo") ||
848 streq(name, "Conflicts") ||
849 streq(name, "Before") ||
850 streq(name, "After") ||
851 streq(name, "OnFailure") ||
852 streq(name, "PropagatesReloadTo") ||
853 streq(name, "ReloadPropagatedFrom") ||
854 streq(name, "PartOf")) {
855
856 UnitDependency d;
857 const char *other;
858
859 d = unit_dependency_from_string(name);
860 if (d < 0)
861 return -EINVAL;
862
863 r = sd_bus_message_enter_container(message, 'a', "s");
864 if (r < 0)
865 return r;
866
867 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
868 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
869 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
870
871 if (mode != UNIT_CHECK) {
872 _cleanup_free_ char *label = NULL;
873
874 r = unit_add_dependency_by_name(u, d, other, NULL, true);
875 if (r < 0)
876 return r;
877
878 label = strjoin(name, "-", other, NULL);
879 if (!label)
880 return -ENOMEM;
881
882 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
883 }
884
885 }
886 if (r < 0)
887 return r;
888
889 r = sd_bus_message_exit_container(message);
890 if (r < 0)
891 return r;
892
893 return 1;
894 }
895
896 return 0;
897 }
898
899 int bus_unit_set_properties(
900 Unit *u,
901 sd_bus_message *message,
902 UnitSetPropertiesMode mode,
903 bool commit,
904 sd_bus_error *error) {
905
906 bool for_real = false;
907 unsigned n = 0;
908 int r;
909
910 assert(u);
911 assert(message);
912
913 /* We iterate through the array twice. First run we just check
914 * if all passed data is valid, second run actually applies
915 * it. This is to implement transaction-like behaviour without
916 * actually providing full transactions. */
917
918 r = sd_bus_message_enter_container(message, 'a', "(sv)");
919 if (r < 0)
920 return r;
921
922 for (;;) {
923 const char *name;
924
925 r = sd_bus_message_enter_container(message, 'r', "sv");
926 if (r < 0)
927 return r;
928 if (r == 0) {
929 if (for_real || mode == UNIT_CHECK)
930 break;
931
932 /* Reached EOF. Let's try again, and this time for realz... */
933 r = sd_bus_message_rewind(message, false);
934 if (r < 0)
935 return r;
936
937 for_real = true;
938 continue;
939 }
940
941 r = sd_bus_message_read(message, "s", &name);
942 if (r < 0)
943 return r;
944
945 if (!UNIT_VTABLE(u)->bus_set_property)
946 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
947
948 r = sd_bus_message_enter_container(message, 'v', NULL);
949 if (r < 0)
950 return r;
951
952 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
953 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
954 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
955 if (r < 0)
956 return r;
957 if (r == 0)
958 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
959
960 r = sd_bus_message_exit_container(message);
961 if (r < 0)
962 return r;
963
964 r = sd_bus_message_exit_container(message);
965 if (r < 0)
966 return r;
967
968 n += for_real;
969 }
970
971 r = sd_bus_message_exit_container(message);
972 if (r < 0)
973 return r;
974
975 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
976 UNIT_VTABLE(u)->bus_commit_properties(u);
977
978 return n;
979 }