]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-unit.c
remove unused includes
[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 *bus,
395 sd_bus_message *message,
396 Unit *u,
397 JobType job_type,
398 bool reload_if_possible,
399 sd_bus_error *error) {
400
401 const char *smode;
402 JobMode mode;
403 int r;
404
405 assert(bus);
406 assert(message);
407 assert(u);
408 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
409
410 r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error);
411 if (r < 0)
412 return r;
413
414 r = sd_bus_message_read(message, "s", &smode);
415 if (r < 0)
416 return r;
417
418 mode = job_mode_from_string(smode);
419 if (mode < 0)
420 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
421
422 r = bus_verify_manage_units_async(u->manager, message, error);
423 if (r < 0)
424 return r;
425 if (r == 0)
426 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
427
428 return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
429 }
430
431 static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
432 return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
433 }
434
435 static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
436 return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
437 }
438
439 static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
440 return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
441 }
442
443 static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
444 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
445 }
446
447 static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
448 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
449 }
450
451 static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
452 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
453 }
454
455 static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
456 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
457 }
458
459 int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
460 Unit *u = userdata;
461 const char *swho;
462 int32_t signo;
463 KillWho who;
464 int r;
465
466 assert(bus);
467 assert(message);
468 assert(u);
469
470 r = mac_selinux_unit_access_check(u, message, "stop", error);
471 if (r < 0)
472 return r;
473
474 r = sd_bus_message_read(message, "si", &swho, &signo);
475 if (r < 0)
476 return r;
477
478 if (isempty(swho))
479 who = KILL_ALL;
480 else {
481 who = kill_who_from_string(swho);
482 if (who < 0)
483 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
484 }
485
486 if (signo <= 0 || signo >= _NSIG)
487 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
488
489 r = bus_verify_manage_units_async_for_kill(u->manager, message, error);
490 if (r < 0)
491 return r;
492 if (r == 0)
493 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
494
495 r = unit_kill(u, who, signo, error);
496 if (r < 0)
497 return r;
498
499 return sd_bus_reply_method_return(message, NULL);
500 }
501
502 int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
503 Unit *u = userdata;
504 int r;
505
506 assert(bus);
507 assert(message);
508 assert(u);
509
510 r = mac_selinux_unit_access_check(u, message, "reload", error);
511 if (r < 0)
512 return r;
513
514 r = bus_verify_manage_units_async(u->manager, message, error);
515 if (r < 0)
516 return r;
517 if (r == 0)
518 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
519
520 unit_reset_failed(u);
521
522 return sd_bus_reply_method_return(message, NULL);
523 }
524
525 int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
526 Unit *u = userdata;
527 int runtime, r;
528
529 assert(bus);
530 assert(message);
531 assert(u);
532
533 r = mac_selinux_unit_access_check(u, message, "start", error);
534 if (r < 0)
535 return r;
536
537 r = sd_bus_message_read(message, "b", &runtime);
538 if (r < 0)
539 return r;
540
541 r = bus_verify_manage_units_async(u->manager, message, error);
542 if (r < 0)
543 return r;
544 if (r == 0)
545 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
546
547 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
548 if (r < 0)
549 return r;
550
551 return sd_bus_reply_method_return(message, NULL);
552 }
553
554 const sd_bus_vtable bus_unit_vtable[] = {
555 SD_BUS_VTABLE_START(0),
556
557 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
558 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
559 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
560 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
561 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
562 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
563 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
564 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
565 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
566 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
567 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
568 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
569 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
570 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
571 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
572 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
573 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
574 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
575 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
576 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
577 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
578 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
579 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
580 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
581 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
582 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
583 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
584 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
585 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
586 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
587 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
588 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
589 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
590 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
591 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
592 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
593 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
594 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
595 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
596 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
597 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
598 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
599 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
600 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
601 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
602 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
603 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
604 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
605 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
606 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
607 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
608 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
609 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
610 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
611 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
612 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
613 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
614 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
615 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
616 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
617 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
618 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
619 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
620 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
621 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
622
623 SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
624 SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
625 SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
626 SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
627 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
628 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
629 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
630 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
631 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
632 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
633
634 SD_BUS_VTABLE_END
635 };
636
637 static int property_get_slice(
638 sd_bus *bus,
639 const char *path,
640 const char *interface,
641 const char *property,
642 sd_bus_message *reply,
643 void *userdata,
644 sd_bus_error *error) {
645
646 Unit *u = userdata;
647
648 assert(bus);
649 assert(reply);
650 assert(u);
651
652 return sd_bus_message_append(reply, "s", unit_slice_name(u));
653 }
654
655 static int property_get_current_memory(
656 sd_bus *bus,
657 const char *path,
658 const char *interface,
659 const char *property,
660 sd_bus_message *reply,
661 void *userdata,
662 sd_bus_error *error) {
663
664 Unit *u = userdata;
665 uint64_t sz = (uint64_t) -1;
666 int r;
667
668 assert(bus);
669 assert(reply);
670 assert(u);
671
672 if (u->cgroup_path &&
673 (u->cgroup_realized_mask & CGROUP_MEMORY)) {
674 _cleanup_free_ char *v = NULL;
675
676 r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
677 if (r < 0 && r != -ENOENT)
678 log_unit_warning_errno(u->id, r, "Couldn't read memory.usage_in_bytes attribute: %m");
679
680 if (v) {
681 r = safe_atou64(v, &sz);
682 if (r < 0)
683 log_unit_warning_errno(u->id, r, "Failed to parse memory.usage_in_bytes attribute: %m");
684 }
685 }
686
687 return sd_bus_message_append(reply, "t", sz);
688 }
689
690 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
691 SD_BUS_VTABLE_START(0),
692 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
693 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
694 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
695 SD_BUS_VTABLE_END
696 };
697
698 static int send_new_signal(sd_bus *bus, void *userdata) {
699 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
700 _cleanup_free_ char *p = NULL;
701 Unit *u = userdata;
702 int r;
703
704 assert(bus);
705 assert(u);
706
707 p = unit_dbus_path(u);
708 if (!u)
709 return -ENOMEM;
710
711 r = sd_bus_message_new_signal(
712 bus,
713 &m,
714 "/org/freedesktop/systemd1",
715 "org.freedesktop.systemd1.Manager",
716 "UnitNew");
717 if (r < 0)
718 return r;
719
720 r = sd_bus_message_append(m, "so", u->id, p);
721 if (r < 0)
722 return r;
723
724 return sd_bus_send(bus, m, NULL);
725 }
726
727 static int send_changed_signal(sd_bus *bus, void *userdata) {
728 _cleanup_free_ char *p = NULL;
729 Unit *u = userdata;
730 int r;
731
732 assert(bus);
733 assert(u);
734
735 p = unit_dbus_path(u);
736 if (!p)
737 return -ENOMEM;
738
739 /* Send a properties changed signal. First for the specific
740 * type, then for the generic unit. The clients may rely on
741 * this order to get atomic behavior if needed. */
742
743 r = sd_bus_emit_properties_changed_strv(
744 bus, p,
745 UNIT_VTABLE(u)->bus_interface,
746 NULL);
747 if (r < 0)
748 return r;
749
750 return sd_bus_emit_properties_changed_strv(
751 bus, p,
752 "org.freedesktop.systemd1.Unit",
753 NULL);
754 }
755
756 void bus_unit_send_change_signal(Unit *u) {
757 int r;
758 assert(u);
759
760 if (u->in_dbus_queue) {
761 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
762 u->in_dbus_queue = false;
763 }
764
765 if (!u->id)
766 return;
767
768 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
769 if (r < 0)
770 log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
771
772 u->sent_dbus_new_signal = true;
773 }
774
775 static int send_removed_signal(sd_bus *bus, void *userdata) {
776 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
777 _cleanup_free_ char *p = NULL;
778 Unit *u = userdata;
779 int r;
780
781 assert(bus);
782 assert(u);
783
784 p = unit_dbus_path(u);
785 if (!u)
786 return -ENOMEM;
787
788 r = sd_bus_message_new_signal(
789 bus,
790 &m,
791 "/org/freedesktop/systemd1",
792 "org.freedesktop.systemd1.Manager",
793 "UnitRemoved");
794 if (r < 0)
795 return r;
796
797 r = sd_bus_message_append(m, "so", u->id, p);
798 if (r < 0)
799 return r;
800
801 return sd_bus_send(bus, m, NULL);
802 }
803
804 void bus_unit_send_removed_signal(Unit *u) {
805 int r;
806 assert(u);
807
808 if (!u->sent_dbus_new_signal)
809 bus_unit_send_change_signal(u);
810
811 if (!u->id)
812 return;
813
814 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
815 if (r < 0)
816 log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
817 }
818
819 int bus_unit_queue_job(
820 sd_bus *bus,
821 sd_bus_message *message,
822 Unit *u,
823 JobType type,
824 JobMode mode,
825 bool reload_if_possible,
826 sd_bus_error *error) {
827
828 _cleanup_free_ char *path = NULL;
829 Job *j;
830 int r;
831
832 assert(bus);
833 assert(message);
834 assert(u);
835 assert(type >= 0 && type < _JOB_TYPE_MAX);
836 assert(mode >= 0 && mode < _JOB_MODE_MAX);
837
838 if (reload_if_possible && unit_can_reload(u)) {
839 if (type == JOB_RESTART)
840 type = JOB_RELOAD_OR_START;
841 else if (type == JOB_TRY_RESTART)
842 type = JOB_RELOAD;
843 }
844
845 r = mac_selinux_unit_access_check(
846 u, message,
847 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
848 type == JOB_STOP ? "stop" : "reload", error);
849 if (r < 0)
850 return r;
851
852 if (type == JOB_STOP &&
853 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
854 unit_active_state(u) == UNIT_INACTIVE)
855 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
856
857 if ((type == JOB_START && u->refuse_manual_start) ||
858 (type == JOB_STOP && u->refuse_manual_stop) ||
859 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
860 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
861
862 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
863 if (r < 0)
864 return r;
865
866 if (bus == u->manager->api_bus) {
867 if (!j->clients) {
868 r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
869 if (r < 0)
870 return r;
871 }
872
873 r = sd_bus_track_add_sender(j->clients, message);
874 if (r < 0)
875 return r;
876 }
877
878 path = job_dbus_path(j);
879 if (!path)
880 return -ENOMEM;
881
882 return sd_bus_reply_method_return(message, "o", path);
883 }
884
885 static int bus_unit_set_transient_property(
886 Unit *u,
887 const char *name,
888 sd_bus_message *message,
889 UnitSetPropertiesMode mode,
890 sd_bus_error *error) {
891
892 int r;
893
894 assert(u);
895 assert(name);
896 assert(message);
897
898 if (streq(name, "Description")) {
899 const char *d;
900
901 r = sd_bus_message_read(message, "s", &d);
902 if (r < 0)
903 return r;
904
905 if (mode != UNIT_CHECK) {
906 r = unit_set_description(u, d);
907 if (r < 0)
908 return r;
909
910 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
911 }
912
913 return 1;
914
915 } else if (streq(name, "DefaultDependencies")) {
916 int b;
917
918 r = sd_bus_message_read(message, "b", &b);
919 if (r < 0)
920 return r;
921
922 if (mode != UNIT_CHECK) {
923 u->default_dependencies = b;
924 unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
925 }
926
927 return 1;
928
929 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
930 const char *s;
931
932 r = sd_bus_message_read(message, "s", &s);
933 if (r < 0)
934 return r;
935
936 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
937 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
938
939 if (isempty(s)) {
940 if (mode != UNIT_CHECK) {
941 unit_ref_unset(&u->slice);
942 unit_remove_drop_in(u, mode, name);
943 }
944 } else {
945 Unit *slice;
946
947 r = manager_load_unit(u->manager, s, NULL, error, &slice);
948 if (r < 0)
949 return r;
950
951 if (slice->type != UNIT_SLICE)
952 return -EINVAL;
953
954 if (mode != UNIT_CHECK) {
955 unit_ref_set(&u->slice, slice);
956 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
957 }
958 }
959
960 return 1;
961 } else if (STR_IN_SET(name,
962 "Requires", "RequiresOverridable",
963 "Requisite", "RequisiteOverridable",
964 "Wants",
965 "BindsTo",
966 "Conflicts",
967 "Before", "After",
968 "OnFailure",
969 "PropagatesReloadTo", "ReloadPropagatedFrom",
970 "PartOf")) {
971
972 UnitDependency d;
973 const char *other;
974
975 d = unit_dependency_from_string(name);
976 if (d < 0)
977 return -EINVAL;
978
979 r = sd_bus_message_enter_container(message, 'a', "s");
980 if (r < 0)
981 return r;
982
983 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
984 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
985 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
986
987 if (mode != UNIT_CHECK) {
988 _cleanup_free_ char *label = NULL;
989
990 r = unit_add_dependency_by_name(u, d, other, NULL, true);
991 if (r < 0)
992 return r;
993
994 label = strjoin(name, "-", other, NULL);
995 if (!label)
996 return -ENOMEM;
997
998 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
999 }
1000
1001 }
1002 if (r < 0)
1003 return r;
1004
1005 r = sd_bus_message_exit_container(message);
1006 if (r < 0)
1007 return r;
1008
1009 return 1;
1010 }
1011
1012 return 0;
1013 }
1014
1015 int bus_unit_set_properties(
1016 Unit *u,
1017 sd_bus_message *message,
1018 UnitSetPropertiesMode mode,
1019 bool commit,
1020 sd_bus_error *error) {
1021
1022 bool for_real = false;
1023 unsigned n = 0;
1024 int r;
1025
1026 assert(u);
1027 assert(message);
1028
1029 /* We iterate through the array twice. First run we just check
1030 * if all passed data is valid, second run actually applies
1031 * it. This is to implement transaction-like behaviour without
1032 * actually providing full transactions. */
1033
1034 r = sd_bus_message_enter_container(message, 'a', "(sv)");
1035 if (r < 0)
1036 return r;
1037
1038 for (;;) {
1039 const char *name;
1040
1041 r = sd_bus_message_enter_container(message, 'r', "sv");
1042 if (r < 0)
1043 return r;
1044 if (r == 0) {
1045 if (for_real || mode == UNIT_CHECK)
1046 break;
1047
1048 /* Reached EOF. Let's try again, and this time for realz... */
1049 r = sd_bus_message_rewind(message, false);
1050 if (r < 0)
1051 return r;
1052
1053 for_real = true;
1054 continue;
1055 }
1056
1057 r = sd_bus_message_read(message, "s", &name);
1058 if (r < 0)
1059 return r;
1060
1061 if (!UNIT_VTABLE(u)->bus_set_property)
1062 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
1063
1064 r = sd_bus_message_enter_container(message, 'v', NULL);
1065 if (r < 0)
1066 return r;
1067
1068 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1069 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
1070 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1071 if (r < 0)
1072 return r;
1073 if (r == 0)
1074 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
1075
1076 r = sd_bus_message_exit_container(message);
1077 if (r < 0)
1078 return r;
1079
1080 r = sd_bus_message_exit_container(message);
1081 if (r < 0)
1082 return r;
1083
1084 n += for_real;
1085 }
1086
1087 r = sd_bus_message_exit_container(message);
1088 if (r < 0)
1089 return r;
1090
1091 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
1092 UNIT_VTABLE(u)->bus_commit_properties(u);
1093
1094 return n;
1095 }