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