]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-unit.c
sd-bus: drop bus parameter from message callback prototype
[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),
564 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
565 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
566 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
567 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
568 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
569 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
570 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
571 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
572 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
573 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
574 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
575 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
576 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
577 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
578 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
579 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
580 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
581 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
582 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
583 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
584 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
585 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
718db961 586 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
d2dc52db 587 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
718db961
LP
588 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
589 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
590 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
591 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
592 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
593 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
594 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
595 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
718db961 596 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
597 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
598 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
599 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
600 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
601 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
602 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
603 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
604 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
605 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
606 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
f189ab18
LP
607 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
608 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
718db961 609 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
59fccdc5 610 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
718db961 611 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
59fccdc5
LP
612 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
613 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
614 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
556089dc
LP
615 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
616 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
718db961 617
1d22e906
LP
618 SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
619 SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
620 SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
621 SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
622 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
623 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
624 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
625 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
626 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
627 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
718db961
LP
628
629 SD_BUS_VTABLE_END
630};
2cccbca4 631
718db961
LP
632static int property_get_slice(
633 sd_bus *bus,
634 const char *path,
635 const char *interface,
636 const char *property,
637 sd_bus_message *reply,
ebcf1f97
LP
638 void *userdata,
639 sd_bus_error *error) {
2cccbca4 640
718db961 641 Unit *u = userdata;
2cccbca4 642
718db961
LP
643 assert(bus);
644 assert(reply);
645 assert(u);
2cccbca4 646
718db961
LP
647 return sd_bus_message_append(reply, "s", unit_slice_name(u));
648}
2cccbca4 649
934277fe
LP
650static int property_get_current_memory(
651 sd_bus *bus,
652 const char *path,
653 const char *interface,
654 const char *property,
655 sd_bus_message *reply,
656 void *userdata,
657 sd_bus_error *error) {
658
934277fe 659 uint64_t sz = (uint64_t) -1;
5ad096b3 660 Unit *u = userdata;
934277fe
LP
661 int r;
662
663 assert(bus);
664 assert(reply);
665 assert(u);
666
5ad096b3
LP
667 r = unit_get_memory_current(u, &sz);
668 if (r < 0 && r != -ENODATA)
669 log_unit_warning_errno(u->id, r, "Failed to get memory.usage_in_bytes attribute: %m");
934277fe 670
5ad096b3
LP
671 return sd_bus_message_append(reply, "t", sz);
672}
934277fe 673
5ad096b3
LP
674static int property_get_cpu_usage(
675 sd_bus *bus,
676 const char *path,
677 const char *interface,
678 const char *property,
679 sd_bus_message *reply,
680 void *userdata,
681 sd_bus_error *error) {
934277fe 682
5ad096b3
LP
683 nsec_t ns = (nsec_t) -1;
684 Unit *u = userdata;
685 int r;
686
687 assert(bus);
688 assert(reply);
689 assert(u);
690
691 r = unit_get_cpu_usage(u, &ns);
692 if (r < 0 && r != -ENODATA)
693 log_unit_warning_errno(u->id, r, "Failed to get cpuacct.usage attribute: %m");
694
695 return sd_bus_message_append(reply, "t", ns);
934277fe
LP
696}
697
718db961
LP
698const sd_bus_vtable bus_unit_cgroup_vtable[] = {
699 SD_BUS_VTABLE_START(0),
700 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
701 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
934277fe 702 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
5ad096b3 703 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
718db961
LP
704 SD_BUS_VTABLE_END
705};
2cccbca4 706
8f8f05a9 707static int send_new_signal(sd_bus *bus, void *userdata) {
718db961
LP
708 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
709 _cleanup_free_ char *p = NULL;
710 Unit *u = userdata;
711 int r;
2cccbca4 712
718db961
LP
713 assert(bus);
714 assert(u);
2cccbca4 715
718db961
LP
716 p = unit_dbus_path(u);
717 if (!u)
718 return -ENOMEM;
2cccbca4 719
718db961
LP
720 r = sd_bus_message_new_signal(
721 bus,
151b9b96 722 &m,
718db961
LP
723 "/org/freedesktop/systemd1",
724 "org.freedesktop.systemd1.Manager",
151b9b96 725 "UnitNew");
718db961
LP
726 if (r < 0)
727 return r;
2cccbca4 728
718db961
LP
729 r = sd_bus_message_append(m, "so", u->id, p);
730 if (r < 0)
731 return r;
2cccbca4 732
8f8f05a9 733 return sd_bus_send(bus, m, NULL);
718db961 734}
2cccbca4 735
8f8f05a9 736static int send_changed_signal(sd_bus *bus, void *userdata) {
718db961
LP
737 _cleanup_free_ char *p = NULL;
738 Unit *u = userdata;
739 int r;
2cccbca4 740
718db961
LP
741 assert(bus);
742 assert(u);
2cccbca4 743
718db961 744 p = unit_dbus_path(u);
9ceefc81 745 if (!p)
718db961 746 return -ENOMEM;
2cccbca4 747
718db961
LP
748 /* Send a properties changed signal. First for the specific
749 * type, then for the generic unit. The clients may rely on
750 * this order to get atomic behavior if needed. */
ea430986 751
aec8de63
LP
752 r = sd_bus_emit_properties_changed_strv(
753 bus, p,
754 UNIT_VTABLE(u)->bus_interface,
755 NULL);
fe7f06f1 756 if (r < 0)
aec8de63 757 return r;
80fbf05e 758
fe7f06f1 759 return sd_bus_emit_properties_changed_strv(
718db961
LP
760 bus, p,
761 "org.freedesktop.systemd1.Unit",
718db961 762 NULL);
ea430986
LP
763}
764
c1e1601e 765void bus_unit_send_change_signal(Unit *u) {
b170dd80 766 int r;
c1e1601e 767 assert(u);
c1e1601e 768
ac155bb8 769 if (u->in_dbus_queue) {
71fda00f 770 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
ac155bb8 771 u->in_dbus_queue = false;
c0bd0cf7 772 }
c1e1601e 773
ac155bb8 774 if (!u->id)
04ade7d2
LP
775 return;
776
8f8f05a9 777 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
718db961 778 if (r < 0)
da927ba9 779 log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
c1e1601e 780
718db961
LP
781 u->sent_dbus_new_signal = true;
782}
c4e2ceae 783
8f8f05a9 784static int send_removed_signal(sd_bus *bus, void *userdata) {
718db961
LP
785 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
786 _cleanup_free_ char *p = NULL;
787 Unit *u = userdata;
788 int r;
c4e2ceae 789
718db961
LP
790 assert(bus);
791 assert(u);
c1e1601e 792
718db961
LP
793 p = unit_dbus_path(u);
794 if (!u)
795 return -ENOMEM;
c1e1601e 796
718db961
LP
797 r = sd_bus_message_new_signal(
798 bus,
151b9b96 799 &m,
718db961
LP
800 "/org/freedesktop/systemd1",
801 "org.freedesktop.systemd1.Manager",
151b9b96 802 "UnitRemoved");
718db961
LP
803 if (r < 0)
804 return r;
c1e1601e 805
718db961
LP
806 r = sd_bus_message_append(m, "so", u->id, p);
807 if (r < 0)
808 return r;
c1e1601e 809
8f8f05a9 810 return sd_bus_send(bus, m, NULL);
c1e1601e
LP
811}
812
813void bus_unit_send_removed_signal(Unit *u) {
718db961 814 int r;
c1e1601e
LP
815 assert(u);
816
ac155bb8 817 if (!u->sent_dbus_new_signal)
7535cc78
LP
818 bus_unit_send_change_signal(u);
819
ac155bb8 820 if (!u->id)
04ade7d2
LP
821 return;
822
8f8f05a9 823 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
718db961 824 if (r < 0)
da927ba9 825 log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
c1e1601e 826}
e2110e5d 827
718db961 828int bus_unit_queue_job(
718db961 829 sd_bus_message *message,
cad45ba1
LP
830 Unit *u,
831 JobType type,
832 JobMode mode,
ebcf1f97
LP
833 bool reload_if_possible,
834 sd_bus_error *error) {
cad45ba1 835
cad45ba1
LP
836 _cleanup_free_ char *path = NULL;
837 Job *j;
cad45ba1
LP
838 int r;
839
cad45ba1
LP
840 assert(message);
841 assert(u);
842 assert(type >= 0 && type < _JOB_TYPE_MAX);
843 assert(mode >= 0 && mode < _JOB_MODE_MAX);
844
cad45ba1
LP
845 if (reload_if_possible && unit_can_reload(u)) {
846 if (type == JOB_RESTART)
847 type = JOB_RELOAD_OR_START;
848 else if (type == JOB_TRY_RESTART)
849 type = JOB_RELOAD;
850 }
851
8a188de9 852 r = mac_selinux_unit_access_check(
4f4f7036 853 u, message,
ebcf1f97
LP
854 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
855 type == JOB_STOP ? "stop" : "reload", error);
856 if (r < 0)
857 return r;
cad45ba1 858
718db961
LP
859 if (type == JOB_STOP &&
860 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
861 unit_active_state(u) == UNIT_INACTIVE)
ebcf1f97 862 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
cad45ba1
LP
863
864 if ((type == JOB_START && u->refuse_manual_start) ||
865 (type == JOB_STOP && u->refuse_manual_stop) ||
718db961 866 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
ebcf1f97 867 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
cad45ba1 868
ebcf1f97 869 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
cad45ba1 870 if (r < 0)
ebcf1f97 871 return r;
cad45ba1 872
19070062 873 if (sd_bus_message_get_bus(message) == u->manager->api_bus) {
b39a2770 874 if (!j->clients) {
19070062 875 r = sd_bus_track_new(sd_bus_message_get_bus(message), &j->clients, NULL, NULL);
8f8f05a9
LP
876 if (r < 0)
877 return r;
878 }
879
b39a2770 880 r = sd_bus_track_add_sender(j->clients, message);
8f8f05a9
LP
881 if (r < 0)
882 return r;
883 }
cad45ba1
LP
884
885 path = job_dbus_path(j);
886 if (!path)
6ce270b1 887 return -ENOMEM;
cad45ba1 888
df2d202e 889 return sd_bus_reply_method_return(message, "o", path);
cad45ba1
LP
890}
891
9f2e86af
LP
892static int bus_unit_set_transient_property(
893 Unit *u,
894 const char *name,
718db961 895 sd_bus_message *message,
9f2e86af 896 UnitSetPropertiesMode mode,
718db961 897 sd_bus_error *error) {
9f2e86af
LP
898
899 int r;
900
901 assert(u);
902 assert(name);
718db961 903 assert(message);
9f2e86af
LP
904
905 if (streq(name, "Description")) {
718db961 906 const char *d;
9f2e86af 907
718db961
LP
908 r = sd_bus_message_read(message, "s", &d);
909 if (r < 0)
910 return r;
8aec412f 911
718db961
LP
912 if (mode != UNIT_CHECK) {
913 r = unit_set_description(u, d);
8aec412f
LP
914 if (r < 0)
915 return r;
b9316fb0 916
718db961 917 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
8aec412f 918 }
9f2e86af
LP
919
920 return 1;
261420ba
LP
921
922 } else if (streq(name, "DefaultDependencies")) {
923 int b;
924
925 r = sd_bus_message_read(message, "b", &b);
926 if (r < 0)
927 return r;
928
929 if (mode != UNIT_CHECK) {
930 u->default_dependencies = b;
931 unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
932 }
933
934 return 1;
c221420b
LP
935
936 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
937 const char *s;
c221420b 938
718db961
LP
939 r = sd_bus_message_read(message, "s", &s);
940 if (r < 0)
941 return r;
c221420b 942
f78e6385 943 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
718db961 944 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
c221420b 945
8aec412f 946 if (isempty(s)) {
b9ec9359 947 if (mode != UNIT_CHECK) {
8aec412f 948 unit_ref_unset(&u->slice);
b9ec9359
LP
949 unit_remove_drop_in(u, mode, name);
950 }
8aec412f 951 } else {
b9ec9359 952 Unit *slice;
b9316fb0 953
8aec412f
LP
954 r = manager_load_unit(u->manager, s, NULL, error, &slice);
955 if (r < 0)
956 return r;
c221420b 957
8aec412f
LP
958 if (slice->type != UNIT_SLICE)
959 return -EINVAL;
c221420b 960
b9ec9359 961 if (mode != UNIT_CHECK) {
8aec412f 962 unit_ref_set(&u->slice, slice);
b9ec9359
LP
963 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
964 }
8aec412f 965 }
b9ec9359 966
c221420b 967 return 1;
311f6cf3
WC
968 } else if (STR_IN_SET(name,
969 "Requires", "RequiresOverridable",
970 "Requisite", "RequisiteOverridable",
971 "Wants",
972 "BindsTo",
973 "Conflicts",
974 "Before", "After",
975 "OnFailure",
976 "PropagatesReloadTo", "ReloadPropagatedFrom",
977 "PartOf")) {
7fb3ee51
LP
978
979 UnitDependency d;
718db961 980 const char *other;
7fb3ee51
LP
981
982 d = unit_dependency_from_string(name);
983 if (d < 0)
984 return -EINVAL;
985
718db961
LP
986 r = sd_bus_message_enter_container(message, 'a', "s");
987 if (r < 0)
988 return r;
7fb3ee51 989
718db961 990 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
f78e6385 991 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
718db961 992 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
7fb3ee51
LP
993
994 if (mode != UNIT_CHECK) {
b9ec9359 995 _cleanup_free_ char *label = NULL;
7fb3ee51
LP
996
997 r = unit_add_dependency_by_name(u, d, other, NULL, true);
998 if (r < 0)
999 return r;
1000
1001 label = strjoin(name, "-", other, NULL);
1002 if (!label)
1003 return -ENOMEM;
1004
b9ec9359 1005 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
7fb3ee51
LP
1006 }
1007
7fb3ee51 1008 }
718db961
LP
1009 if (r < 0)
1010 return r;
7fb3ee51 1011
6ce270b1
LP
1012 r = sd_bus_message_exit_container(message);
1013 if (r < 0)
1014 return r;
1015
7fb3ee51 1016 return 1;
9f2e86af
LP
1017 }
1018
1019 return 0;
1020}
1021
c2756a68
LP
1022int bus_unit_set_properties(
1023 Unit *u,
718db961 1024 sd_bus_message *message,
c2756a68
LP
1025 UnitSetPropertiesMode mode,
1026 bool commit,
718db961 1027 sd_bus_error *error) {
c2756a68 1028
8e2af478 1029 bool for_real = false;
8e2af478
LP
1030 unsigned n = 0;
1031 int r;
1032
1033 assert(u);
718db961 1034 assert(message);
8e2af478
LP
1035
1036 /* We iterate through the array twice. First run we just check
1037 * if all passed data is valid, second run actually applies
1038 * it. This is to implement transaction-like behaviour without
1039 * actually providing full transactions. */
1040
718db961
LP
1041 r = sd_bus_message_enter_container(message, 'a', "(sv)");
1042 if (r < 0)
1043 return r;
8e2af478 1044
8e2af478 1045 for (;;) {
8e2af478
LP
1046 const char *name;
1047
718db961
LP
1048 r = sd_bus_message_enter_container(message, 'r', "sv");
1049 if (r < 0)
1050 return r;
1051 if (r == 0) {
a255a7f1 1052 if (for_real || mode == UNIT_CHECK)
8e2af478
LP
1053 break;
1054
1055 /* Reached EOF. Let's try again, and this time for realz... */
718db961
LP
1056 r = sd_bus_message_rewind(message, false);
1057 if (r < 0)
1058 return r;
6ce270b1 1059
8e2af478
LP
1060 for_real = true;
1061 continue;
1062 }
1063
718db961
LP
1064 r = sd_bus_message_read(message, "s", &name);
1065 if (r < 0)
1066 return r;
8e2af478 1067
718db961
LP
1068 if (!UNIT_VTABLE(u)->bus_set_property)
1069 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
8e2af478 1070
718db961
LP
1071 r = sd_bus_message_enter_container(message, 'v', NULL);
1072 if (r < 0)
1073 return r;
8e2af478 1074
718db961 1075 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
9f2e86af 1076 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
718db961
LP
1077 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1078 if (r < 0)
1079 return r;
1080 if (r == 0)
1081 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
1082
1083 r = sd_bus_message_exit_container(message);
8e2af478
LP
1084 if (r < 0)
1085 return r;
8e2af478 1086
718db961
LP
1087 r = sd_bus_message_exit_container(message);
1088 if (r < 0)
1089 return r;
8e2af478
LP
1090
1091 n += for_real;
1092 }
1093
6ce270b1
LP
1094 r = sd_bus_message_exit_container(message);
1095 if (r < 0)
1096 return r;
1097
c2756a68 1098 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
8e2af478
LP
1099 UNIT_VTABLE(u)->bus_commit_properties(u);
1100
241da328 1101 return n;
8e2af478 1102}