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