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