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