]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-unit.c
1fec0e3b1fcb9cd26042b8677416733d74598d46
[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 "dbus-unit.h"
30 #include "dbus-manager.h"
31 #include "bus-errors.h"
32 #include "dbus-client-track.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, bus, 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, bus, 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, bus, message, "start", error);
480 if (r < 0)
481 return r;
482
483 r = sd_bus_message_enter_container(message, 'a', "(sv)");
484 if (r < 0)
485 return r;
486
487 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
488 if (r < 0)
489 return r;
490
491 r = sd_bus_message_exit_container(message);
492 if (r < 0)
493 return r;
494
495 return sd_bus_reply_method_return(message, NULL);
496 }
497
498 const 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),
525 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), 0),
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),
550 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), 0),
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 };
574
575 static 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,
581 void *userdata,
582 sd_bus_error *error) {
583
584 Unit *u = userdata;
585
586 assert(bus);
587 assert(reply);
588 assert(u);
589
590 return sd_bus_message_append(reply, "s", unit_slice_name(u));
591 }
592
593 const 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 };
599
600 static 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;
605
606 assert(bus);
607 assert(u);
608
609 p = unit_dbus_path(u);
610 if (!u)
611 return -ENOMEM;
612
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;
621
622 r = sd_bus_message_append(m, "so", u->id, p);
623 if (r < 0)
624 return r;
625
626 return sd_bus_send_to(bus, m, destination, NULL);
627 }
628
629 static 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;
633
634 assert(bus);
635 assert(u);
636
637 p = unit_dbus_path(u);
638 if (!u)
639 return -ENOMEM;
640
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. */
644
645 if (UNIT_VTABLE(u)->bus_changing_properties) {
646
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 }
654
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);
668 }
669
670 void bus_unit_send_change_signal(Unit *u) {
671 int r;
672 assert(u);
673
674 if (u->in_dbus_queue) {
675 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
676 u->in_dbus_queue = false;
677 }
678
679 if (!u->id)
680 return;
681
682 r = bus_manager_foreach_client(u->manager, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
683 if (r < 0)
684 log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
685
686 u->sent_dbus_new_signal = true;
687 }
688
689 static 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;
694
695 assert(bus);
696 assert(u);
697
698 p = unit_dbus_path(u);
699 if (!u)
700 return -ENOMEM;
701
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;
710
711 r = sd_bus_message_append(m, "so", u->id, p);
712 if (r < 0)
713 return r;
714
715 return sd_bus_send_to(bus, m, destination, NULL);
716 }
717
718 void bus_unit_send_removed_signal(Unit *u) {
719 int r;
720 assert(u);
721
722 if (!u->sent_dbus_new_signal)
723 bus_unit_send_change_signal(u);
724
725 if (!u->id)
726 return;
727
728 r = bus_manager_foreach_client(u->manager, send_removed_signal, u);
729 if (r < 0)
730 log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r));
731 }
732
733 int bus_unit_queue_job(
734 sd_bus *bus,
735 sd_bus_message *message,
736 Unit *u,
737 JobType type,
738 JobMode mode,
739 bool reload_if_possible,
740 sd_bus_error *error) {
741
742 _cleanup_free_ char *path = NULL;
743 Job *j;
744 int r;
745
746 assert(bus);
747 assert(message);
748 assert(u);
749 assert(type >= 0 && type < _JOB_TYPE_MAX);
750 assert(mode >= 0 && mode < _JOB_MODE_MAX);
751
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
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;
765
766 if (type == JOB_STOP &&
767 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
768 unit_active_state(u) == UNIT_INACTIVE)
769 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
770
771 if ((type == JOB_START && u->refuse_manual_start) ||
772 (type == JOB_STOP && u->refuse_manual_stop) ||
773 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
774 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
775
776 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
777 if (r < 0)
778 return r;
779
780 r = bus_client_track(&j->subscribed, bus, sd_bus_message_get_sender(message));
781 if (r < 0)
782 return r;
783
784 path = job_dbus_path(j);
785 if (!path)
786 return -ENOMEM;
787
788 return sd_bus_reply_method_return(message, "o", path);
789 }
790
791 static int bus_unit_set_transient_property(
792 Unit *u,
793 const char *name,
794 sd_bus_message *message,
795 UnitSetPropertiesMode mode,
796 sd_bus_error *error) {
797
798 int r;
799
800 assert(u);
801 assert(name);
802 assert(message);
803
804 if (streq(name, "Description")) {
805 const char *d;
806
807 r = sd_bus_message_read(message, "s", &d);
808 if (r < 0)
809 return r;
810
811 if (mode != UNIT_CHECK) {
812 r = unit_set_description(u, d);
813 if (r < 0)
814 return r;
815
816 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
817 }
818
819 return 1;
820
821 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
822 const char *s;
823
824 r = sd_bus_message_read(message, "s", &s);
825 if (r < 0)
826 return r;
827
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);
830
831 if (isempty(s)) {
832 if (mode != UNIT_CHECK) {
833 unit_ref_unset(&u->slice);
834 unit_remove_drop_in(u, mode, name);
835 }
836 } else {
837 Unit *slice;
838
839 r = manager_load_unit(u->manager, s, NULL, error, &slice);
840 if (r < 0)
841 return r;
842
843 if (slice->type != UNIT_SLICE)
844 return -EINVAL;
845
846 if (mode != UNIT_CHECK) {
847 unit_ref_set(&u->slice, slice);
848 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
849 }
850 }
851
852 return 1;
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;
869 const char *other;
870
871 d = unit_dependency_from_string(name);
872 if (d < 0)
873 return -EINVAL;
874
875 r = sd_bus_message_enter_container(message, 'a', "s");
876 if (r < 0)
877 return r;
878
879 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
880 if (!unit_name_is_valid(other, false))
881 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
882
883 if (mode != UNIT_CHECK) {
884 _cleanup_free_ char *label = NULL;
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
894 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
895 }
896
897 }
898 if (r < 0)
899 return r;
900
901 r = sd_bus_message_exit_container(message);
902 if (r < 0)
903 return r;
904
905 return 1;
906 }
907
908 return 0;
909 }
910
911 int bus_unit_set_properties(
912 Unit *u,
913 sd_bus_message *message,
914 UnitSetPropertiesMode mode,
915 bool commit,
916 sd_bus_error *error) {
917
918 bool for_real = false;
919 unsigned n = 0;
920 int r;
921
922 assert(u);
923 assert(message);
924
925 if (u->transient)
926 mode &= UNIT_RUNTIME;
927
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
933 r = sd_bus_message_enter_container(message, 'a', "(sv)");
934 if (r < 0)
935 return r;
936
937 for (;;) {
938 const char *name;
939
940 r = sd_bus_message_enter_container(message, 'r', "sv");
941 if (r < 0)
942 return r;
943 if (r == 0) {
944 if (for_real || mode == UNIT_CHECK)
945 break;
946
947 /* Reached EOF. Let's try again, and this time for realz... */
948 r = sd_bus_message_rewind(message, false);
949 if (r < 0)
950 return r;
951
952 for_real = true;
953 continue;
954 }
955
956 r = sd_bus_message_read(message, "s", &name);
957 if (r < 0)
958 return r;
959
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.");
962
963 r = sd_bus_message_enter_container(message, 'v', NULL);
964 if (r < 0)
965 return r;
966
967 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
968 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
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);
976 if (r < 0)
977 return r;
978
979 r = sd_bus_message_exit_container(message);
980 if (r < 0)
981 return r;
982
983 n += for_real;
984 }
985
986 r = sd_bus_message_exit_container(message);
987 if (r < 0)
988 return r;
989
990 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
991 UNIT_VTABLE(u)->bus_commit_properties(u);
992
993 return n;
994 }