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