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