]> git.proxmox.com Git - systemd.git/blame - src/core/dbus-unit.c
New upstream version 250.4
[systemd.git] / src / core / dbus-unit.c
CommitLineData
a032b68d 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
663996b3 2
60f067b4 3#include "sd-bus.h"
db2df898
MP
4
5#include "alloc-util.h"
f5e65279 6#include "bpf-firewall.h"
db2df898 7#include "bus-common-errors.h"
a10f5d05 8#include "bus-get-properties.h"
97e5042f 9#include "bus-polkit.h"
db2df898 10#include "cgroup-util.h"
1d42b86d 11#include "condition.h"
2897b343 12#include "dbus-job.h"
8b3d4ff0 13#include "dbus-manager.h"
db2df898 14#include "dbus-unit.h"
1d42b86d 15#include "dbus-util.h"
db2df898 16#include "dbus.h"
aa27b158 17#include "fd-util.h"
f2dec872 18#include "install.h"
db2df898 19#include "locale-util.h"
663996b3 20#include "log.h"
1d42b86d 21#include "path-util.h"
aa27b158 22#include "process-util.h"
663996b3 23#include "selinux-access.h"
aa27b158 24#include "signal-util.h"
d9dfd233 25#include "special.h"
f2dec872 26#include "string-table.h"
db2df898
MP
27#include "string-util.h"
28#include "strv.h"
29#include "user-util.h"
1d42b86d 30#include "web-util.h"
663996b3 31
b012e921
MB
32static bool unit_can_start_refuse_manual(Unit *u) {
33 return unit_can_start(u) && !u->refuse_manual_start;
34}
35
36static bool unit_can_stop_refuse_manual(Unit *u) {
37 return unit_can_stop(u) && !u->refuse_manual_stop;
38}
39
40static bool unit_can_isolate_refuse_manual(Unit *u) {
41 return unit_can_isolate(u) && !u->refuse_manual_start;
42}
43
52ad194e 44static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_collect_mode, collect_mode, CollectMode);
60f067b4
JS
45static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
46static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
b012e921
MB
47static BUS_DEFINE_PROPERTY_GET(property_get_description, "s", Unit, unit_description);
48static BUS_DEFINE_PROPERTY_GET2(property_get_active_state, "s", Unit, unit_active_state, unit_active_state_to_string);
a10f5d05 49static BUS_DEFINE_PROPERTY_GET2(property_get_freezer_state, "s", Unit, unit_freezer_state, freezer_state_to_string);
b012e921
MB
50static BUS_DEFINE_PROPERTY_GET(property_get_sub_state, "s", Unit, unit_sub_state_to_string);
51static BUS_DEFINE_PROPERTY_GET2(property_get_unit_file_state, "s", Unit, unit_get_unit_file_state, unit_file_state_to_string);
52static BUS_DEFINE_PROPERTY_GET(property_get_can_reload, "b", Unit, unit_can_reload);
53static BUS_DEFINE_PROPERTY_GET(property_get_can_start, "b", Unit, unit_can_start_refuse_manual);
54static BUS_DEFINE_PROPERTY_GET(property_get_can_stop, "b", Unit, unit_can_stop_refuse_manual);
55static BUS_DEFINE_PROPERTY_GET(property_get_can_isolate, "b", Unit, unit_can_isolate_refuse_manual);
a10f5d05 56static BUS_DEFINE_PROPERTY_GET(property_get_can_freeze, "b", Unit, unit_can_freeze);
b012e921
MB
57static BUS_DEFINE_PROPERTY_GET(property_get_need_daemon_reload, "b", Unit, unit_need_daemon_reload);
58static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_strv, "as", 0);
60f067b4 59
f2dec872
BR
60static int property_get_can_clean(
61 sd_bus *bus,
62 const char *path,
63 const char *interface,
64 const char *property,
65 sd_bus_message *reply,
66 void *userdata,
67 sd_bus_error *error) {
68
69 Unit *u = userdata;
70 ExecCleanMask mask;
71 int r;
72
73 assert(bus);
74 assert(reply);
75
76 r = unit_can_clean(u, &mask);
77 if (r < 0)
78 return r;
79
80 r = sd_bus_message_open_container(reply, 'a', "s");
81 if (r < 0)
82 return r;
83
84 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
85 if (!FLAGS_SET(mask, 1U << t))
86 continue;
87
88 r = sd_bus_message_append(reply, "s", exec_resource_type_to_string(t));
89 if (r < 0)
90 return r;
91 }
92
93 return sd_bus_message_close_container(reply);
94}
95
60f067b4
JS
96static int property_get_names(
97 sd_bus *bus,
98 const char *path,
99 const char *interface,
100 const char *property,
101 sd_bus_message *reply,
102 void *userdata,
103 sd_bus_error *error) {
104
a10f5d05 105 Unit *u = userdata;
60f067b4
JS
106 const char *t;
107 int r;
663996b3 108
60f067b4
JS
109 assert(bus);
110 assert(reply);
a10f5d05 111 assert(u);
663996b3 112
60f067b4
JS
113 r = sd_bus_message_open_container(reply, 'a', "s");
114 if (r < 0)
115 return r;
663996b3 116
a10f5d05
MB
117 r = sd_bus_message_append(reply, "s", u->id);
118 if (r < 0)
119 return r;
120
a032b68d 121 SET_FOREACH(t, u->aliases) {
60f067b4
JS
122 r = sd_bus_message_append(reply, "s", t);
123 if (r < 0)
124 return r;
125 }
663996b3 126
60f067b4 127 return sd_bus_message_close_container(reply);
663996b3
MS
128}
129
60f067b4
JS
130static int property_get_following(
131 sd_bus *bus,
132 const char *path,
133 const char *interface,
134 const char *property,
135 sd_bus_message *reply,
136 void *userdata,
137 sd_bus_error *error) {
138
139 Unit *u = userdata, *f;
663996b3 140
60f067b4
JS
141 assert(bus);
142 assert(reply);
663996b3
MS
143 assert(u);
144
145 f = unit_following(u);
b012e921 146 return sd_bus_message_append(reply, "s", f ? f->id : NULL);
663996b3
MS
147}
148
60f067b4
JS
149static int property_get_dependencies(
150 sd_bus *bus,
151 const char *path,
152 const char *interface,
153 const char *property,
154 sd_bus_message *reply,
155 void *userdata,
156 sd_bus_error *error) {
14228c0d 157
8b3d4ff0
MB
158 Unit *u = userdata, *other;
159 UnitDependency d;
160 Hashmap *deps;
52ad194e 161 void *v;
60f067b4 162 int r;
663996b3 163
60f067b4
JS
164 assert(bus);
165 assert(reply);
8b3d4ff0
MB
166 assert(u);
167
168 d = unit_dependency_from_string(property);
169 assert_se(d >= 0);
170
171 deps = unit_get_dependencies(u, d);
663996b3 172
60f067b4
JS
173 r = sd_bus_message_open_container(reply, 'a', "s");
174 if (r < 0)
175 return r;
663996b3 176
8b3d4ff0
MB
177 HASHMAP_FOREACH_KEY(v, other, deps) {
178 r = sd_bus_message_append(reply, "s", other->id);
60f067b4
JS
179 if (r < 0)
180 return r;
181 }
663996b3 182
60f067b4 183 return sd_bus_message_close_container(reply);
663996b3
MS
184}
185
52ad194e
MB
186static int property_get_requires_mounts_for(
187 sd_bus *bus,
188 const char *path,
189 const char *interface,
190 const char *property,
191 sd_bus_message *reply,
192 void *userdata,
193 sd_bus_error *error) {
194
b012e921 195 Hashmap **h = userdata;
52ad194e 196 const char *p;
52ad194e
MB
197 void *v;
198 int r;
199
200 assert(bus);
201 assert(reply);
b012e921 202 assert(h);
52ad194e
MB
203
204 r = sd_bus_message_open_container(reply, 'a', "s");
205 if (r < 0)
206 return r;
207
a032b68d 208 HASHMAP_FOREACH_KEY(v, p, *h) {
52ad194e
MB
209 r = sd_bus_message_append(reply, "s", p);
210 if (r < 0)
211 return r;
212 }
213
214 return sd_bus_message_close_container(reply);
215}
216
f47781d8
MP
217static int property_get_unit_file_preset(
218 sd_bus *bus,
219 const char *path,
220 const char *interface,
221 const char *property,
222 sd_bus_message *reply,
223 void *userdata,
224 sd_bus_error *error) {
225
226 Unit *u = userdata;
227 int r;
228
229 assert(bus);
230 assert(reply);
231 assert(u);
232
233 r = unit_get_unit_file_preset(u);
234
235 return sd_bus_message_append(reply, "s",
b012e921 236 r < 0 ? NULL:
f47781d8
MP
237 r > 0 ? "enabled" : "disabled");
238}
239
60f067b4
JS
240static int property_get_job(
241 sd_bus *bus,
242 const char *path,
243 const char *interface,
244 const char *property,
245 sd_bus_message *reply,
246 void *userdata,
247 sd_bus_error *error) {
248
663996b3 249 _cleanup_free_ char *p = NULL;
b012e921 250 Job **j = userdata;
663996b3 251
60f067b4
JS
252 assert(bus);
253 assert(reply);
b012e921 254 assert(j);
663996b3 255
b012e921 256 if (!*j)
60f067b4 257 return sd_bus_message_append(reply, "(uo)", 0, "/");
663996b3 258
b012e921 259 p = job_dbus_path(*j);
60f067b4 260 if (!p)
663996b3
MS
261 return -ENOMEM;
262
b012e921 263 return sd_bus_message_append(reply, "(uo)", (*j)->id, p);
663996b3
MS
264}
265
60f067b4
JS
266static int property_get_conditions(
267 sd_bus *bus,
268 const char *path,
269 const char *interface,
270 const char *property,
271 sd_bus_message *reply,
272 void *userdata,
273 sd_bus_error *error) {
663996b3 274
f47781d8
MP
275 const char *(*to_string)(ConditionType type) = NULL;
276 Condition **list = userdata, *c;
60f067b4 277 int r;
663996b3 278
60f067b4
JS
279 assert(bus);
280 assert(reply);
f47781d8
MP
281 assert(list);
282
283 to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string;
663996b3 284
60f067b4
JS
285 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
286 if (r < 0)
287 return r;
663996b3 288
f47781d8
MP
289 LIST_FOREACH(conditions, c, *list) {
290 int tristate;
291
292 tristate =
293 c->result == CONDITION_UNTESTED ? 0 :
294 c->result == CONDITION_SUCCEEDED ? 1 : -1;
295
60f067b4 296 r = sd_bus_message_append(reply, "(sbbsi)",
f47781d8 297 to_string(c->type),
60f067b4 298 c->trigger, c->negate,
f47781d8 299 c->parameter, tristate);
60f067b4
JS
300 if (r < 0)
301 return r;
14228c0d 302
60f067b4 303 }
663996b3 304
60f067b4 305 return sd_bus_message_close_container(reply);
663996b3
MS
306}
307
60f067b4
JS
308static int property_get_load_error(
309 sd_bus *bus,
310 const char *path,
311 const char *interface,
312 const char *property,
313 sd_bus_message *reply,
314 void *userdata,
315 sd_bus_error *error) {
663996b3 316
4c89c718 317 _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
60f067b4 318 Unit *u = userdata;
b012e921 319 int r;
663996b3 320
60f067b4
JS
321 assert(bus);
322 assert(reply);
323 assert(u);
663996b3 324
b012e921
MB
325 r = bus_unit_validate_load_state(u, &e);
326 if (r < 0)
327 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
663996b3 328
b012e921 329 return sd_bus_message_append(reply, "(ss)", NULL, NULL);
663996b3
MS
330}
331
3a6ce677
BR
332static int property_get_markers(
333 sd_bus *bus,
334 const char *path,
335 const char *interface,
336 const char *property,
337 sd_bus_message *reply,
338 void *userdata,
d9dfd233
MP
339 sd_bus_error *error) {
340
3a6ce677
BR
341 unsigned *markers = userdata;
342 int r;
d9dfd233 343
3a6ce677
BR
344 assert(bus);
345 assert(reply);
346 assert(markers);
d9dfd233 347
3a6ce677
BR
348 r = sd_bus_message_open_container(reply, 'a', "s");
349 if (r < 0)
350 return r;
351
352 /* Make sure out values fit in the bitfield. */
353 assert_cc(_UNIT_MARKER_MAX <= sizeof(((Unit){}).markers) * 8);
354
355 for (UnitMarker m = 0; m < _UNIT_MARKER_MAX; m++)
356 if (FLAGS_SET(*markers, 1u << m)) {
357 r = sd_bus_message_append(reply, "s", unit_marker_to_string(m));
358 if (r < 0)
359 return r;
360 }
361
362 return sd_bus_message_close_container(reply);
d9dfd233
MP
363}
364
bb4f798a
MB
365static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
366 [JOB_START] = N_("Authentication is required to start '$(unit)'."),
367 [JOB_STOP] = N_("Authentication is required to stop '$(unit)'."),
368 [JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."),
369 [JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."),
370 [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
371};
372
e3bff60a
MP
373int bus_unit_method_start_generic(
374 sd_bus_message *message,
375 Unit *u,
376 JobType job_type,
377 bool reload_if_possible,
378 sd_bus_error *error) {
379
ea0999c9 380 BusUnitQueueFlags job_flags = reload_if_possible ? BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE : 0;
bb4f798a 381 const char *smode, *verb;
60f067b4 382 JobMode mode;
663996b3
MS
383 int r;
384
60f067b4
JS
385 assert(message);
386 assert(u);
387 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
663996b3 388
4c89c718
MP
389 r = mac_selinux_unit_access_check(
390 u, message,
391 job_type_to_access_method(job_type),
392 error);
e3bff60a
MP
393 if (r < 0)
394 return r;
395
60f067b4
JS
396 r = sd_bus_message_read(message, "s", &smode);
397 if (r < 0)
398 return r;
663996b3 399
60f067b4
JS
400 mode = job_mode_from_string(smode);
401 if (mode < 0)
402 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
663996b3 403
d9dfd233 404 if (reload_if_possible)
bb4f798a 405 verb = strjoina("reload-or-", job_type_to_string(job_type));
d9dfd233 406 else
bb4f798a 407 verb = job_type_to_string(job_type);
d9dfd233 408
ea0999c9
MB
409 if (sd_bus_message_is_method_call(message, NULL, "StartUnitWithFlags")) {
410 uint64_t input_flags = 0;
411
412 r = sd_bus_message_read(message, "t", &input_flags);
413 if (r < 0)
414 return r;
415 /* Let clients know that this version doesn't support any flags at the moment. */
416 if (input_flags != 0)
417 return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS,
418 "Invalid 'flags' parameter '%" PRIu64 "'",
419 input_flags);
ea0999c9
MB
420 }
421
d9dfd233
MP
422 r = bus_verify_manage_units_async_full(
423 u,
424 verb,
425 CAP_SYS_ADMIN,
bb4f798a 426 polkit_message_for_job[job_type],
8a584da2 427 true,
d9dfd233
MP
428 message,
429 error);
e3bff60a
MP
430 if (r < 0)
431 return r;
432 if (r == 0)
433 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
434
ea0999c9 435 return bus_unit_queue_job(message, u, job_type, mode, job_flags, error);
60f067b4 436}
663996b3 437
ea0999c9 438static int bus_unit_method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
e3bff60a 439 return bus_unit_method_start_generic(message, userdata, JOB_START, false, error);
60f067b4 440}
663996b3 441
ea0999c9 442static int bus_unit_method_stop(sd_bus_message *message, void *userdata, sd_bus_error *error) {
e3bff60a 443 return bus_unit_method_start_generic(message, userdata, JOB_STOP, false, error);
60f067b4 444}
663996b3 445
ea0999c9 446static int bus_unit_method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
e3bff60a 447 return bus_unit_method_start_generic(message, userdata, JOB_RELOAD, false, error);
60f067b4 448}
663996b3 449
ea0999c9 450static int bus_unit_method_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
e3bff60a 451 return bus_unit_method_start_generic(message, userdata, JOB_RESTART, false, error);
60f067b4 452}
663996b3 453
ea0999c9 454static int bus_unit_method_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
e3bff60a 455 return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, false, error);
60f067b4 456}
663996b3 457
ea0999c9 458static int bus_unit_method_reload_or_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
e3bff60a 459 return bus_unit_method_start_generic(message, userdata, JOB_RESTART, true, error);
60f067b4 460}
663996b3 461
ea0999c9 462static int bus_unit_method_reload_or_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
e3bff60a 463 return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
60f067b4 464}
663996b3 465
bb4f798a
MB
466int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
467 BusUnitQueueFlags flags = BUS_UNIT_QUEUE_VERBOSE_REPLY;
468 const char *jtype, *smode;
469 Unit *u = userdata;
470 JobType type;
471 JobMode mode;
472 int r;
473
474 assert(message);
475 assert(u);
476
477 r = sd_bus_message_read(message, "ss", &jtype, &smode);
478 if (r < 0)
479 return r;
480
481 /* Parse the two magic reload types "reload-or-…" manually */
482 if (streq(jtype, "reload-or-restart")) {
483 type = JOB_RESTART;
484 flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
485 } else if (streq(jtype, "reload-or-try-restart")) {
486 type = JOB_TRY_RESTART;
487 flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
488 } else {
489 /* And the rest generically */
490 type = job_type_from_string(jtype);
491 if (type < 0)
492 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job type %s invalid", jtype);
493 }
494
495 mode = job_mode_from_string(smode);
496 if (mode < 0)
497 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
498
499 r = mac_selinux_unit_access_check(
500 u, message,
501 job_type_to_access_method(type),
502 error);
503 if (r < 0)
504 return r;
505
506 r = bus_verify_manage_units_async_full(
507 u,
508 jtype,
509 CAP_SYS_ADMIN,
510 polkit_message_for_job[type],
511 true,
512 message,
513 error);
514 if (r < 0)
515 return r;
516 if (r == 0)
517 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
518
519 return bus_unit_queue_job(message, u, type, mode, flags, error);
520}
521
e3bff60a 522int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4
JS
523 Unit *u = userdata;
524 const char *swho;
525 int32_t signo;
526 KillWho who;
527 int r;
663996b3 528
60f067b4
JS
529 assert(message);
530 assert(u);
663996b3 531
e3bff60a 532 r = mac_selinux_unit_access_check(u, message, "stop", error);
5eef597e
MP
533 if (r < 0)
534 return r;
5eef597e 535
60f067b4
JS
536 r = sd_bus_message_read(message, "si", &swho, &signo);
537 if (r < 0)
538 return r;
539
540 if (isempty(swho))
541 who = KILL_ALL;
542 else {
543 who = kill_who_from_string(swho);
544 if (who < 0)
545 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
663996b3
MS
546 }
547
aa27b158 548 if (!SIGNAL_VALID(signo))
8b3d4ff0 549 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
60f067b4 550
d9dfd233
MP
551 r = bus_verify_manage_units_async_full(
552 u,
553 "kill",
554 CAP_KILL,
6e866b33 555 N_("Authentication is required to send a UNIX signal to the processes of '$(unit)'."),
8a584da2 556 true,
d9dfd233
MP
557 message,
558 error);
60f067b4
JS
559 if (r < 0)
560 return r;
e3bff60a
MP
561 if (r == 0)
562 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
663996b3 563
60f067b4
JS
564 r = unit_kill(u, who, signo, error);
565 if (r < 0)
566 return r;
663996b3 567
60f067b4 568 return sd_bus_reply_method_return(message, NULL);
663996b3
MS
569}
570
e3bff60a 571int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4 572 Unit *u = userdata;
663996b3 573 int r;
663996b3 574
663996b3 575 assert(message);
60f067b4 576 assert(u);
663996b3 577
e3bff60a 578 r = mac_selinux_unit_access_check(u, message, "reload", error);
5eef597e
MP
579 if (r < 0)
580 return r;
5eef597e 581
d9dfd233
MP
582 r = bus_verify_manage_units_async_full(
583 u,
584 "reset-failed",
585 CAP_SYS_ADMIN,
586 N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
8a584da2 587 true,
d9dfd233
MP
588 message,
589 error);
60f067b4
JS
590 if (r < 0)
591 return r;
e3bff60a
MP
592 if (r == 0)
593 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
663996b3 594
60f067b4 595 unit_reset_failed(u);
663996b3 596
60f067b4
JS
597 return sd_bus_reply_method_return(message, NULL);
598}
663996b3 599
e3bff60a 600int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4
JS
601 Unit *u = userdata;
602 int runtime, r;
663996b3 603
60f067b4
JS
604 assert(message);
605 assert(u);
663996b3 606
e3bff60a 607 r = mac_selinux_unit_access_check(u, message, "start", error);
5eef597e
MP
608 if (r < 0)
609 return r;
5eef597e 610
60f067b4
JS
611 r = sd_bus_message_read(message, "b", &runtime);
612 if (r < 0)
613 return r;
663996b3 614
d9dfd233
MP
615 r = bus_verify_manage_units_async_full(
616 u,
617 "set-property",
618 CAP_SYS_ADMIN,
619 N_("Authentication is required to set properties on '$(unit)'."),
8a584da2 620 true,
d9dfd233
MP
621 message,
622 error);
60f067b4
JS
623 if (r < 0)
624 return r;
e3bff60a
MP
625 if (r == 0)
626 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
663996b3 627
60f067b4
JS
628 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
629 if (r < 0)
630 return r;
663996b3 631
60f067b4
JS
632 return sd_bus_reply_method_return(message, NULL);
633}
663996b3 634
8a584da2
MP
635int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error) {
636 Unit *u = userdata;
637 int r;
638
639 assert(message);
640 assert(u);
641
642 r = mac_selinux_unit_access_check(u, message, "start", error);
643 if (r < 0)
644 return r;
645
646 r = bus_verify_manage_units_async_full(
647 u,
648 "ref",
649 CAP_SYS_ADMIN,
650 NULL,
651 false,
652 message,
653 error);
654 if (r < 0)
655 return r;
656 if (r == 0)
657 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
658
659 r = bus_unit_track_add_sender(u, message);
660 if (r < 0)
661 return r;
662
663 return sd_bus_reply_method_return(message, NULL);
664}
665
666int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error) {
667 Unit *u = userdata;
668 int r;
669
670 assert(message);
671 assert(u);
672
673 r = bus_unit_track_remove_sender(u, message);
674 if (r == -EUNATCH)
8b3d4ff0 675 return sd_bus_error_set(error, BUS_ERROR_NOT_REFERENCED, "Unit has not been referenced yet.");
8a584da2
MP
676 if (r < 0)
677 return r;
678
679 return sd_bus_reply_method_return(message, NULL);
680}
681
f2dec872
BR
682int bus_unit_method_clean(sd_bus_message *message, void *userdata, sd_bus_error *error) {
683 ExecCleanMask mask = 0;
684 Unit *u = userdata;
685 int r;
686
687 assert(message);
688 assert(u);
689
690 r = mac_selinux_unit_access_check(u, message, "stop", error);
691 if (r < 0)
692 return r;
693
694 r = sd_bus_message_enter_container(message, 'a', "s");
695 if (r < 0)
696 return r;
697
698 for (;;) {
699 const char *i;
700
701 r = sd_bus_message_read(message, "s", &i);
702 if (r < 0)
703 return r;
704 if (r == 0)
705 break;
706
707 if (streq(i, "all"))
708 mask |= EXEC_CLEAN_ALL;
709 else {
710 ExecDirectoryType t;
711
712 t = exec_resource_type_from_string(i);
713 if (t < 0)
714 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid resource type: %s", i);
715
716 mask |= 1U << t;
717 }
718 }
719
720 r = sd_bus_message_exit_container(message);
721 if (r < 0)
722 return r;
723
724 r = bus_verify_manage_units_async_full(
725 u,
726 "clean",
727 CAP_DAC_OVERRIDE,
728 N_("Authentication is required to delete files and directories associated with '$(unit)'."),
729 true,
730 message,
731 error);
732 if (r < 0)
733 return r;
734 if (r == 0)
735 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
736
737 r = unit_clean(u, mask);
738 if (r == -EOPNOTSUPP)
739 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Unit '%s' does not supporting cleaning.", u->id);
740 if (r == -EUNATCH)
8b3d4ff0 741 return sd_bus_error_set(error, BUS_ERROR_NOTHING_TO_CLEAN, "No matching resources found.");
f2dec872 742 if (r == -EBUSY)
8b3d4ff0 743 return sd_bus_error_set(error, BUS_ERROR_UNIT_BUSY, "Unit is not inactive or has pending job.");
f2dec872
BR
744 if (r < 0)
745 return r;
746
747 return sd_bus_reply_method_return(message, NULL);
748}
749
a10f5d05
MB
750static int bus_unit_method_freezer_generic(sd_bus_message *message, void *userdata, sd_bus_error *error, FreezerAction action) {
751 const char* perm;
752 int (*method)(Unit*);
753 Unit *u = userdata;
754 bool reply_no_delay = false;
755 int r;
756
757 assert(message);
758 assert(u);
759 assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
760
761 if (action == FREEZER_FREEZE) {
762 perm = "stop";
763 method = unit_freeze;
764 } else {
765 perm = "start";
766 method = unit_thaw;
767 }
768
769 r = mac_selinux_unit_access_check(u, message, perm, error);
770 if (r < 0)
771 return r;
772
773 r = bus_verify_manage_units_async_full(
774 u,
775 perm,
776 CAP_SYS_ADMIN,
777 N_("Authentication is required to freeze or thaw the processes of '$(unit)' unit."),
778 true,
779 message,
780 error);
781 if (r < 0)
782 return r;
783 if (r == 0)
784 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
785
786 r = method(u);
787 if (r == -EOPNOTSUPP)
788 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Unit '%s' does not support freezing.", u->id);
789 if (r == -EBUSY)
8b3d4ff0 790 return sd_bus_error_set(error, BUS_ERROR_UNIT_BUSY, "Unit has a pending job.");
a10f5d05 791 if (r == -EHOSTDOWN)
8b3d4ff0 792 return sd_bus_error_set(error, BUS_ERROR_UNIT_INACTIVE, "Unit is inactive.");
a10f5d05
MB
793 if (r == -EALREADY)
794 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Previously requested freezer operation for unit '%s' is still in progress.", u->id);
795 if (r < 0)
796 return r;
797 if (r == 0)
798 reply_no_delay = true;
799
800 assert(!u->pending_freezer_message);
801
802 r = sd_bus_message_new_method_return(message, &u->pending_freezer_message);
803 if (r < 0)
804 return r;
805
806 if (reply_no_delay) {
807 r = bus_unit_send_pending_freezer_message(u);
808 if (r < 0)
809 return r;
810 }
811
812 return 1;
813}
814
815int bus_unit_method_thaw(sd_bus_message *message, void *userdata, sd_bus_error *error) {
816 return bus_unit_method_freezer_generic(message, userdata, error, FREEZER_THAW);
817}
818
819int bus_unit_method_freeze(sd_bus_message *message, void *userdata, sd_bus_error *error) {
820 return bus_unit_method_freezer_generic(message, userdata, error, FREEZER_FREEZE);
821}
822
6e866b33
MB
823static int property_get_refs(
824 sd_bus *bus,
825 const char *path,
826 const char *interface,
827 const char *property,
828 sd_bus_message *reply,
829 void *userdata,
830 sd_bus_error *error) {
831
832 Unit *u = userdata;
6e866b33
MB
833 int r;
834
835 assert(bus);
836 assert(reply);
837
838 r = sd_bus_message_open_container(reply, 'a', "s");
839 if (r < 0)
840 return r;
841
3a6ce677
BR
842 for (const char *i = sd_bus_track_first(u->bus_track); i; i = sd_bus_track_next(u->bus_track)) {
843 int c;
6e866b33
MB
844
845 c = sd_bus_track_count_name(u->bus_track, i);
846 if (c < 0)
847 return c;
848
849 /* Add the item multiple times if the ref count for each is above 1 */
3a6ce677 850 for (int k = 0; k < c; k++) {
6e866b33
MB
851 r = sd_bus_message_append(reply, "s", i);
852 if (r < 0)
853 return r;
854 }
855 }
856
857 return sd_bus_message_close_container(reply);
858}
859
60f067b4
JS
860const sd_bus_vtable bus_unit_vtable[] = {
861 SD_BUS_VTABLE_START(0),
862
863 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
a10f5d05 864 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
60f067b4 865 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
8b3d4ff0
MB
866 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
867 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
868 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
869 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
870 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
a80b52fd 871 SD_BUS_PROPERTY("Upholds", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
8b3d4ff0
MB
872 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
873 SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
874 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
875 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
a80b52fd 876 SD_BUS_PROPERTY("UpheldBy", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
8b3d4ff0
MB
877 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
878 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
879 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
880 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
881 SD_BUS_PROPERTY("After", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
8b3d4ff0
MB
882 SD_BUS_PROPERTY("OnSuccess", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
883 SD_BUS_PROPERTY("OnSuccessOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
a80b52fd
MB
884 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
885 SD_BUS_PROPERTY("OnFailureOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
8b3d4ff0
MB
886 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
887 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
888 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
889 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
890 SD_BUS_PROPERTY("PropagatesStopTo", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
891 SD_BUS_PROPERTY("StopPropagatedFrom", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
892 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
893 SD_BUS_PROPERTY("SliceOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
52ad194e 894 SD_BUS_PROPERTY("RequiresMountsFor", "as", property_get_requires_mounts_for, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
60f067b4
JS
895 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
896 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
897 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
898 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
a10f5d05 899 SD_BUS_PROPERTY("FreezerState", "s", property_get_freezer_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
60f067b4
JS
900 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
901 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
902 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
903 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
904 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
f47781d8 905 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
4c89c718 906 BUS_PROPERTY_DUAL_TIMESTAMP("StateChangeTimestamp", offsetof(Unit, state_change_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
60f067b4
JS
907 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
908 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
909 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
910 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
911 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
912 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
913 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
914 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
f2dec872 915 SD_BUS_PROPERTY("CanClean", "as", property_get_can_clean, 0, SD_BUS_VTABLE_PROPERTY_CONST),
a10f5d05 916 SD_BUS_PROPERTY("CanFreeze", "b", property_get_can_freeze, 0, SD_BUS_VTABLE_PROPERTY_CONST),
b012e921 917 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, offsetof(Unit, job), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
60f067b4
JS
918 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
919 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
920 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
921 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
922 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
2c6f20ef
MB
923 SD_BUS_PROPERTY("OnSuccesJobMode", "s", property_get_job_mode, offsetof(Unit, on_success_job_mode), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* deprecated */
924 SD_BUS_PROPERTY("OnSuccessJobMode", "s", property_get_job_mode, offsetof(Unit, on_success_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
60f067b4
JS
925 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
926 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
ce5f39bd 927 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, 0),
3a6ce677 928 SD_BUS_PROPERTY("Markers", "as", property_get_markers, offsetof(Unit, markers), 0),
60f067b4 929 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
81c58355 930 SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
8b3d4ff0 931 SD_BUS_PROPERTY("JobTimeoutAction", "s", bus_property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
5eef597e 932 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
60f067b4 933 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f47781d8 934 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
60f067b4 935 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f47781d8 936 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
6e866b33
MB
937 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
938 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
60f067b4
JS
939 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
940 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
8a584da2 941 SD_BUS_PROPERTY("Perpetual", "b", bus_property_get_bool, offsetof(Unit, perpetual), SD_BUS_VTABLE_PROPERTY_CONST),
e1f67bc7
MB
942 SD_BUS_PROPERTY("StartLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Unit, start_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
943 SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_ratelimit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
8b3d4ff0
MB
944 SD_BUS_PROPERTY("StartLimitAction", "s", bus_property_get_emergency_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
945 SD_BUS_PROPERTY("FailureAction", "s", bus_property_get_emergency_action, offsetof(Unit, failure_action), SD_BUS_VTABLE_PROPERTY_CONST),
6e866b33 946 SD_BUS_PROPERTY("FailureActionExitStatus", "i", bus_property_get_int, offsetof(Unit, failure_action_exit_status), SD_BUS_VTABLE_PROPERTY_CONST),
8b3d4ff0 947 SD_BUS_PROPERTY("SuccessAction", "s", bus_property_get_emergency_action, offsetof(Unit, success_action), SD_BUS_VTABLE_PROPERTY_CONST),
6e866b33 948 SD_BUS_PROPERTY("SuccessActionExitStatus", "i", bus_property_get_int, offsetof(Unit, success_action_exit_status), SD_BUS_VTABLE_PROPERTY_CONST),
4c89c718 949 SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
6e866b33
MB
950 SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
951 SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode, offsetof(Unit, collect_mode), SD_BUS_VTABLE_PROPERTY_CONST),
952 SD_BUS_PROPERTY("Refs", "as", property_get_refs, 0, 0),
60f067b4 953
a10f5d05
MB
954 SD_BUS_METHOD_WITH_NAMES("Start",
955 "s",
956 SD_BUS_PARAM(mode),
957 "o",
958 SD_BUS_PARAM(job),
ea0999c9 959 bus_unit_method_start,
a10f5d05
MB
960 SD_BUS_VTABLE_UNPRIVILEGED),
961 SD_BUS_METHOD_WITH_NAMES("Stop",
962 "s",
963 SD_BUS_PARAM(mode),
964 "o",
965 SD_BUS_PARAM(job),
ea0999c9 966 bus_unit_method_stop,
a10f5d05
MB
967 SD_BUS_VTABLE_UNPRIVILEGED),
968 SD_BUS_METHOD_WITH_NAMES("Reload",
969 "s",
970 SD_BUS_PARAM(mode),
971 "o",
972 SD_BUS_PARAM(job),
ea0999c9 973 bus_unit_method_reload,
a10f5d05
MB
974 SD_BUS_VTABLE_UNPRIVILEGED),
975 SD_BUS_METHOD_WITH_NAMES("Restart",
976 "s",
977 SD_BUS_PARAM(mode),
978 "o",
979 SD_BUS_PARAM(job),
ea0999c9 980 bus_unit_method_restart,
a10f5d05
MB
981 SD_BUS_VTABLE_UNPRIVILEGED),
982 SD_BUS_METHOD_WITH_NAMES("TryRestart",
983 "s",
984 SD_BUS_PARAM(mode),
985 "o",
986 SD_BUS_PARAM(job),
ea0999c9 987 bus_unit_method_try_restart,
a10f5d05
MB
988 SD_BUS_VTABLE_UNPRIVILEGED),
989 SD_BUS_METHOD_WITH_NAMES("ReloadOrRestart",
990 "s",
991 SD_BUS_PARAM(mode),
992 "o",
993 SD_BUS_PARAM(job),
ea0999c9 994 bus_unit_method_reload_or_restart,
a10f5d05
MB
995 SD_BUS_VTABLE_UNPRIVILEGED),
996 SD_BUS_METHOD_WITH_NAMES("ReloadOrTryRestart",
997 "s",
998 SD_BUS_PARAM(mode),
999 "o",
1000 SD_BUS_PARAM(job),
ea0999c9 1001 bus_unit_method_reload_or_try_restart,
a10f5d05
MB
1002 SD_BUS_VTABLE_UNPRIVILEGED),
1003 SD_BUS_METHOD_WITH_NAMES("EnqueueJob",
1004 "ss",
1005 SD_BUS_PARAM(job_type)
1006 SD_BUS_PARAM(job_mode),
1007 "uososa(uosos)",
1008 SD_BUS_PARAM(job_id)
1009 SD_BUS_PARAM(job_path)
1010 SD_BUS_PARAM(unit_id)
1011 SD_BUS_PARAM(unit_path)
1012 SD_BUS_PARAM(job_type)
1013 SD_BUS_PARAM(affected_jobs),
1014 bus_unit_method_enqueue_job,
1015 SD_BUS_VTABLE_UNPRIVILEGED),
1016 SD_BUS_METHOD_WITH_NAMES("Kill",
1017 "si",
1018 SD_BUS_PARAM(whom)
1019 SD_BUS_PARAM(signal),
1020 NULL,,
1021 bus_unit_method_kill,
1022 SD_BUS_VTABLE_UNPRIVILEGED),
1023 SD_BUS_METHOD("ResetFailed",
1024 NULL,
1025 NULL,
1026 bus_unit_method_reset_failed,
1027 SD_BUS_VTABLE_UNPRIVILEGED),
1028 SD_BUS_METHOD_WITH_NAMES("SetProperties",
1029 "ba(sv)",
1030 SD_BUS_PARAM(runtime)
1031 SD_BUS_PARAM(properties),
1032 NULL,,
1033 bus_unit_method_set_properties,
1034 SD_BUS_VTABLE_UNPRIVILEGED),
1035 SD_BUS_METHOD("Ref",
1036 NULL,
1037 NULL,
1038 bus_unit_method_ref,
1039 SD_BUS_VTABLE_UNPRIVILEGED),
1040 SD_BUS_METHOD("Unref",
1041 NULL,
1042 NULL,
1043 bus_unit_method_unref,
1044 SD_BUS_VTABLE_UNPRIVILEGED),
1045 SD_BUS_METHOD_WITH_NAMES("Clean",
1046 "as",
1047 SD_BUS_PARAM(mask),
1048 NULL,,
1049 bus_unit_method_clean,
1050 SD_BUS_VTABLE_UNPRIVILEGED),
1051 SD_BUS_METHOD("Freeze",
1052 NULL,
1053 NULL,
1054 bus_unit_method_freeze,
1055 SD_BUS_VTABLE_UNPRIVILEGED),
1056 SD_BUS_METHOD("Thaw",
1057 NULL,
1058 NULL,
1059 bus_unit_method_thaw,
1060 SD_BUS_VTABLE_UNPRIVILEGED),
60f067b4 1061
b012e921
MB
1062 /* For dependency types we don't support anymore always return an empty array */
1063 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
1064 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
1065 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
1066 SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
1067 /* Obsolete alias names */
e1f67bc7
MB
1068 SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1069 SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
a10f5d05 1070
60f067b4
JS
1071 SD_BUS_VTABLE_END
1072};
663996b3 1073
60f067b4
JS
1074static int property_get_slice(
1075 sd_bus *bus,
1076 const char *path,
1077 const char *interface,
1078 const char *property,
1079 sd_bus_message *reply,
1080 void *userdata,
1081 sd_bus_error *error) {
663996b3 1082
60f067b4 1083 Unit *u = userdata;
663996b3 1084
60f067b4
JS
1085 assert(bus);
1086 assert(reply);
1087 assert(u);
663996b3 1088
60f067b4
JS
1089 return sd_bus_message_append(reply, "s", unit_slice_name(u));
1090}
663996b3 1091
e735f4d4
MP
1092static int property_get_current_memory(
1093 sd_bus *bus,
1094 const char *path,
1095 const char *interface,
1096 const char *property,
1097 sd_bus_message *reply,
1098 void *userdata,
1099 sd_bus_error *error) {
1100
3a6ce677 1101 uint64_t sz = UINT64_MAX;
e3bff60a 1102 Unit *u = userdata;
e735f4d4
MP
1103 int r;
1104
1105 assert(bus);
1106 assert(reply);
1107 assert(u);
1108
e3bff60a
MP
1109 r = unit_get_memory_current(u, &sz);
1110 if (r < 0 && r != -ENODATA)
1111 log_unit_warning_errno(u, r, "Failed to get memory.usage_in_bytes attribute: %m");
e735f4d4 1112
e3bff60a
MP
1113 return sd_bus_message_append(reply, "t", sz);
1114}
e735f4d4 1115
8b3d4ff0
MB
1116static int property_get_available_memory(
1117 sd_bus *bus,
1118 const char *path,
1119 const char *interface,
1120 const char *property,
1121 sd_bus_message *reply,
1122 void *userdata,
1123 sd_bus_error *error) {
1124
1125 uint64_t sz = UINT64_MAX;
1126 Unit *u = userdata;
1127 int r;
1128
1129 assert(bus);
1130 assert(reply);
1131 assert(u);
1132
1133 r = unit_get_memory_available(u, &sz);
1134 if (r < 0 && r != -ENODATA)
1135 log_unit_warning_errno(u, r, "Failed to get total available memory from cgroup: %m");
1136
1137 return sd_bus_message_append(reply, "t", sz);
1138}
1139
6300502b
MP
1140static int property_get_current_tasks(
1141 sd_bus *bus,
1142 const char *path,
1143 const char *interface,
1144 const char *property,
1145 sd_bus_message *reply,
1146 void *userdata,
1147 sd_bus_error *error) {
1148
3a6ce677 1149 uint64_t cn = UINT64_MAX;
6300502b
MP
1150 Unit *u = userdata;
1151 int r;
1152
1153 assert(bus);
1154 assert(reply);
1155 assert(u);
1156
1157 r = unit_get_tasks_current(u, &cn);
1158 if (r < 0 && r != -ENODATA)
1159 log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m");
1160
1161 return sd_bus_message_append(reply, "t", cn);
1162}
1163
e3bff60a
MP
1164static int property_get_cpu_usage(
1165 sd_bus *bus,
1166 const char *path,
1167 const char *interface,
1168 const char *property,
1169 sd_bus_message *reply,
1170 void *userdata,
1171 sd_bus_error *error) {
e735f4d4 1172
3a6ce677 1173 nsec_t ns = NSEC_INFINITY;
e3bff60a
MP
1174 Unit *u = userdata;
1175 int r;
1176
1177 assert(bus);
1178 assert(reply);
1179 assert(u);
1180
1181 r = unit_get_cpu_usage(u, &ns);
1182 if (r < 0 && r != -ENODATA)
1183 log_unit_warning_errno(u, r, "Failed to get cpuacct.usage attribute: %m");
1184
1185 return sd_bus_message_append(reply, "t", ns);
e735f4d4
MP
1186}
1187
e1f67bc7
MB
1188static int property_get_cpuset_cpus(
1189 sd_bus *bus,
1190 const char *path,
1191 const char *interface,
1192 const char *property,
1193 sd_bus_message *reply,
1194 void *userdata,
1195 sd_bus_error *error) {
1196
1197 Unit *u = userdata;
1198 _cleanup_(cpu_set_reset) CPUSet cpus = {};
1199 _cleanup_free_ uint8_t *array = NULL;
1200 size_t allocated;
1201
1202 assert(bus);
1203 assert(reply);
1204 assert(u);
1205
1206 (void) unit_get_cpuset(u, &cpus, "cpuset.cpus.effective");
1207 (void) cpu_set_to_dbus(&cpus, &array, &allocated);
1208 return sd_bus_message_append_array(reply, 'y', array, allocated);
1209}
1210
1211static int property_get_cpuset_mems(
1212 sd_bus *bus,
1213 const char *path,
1214 const char *interface,
1215 const char *property,
1216 sd_bus_message *reply,
1217 void *userdata,
1218 sd_bus_error *error) {
1219
1220 Unit *u = userdata;
1221 _cleanup_(cpu_set_reset) CPUSet mems = {};
1222 _cleanup_free_ uint8_t *array = NULL;
1223 size_t allocated;
1224
1225 assert(bus);
1226 assert(reply);
1227 assert(u);
1228
1229 (void) unit_get_cpuset(u, &mems, "cpuset.mems.effective");
1230 (void) cpu_set_to_dbus(&mems, &array, &allocated);
1231 return sd_bus_message_append_array(reply, 'y', array, allocated);
1232}
1233
13d276d0
MP
1234static int property_get_cgroup(
1235 sd_bus *bus,
1236 const char *path,
1237 const char *interface,
1238 const char *property,
1239 sd_bus_message *reply,
1240 void *userdata,
1241 sd_bus_error *error) {
1242
1243 Unit *u = userdata;
b012e921 1244 const char *t = NULL;
13d276d0
MP
1245
1246 assert(bus);
1247 assert(reply);
1248 assert(u);
1249
1250 /* Three cases: a) u->cgroup_path is NULL, in which case the
1251 * unit has no control group, which we report as the empty
1252 * string. b) u->cgroup_path is the empty string, which
1253 * indicates the root cgroup, which we report as "/". c) all
1254 * other cases we report as-is. */
1255
1256 if (u->cgroup_path)
b012e921 1257 t = empty_to_root(u->cgroup_path);
13d276d0
MP
1258
1259 return sd_bus_message_append(reply, "s", t);
1260}
1261
aa27b158
MP
1262static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *pids) {
1263 _cleanup_free_ char *buf = NULL, *cmdline = NULL;
1264 int r;
1265
1266 assert(reply);
1267 assert(pid > 0);
1268
1269 r = set_put(pids, PID_TO_PTR(pid));
f5e65279 1270 if (IN_SET(r, 0, -EEXIST))
aa27b158
MP
1271 return 0;
1272 if (r < 0)
1273 return r;
1274
1275 if (!p) {
1276 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &buf);
1277 if (r == -ESRCH)
1278 return 0;
1279 if (r < 0)
1280 return r;
1281
1282 p = buf;
1283 }
1284
8b3d4ff0
MB
1285 (void) get_process_cmdline(pid, SIZE_MAX,
1286 PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE,
1287 &cmdline);
aa27b158
MP
1288
1289 return sd_bus_message_append(reply,
1290 "(sus)",
1291 p,
1292 (uint32_t) pid,
1293 cmdline);
1294}
1295
1296static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) {
1297 _cleanup_closedir_ DIR *d = NULL;
1298 _cleanup_fclose_ FILE *f = NULL;
1299 int r;
1300
1301 assert(reply);
1302 assert(p);
1303
1304 r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f);
b012e921 1305 if (r == -ENOENT)
aa27b158
MP
1306 return 0;
1307 if (r < 0)
1308 return r;
1309
1310 for (;;) {
1311 pid_t pid;
1312
a80b52fd
MB
1313 /* libvirt / qemu uses threaded mode and cgroup.procs cannot be read at the lower levels.
1314 * From https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#threads,
1315 * “cgroup.procs” in a threaded domain cgroup contains the PIDs of all processes in
1316 * the subtree and is not readable in the subtree proper. */
aa27b158 1317 r = cg_read_pid(f, &pid);
a80b52fd
MB
1318 if (IN_SET(r, 0, -EOPNOTSUPP))
1319 break;
aa27b158
MP
1320 if (r < 0)
1321 return r;
aa27b158
MP
1322
1323 if (is_kernel_thread(pid) > 0)
1324 continue;
1325
1326 r = append_process(reply, p, pid, pids);
1327 if (r < 0)
1328 return r;
1329 }
1330
1331 r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, p, &d);
1332 if (r == -ENOENT)
1333 return 0;
1334 if (r < 0)
1335 return r;
1336
1337 for (;;) {
1338 _cleanup_free_ char *g = NULL, *j = NULL;
1339
1340 r = cg_read_subgroup(d, &g);
1341 if (r < 0)
1342 return r;
1343 if (r == 0)
1344 break;
1345
f2dec872 1346 j = path_join(empty_to_root(p), g);
aa27b158
MP
1347 if (!j)
1348 return -ENOMEM;
1349
1350 r = append_cgroup(reply, j, pids);
1351 if (r < 0)
1352 return r;
1353 }
1354
1355 return 0;
1356}
1357
1358int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1359 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
b012e921 1360 _cleanup_set_free_ Set *pids = NULL;
aa27b158
MP
1361 Unit *u = userdata;
1362 pid_t pid;
1363 int r;
1364
1365 assert(message);
1366
2897b343
MP
1367 r = mac_selinux_unit_access_check(u, message, "status", error);
1368 if (r < 0)
1369 return r;
1370
aa27b158
MP
1371 pids = set_new(NULL);
1372 if (!pids)
1373 return -ENOMEM;
1374
1375 r = sd_bus_message_new_method_return(message, &reply);
1376 if (r < 0)
1377 return r;
1378
1379 r = sd_bus_message_open_container(reply, 'a', "(sus)");
1380 if (r < 0)
1381 return r;
1382
1383 if (u->cgroup_path) {
1384 r = append_cgroup(reply, u->cgroup_path, pids);
1385 if (r < 0)
1386 return r;
1387 }
1388
1389 /* The main and control pids might live outside of the cgroup, hence fetch them separately */
1390 pid = unit_main_pid(u);
1391 if (pid > 0) {
1392 r = append_process(reply, NULL, pid, pids);
1393 if (r < 0)
1394 return r;
1395 }
1396
1397 pid = unit_control_pid(u);
1398 if (pid > 0) {
1399 r = append_process(reply, NULL, pid, pids);
1400 if (r < 0)
1401 return r;
1402 }
1403
1404 r = sd_bus_message_close_container(reply);
1405 if (r < 0)
1406 return r;
1407
1408 return sd_bus_send(NULL, reply, NULL);
1409}
1410
f5e65279
MB
1411static int property_get_ip_counter(
1412 sd_bus *bus,
1413 const char *path,
1414 const char *interface,
1415 const char *property,
1416 sd_bus_message *reply,
1417 void *userdata,
1418 sd_bus_error *error) {
1419
f2dec872
BR
1420 static const char *const table[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
1421 [CGROUP_IP_INGRESS_BYTES] = "IPIngressBytes",
1422 [CGROUP_IP_EGRESS_BYTES] = "IPEgressBytes",
1423 [CGROUP_IP_INGRESS_PACKETS] = "IPIngressPackets",
1424 [CGROUP_IP_EGRESS_PACKETS] = "IPEgressPackets",
1425 };
1426
1427 uint64_t value = UINT64_MAX;
f5e65279 1428 Unit *u = userdata;
f2dec872 1429 ssize_t metric;
f5e65279
MB
1430
1431 assert(bus);
1432 assert(reply);
1433 assert(property);
1434 assert(u);
1435
f2dec872 1436 assert_se((metric = string_table_lookup(table, ELEMENTSOF(table), property)) >= 0);
f5e65279
MB
1437 (void) unit_get_ip_accounting(u, metric, &value);
1438 return sd_bus_message_append(reply, "t", value);
1439}
1440
f2dec872
BR
1441static int property_get_io_counter(
1442 sd_bus *bus,
1443 const char *path,
1444 const char *interface,
1445 const char *property,
1446 sd_bus_message *reply,
1447 void *userdata,
1448 sd_bus_error *error) {
1449
1450 static const char *const table[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
1451 [CGROUP_IO_READ_BYTES] = "IOReadBytes",
1452 [CGROUP_IO_WRITE_BYTES] = "IOWriteBytes",
1453 [CGROUP_IO_READ_OPERATIONS] = "IOReadOperations",
1454 [CGROUP_IO_WRITE_OPERATIONS] = "IOWriteOperations",
1455 };
1456
1457 uint64_t value = UINT64_MAX;
1458 Unit *u = userdata;
1459 ssize_t metric;
1460
1461 assert(bus);
1462 assert(reply);
1463 assert(property);
1464 assert(u);
1465
1466 assert_se((metric = string_table_lookup(table, ELEMENTSOF(table), property)) >= 0);
1467 (void) unit_get_io_accounting(u, metric, false, &value);
1468 return sd_bus_message_append(reply, "t", value);
1469}
1470
98393f85
MB
1471int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1472
1473 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
b012e921 1474 _cleanup_set_free_ Set *pids = NULL;
98393f85
MB
1475 Unit *u = userdata;
1476 const char *path;
1477 int r;
1478
1479 assert(message);
1480
1481 /* This migrates the processes with the specified PIDs into the cgroup of this unit, optionally below a
1482 * specified cgroup path. Obviously this only works for units that actually maintain a cgroup
1483 * representation. If a process is already in the cgroup no operation is executed – in this case the specified
1484 * subcgroup path has no effect! */
1485
1486 r = mac_selinux_unit_access_check(u, message, "start", error);
1487 if (r < 0)
1488 return r;
1489
1490 r = sd_bus_message_read(message, "s", &path);
1491 if (r < 0)
1492 return r;
1493
1494 path = empty_to_null(path);
1495 if (path) {
1496 if (!path_is_absolute(path))
1497 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not absolute: %s", path);
1498
1499 if (!path_is_normalized(path))
1500 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not normalized: %s", path);
1501 }
1502
1503 if (!unit_cgroup_delegate(u))
8b3d4ff0 1504 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Process migration not available on non-delegated units.");
98393f85
MB
1505
1506 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)))
8b3d4ff0 1507 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not active, refusing.");
98393f85
MB
1508
1509 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID, &creds);
1510 if (r < 0)
1511 return r;
1512
1513 r = sd_bus_message_enter_container(message, 'a', "u");
1514 if (r < 0)
1515 return r;
1516 for (;;) {
1517 uid_t process_uid, sender_uid;
1518 uint32_t upid;
1519 pid_t pid;
1520
1521 r = sd_bus_message_read(message, "u", &upid);
1522 if (r < 0)
1523 return r;
1524 if (r == 0)
1525 break;
1526
1527 if (upid == 0) {
1528 r = sd_bus_creds_get_pid(creds, &pid);
1529 if (r < 0)
1530 return r;
1531 } else
1532 pid = (uid_t) upid;
1533
1534 /* Filter out duplicates */
1535 if (set_contains(pids, PID_TO_PTR(pid)))
1536 continue;
1537
1538 /* Check if this process is suitable for attaching to this unit */
1539 r = unit_pid_attachable(u, pid, error);
1540 if (r < 0)
1541 return r;
1542
1543 /* Let's query the sender's UID, so that we can make our security decisions */
1544 r = sd_bus_creds_get_euid(creds, &sender_uid);
1545 if (r < 0)
1546 return r;
1547
6e866b33 1548 /* Let's validate security: if the sender is root, then all is OK. If the sender is any other unit,
98393f85
MB
1549 * then the process' UID and the target unit's UID have to match the sender's UID */
1550 if (sender_uid != 0 && sender_uid != getuid()) {
1551 r = get_process_uid(pid, &process_uid);
1552 if (r < 0)
1553 return sd_bus_error_set_errnof(error, r, "Failed to retrieve process UID: %m");
1554
1555 if (process_uid != sender_uid)
1556 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Process " PID_FMT " not owned by client's UID. Refusing.", pid);
1557 if (process_uid != u->ref_uid)
1558 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Process " PID_FMT " not owned by target unit's UID. Refusing.", pid);
1559 }
1560
1561 if (!pids) {
1562 pids = set_new(NULL);
1563 if (!pids)
1564 return -ENOMEM;
1565 }
1566
1567 r = set_put(pids, PID_TO_PTR(pid));
1568 if (r < 0)
1569 return r;
1570 }
1571
1572 r = sd_bus_message_exit_container(message);
1573 if (r < 0)
1574 return r;
1575
1576 r = unit_attach_pids_to_cgroup(u, pids, path);
1577 if (r < 0)
1578 return sd_bus_error_set_errnof(error, r, "Failed to attach processes to control group: %m");
1579
1580 return sd_bus_reply_method_return(message, NULL);
1581}
1582
60f067b4
JS
1583const sd_bus_vtable bus_unit_cgroup_vtable[] = {
1584 SD_BUS_VTABLE_START(0),
1585 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
13d276d0 1586 SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0),
e735f4d4 1587 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
8b3d4ff0 1588 SD_BUS_PROPERTY("MemoryAvailable", "t", property_get_available_memory, 0, 0),
e3bff60a 1589 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
e1f67bc7
MB
1590 SD_BUS_PROPERTY("EffectiveCPUs", "ay", property_get_cpuset_cpus, 0, 0),
1591 SD_BUS_PROPERTY("EffectiveMemoryNodes", "ay", property_get_cpuset_mems, 0, 0),
6300502b 1592 SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
f5e65279
MB
1593 SD_BUS_PROPERTY("IPIngressBytes", "t", property_get_ip_counter, 0, 0),
1594 SD_BUS_PROPERTY("IPIngressPackets", "t", property_get_ip_counter, 0, 0),
1595 SD_BUS_PROPERTY("IPEgressBytes", "t", property_get_ip_counter, 0, 0),
1596 SD_BUS_PROPERTY("IPEgressPackets", "t", property_get_ip_counter, 0, 0),
f2dec872
BR
1597 SD_BUS_PROPERTY("IOReadBytes", "t", property_get_io_counter, 0, 0),
1598 SD_BUS_PROPERTY("IOReadOperations", "t", property_get_io_counter, 0, 0),
1599 SD_BUS_PROPERTY("IOWriteBytes", "t", property_get_io_counter, 0, 0),
1600 SD_BUS_PROPERTY("IOWriteOperations", "t", property_get_io_counter, 0, 0),
a10f5d05
MB
1601
1602 SD_BUS_METHOD_WITH_NAMES("GetProcesses",
1603 NULL,,
1604 "a(sus)",
1605 SD_BUS_PARAM(processes),
1606 bus_unit_method_get_processes,
1607 SD_BUS_VTABLE_UNPRIVILEGED),
1608
1609 SD_BUS_METHOD_WITH_NAMES("AttachProcesses",
1610 "sau",
1611 SD_BUS_PARAM(subcgroup)
1612 SD_BUS_PARAM(pids),
1613 NULL,,
1614 bus_unit_method_attach_processes,
1615 SD_BUS_VTABLE_UNPRIVILEGED),
1616
60f067b4
JS
1617 SD_BUS_VTABLE_END
1618};
663996b3 1619
60f067b4 1620static int send_new_signal(sd_bus *bus, void *userdata) {
4c89c718 1621 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
60f067b4
JS
1622 _cleanup_free_ char *p = NULL;
1623 Unit *u = userdata;
1624 int r;
663996b3 1625
60f067b4
JS
1626 assert(bus);
1627 assert(u);
663996b3 1628
60f067b4 1629 p = unit_dbus_path(u);
e3bff60a 1630 if (!p)
60f067b4 1631 return -ENOMEM;
663996b3 1632
60f067b4
JS
1633 r = sd_bus_message_new_signal(
1634 bus,
1635 &m,
1636 "/org/freedesktop/systemd1",
1637 "org.freedesktop.systemd1.Manager",
1638 "UnitNew");
1639 if (r < 0)
1640 return r;
663996b3 1641
60f067b4
JS
1642 r = sd_bus_message_append(m, "so", u->id, p);
1643 if (r < 0)
1644 return r;
663996b3 1645
60f067b4
JS
1646 return sd_bus_send(bus, m, NULL);
1647}
663996b3 1648
60f067b4
JS
1649static int send_changed_signal(sd_bus *bus, void *userdata) {
1650 _cleanup_free_ char *p = NULL;
1651 Unit *u = userdata;
1652 int r;
663996b3 1653
60f067b4
JS
1654 assert(bus);
1655 assert(u);
663996b3 1656
60f067b4
JS
1657 p = unit_dbus_path(u);
1658 if (!p)
1659 return -ENOMEM;
663996b3 1660
60f067b4
JS
1661 /* Send a properties changed signal. First for the specific
1662 * type, then for the generic unit. The clients may rely on
1663 * this order to get atomic behavior if needed. */
663996b3 1664
60f067b4
JS
1665 r = sd_bus_emit_properties_changed_strv(
1666 bus, p,
d9dfd233 1667 unit_dbus_interface_from_type(u->type),
60f067b4
JS
1668 NULL);
1669 if (r < 0)
1670 return r;
663996b3 1671
60f067b4
JS
1672 return sd_bus_emit_properties_changed_strv(
1673 bus, p,
1674 "org.freedesktop.systemd1.Unit",
1675 NULL);
1676}
663996b3
MS
1677
1678void bus_unit_send_change_signal(Unit *u) {
14228c0d 1679 int r;
663996b3
MS
1680 assert(u);
1681
1682 if (u->in_dbus_queue) {
60f067b4 1683 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
663996b3
MS
1684 u->in_dbus_queue = false;
1685 }
1686
1687 if (!u->id)
1688 return;
1689
2897b343 1690 r = bus_foreach_bus(u->manager, u->bus_track, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
60f067b4 1691 if (r < 0)
e3bff60a 1692 log_unit_debug_errno(u, r, "Failed to send unit change signal for %s: %m", u->id);
663996b3 1693
60f067b4
JS
1694 u->sent_dbus_new_signal = true;
1695}
663996b3 1696
6e866b33
MB
1697void bus_unit_send_pending_change_signal(Unit *u, bool including_new) {
1698
1699 /* Sends out any pending change signals, but only if they really are pending. This call is used when we are
1700 * about to change state in order to force out a PropertiesChanged signal beforehand if there was one pending
1701 * so that clients can follow the full state transition */
1702
1703 if (!u->in_dbus_queue) /* If not enqueued, don't bother */
1704 return;
1705
1706 if (!u->sent_dbus_new_signal && !including_new) /* If the unit was never announced, don't bother, it's fine if
1707 * the unit appears in the new state right-away (except if the
1708 * caller explicitly asked us to send it anyway) */
1709 return;
1710
1711 if (MANAGER_IS_RELOADING(u->manager)) /* Don't generate unnecessary PropertiesChanged signals for the same unit
1712 * when we are reloading. */
1713 return;
1714
1715 bus_unit_send_change_signal(u);
1716}
1717
a10f5d05
MB
1718int bus_unit_send_pending_freezer_message(Unit *u) {
1719 int r;
1720
1721 assert(u);
1722
1723 if (!u->pending_freezer_message)
1724 return 0;
1725
1726 r = sd_bus_send(NULL, u->pending_freezer_message, NULL);
1727 if (r < 0)
1728 log_warning_errno(r, "Failed to send queued message, ignoring: %m");
1729
1730 u->pending_freezer_message = sd_bus_message_unref(u->pending_freezer_message);
1731
1732 return 0;
1733}
1734
60f067b4 1735static int send_removed_signal(sd_bus *bus, void *userdata) {
4c89c718 1736 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
60f067b4
JS
1737 _cleanup_free_ char *p = NULL;
1738 Unit *u = userdata;
1739 int r;
663996b3 1740
60f067b4
JS
1741 assert(bus);
1742 assert(u);
663996b3 1743
60f067b4 1744 p = unit_dbus_path(u);
e3bff60a 1745 if (!p)
60f067b4 1746 return -ENOMEM;
663996b3 1747
60f067b4
JS
1748 r = sd_bus_message_new_signal(
1749 bus,
1750 &m,
1751 "/org/freedesktop/systemd1",
1752 "org.freedesktop.systemd1.Manager",
1753 "UnitRemoved");
1754 if (r < 0)
1755 return r;
663996b3 1756
60f067b4
JS
1757 r = sd_bus_message_append(m, "so", u->id, p);
1758 if (r < 0)
1759 return r;
663996b3 1760
60f067b4 1761 return sd_bus_send(bus, m, NULL);
663996b3
MS
1762}
1763
1764void bus_unit_send_removed_signal(Unit *u) {
60f067b4 1765 int r;
663996b3
MS
1766 assert(u);
1767
8a584da2 1768 if (!u->sent_dbus_new_signal || u->in_dbus_queue)
663996b3
MS
1769 bus_unit_send_change_signal(u);
1770
1771 if (!u->id)
1772 return;
1773
2897b343 1774 r = bus_foreach_bus(u->manager, u->bus_track, send_removed_signal, u);
60f067b4 1775 if (r < 0)
e3bff60a 1776 log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id);
663996b3
MS
1777}
1778
3a6ce677 1779int bus_unit_queue_job_one(
60f067b4 1780 sd_bus_message *message,
663996b3
MS
1781 Unit *u,
1782 JobType type,
1783 JobMode mode,
bb4f798a 1784 BusUnitQueueFlags flags,
3a6ce677 1785 sd_bus_message *reply,
60f067b4 1786 sd_bus_error *error) {
663996b3 1787
a10f5d05 1788 _cleanup_set_free_ Set *affected = NULL;
3a6ce677 1789 _cleanup_free_ char *job_path = NULL, *unit_path = NULL;
bb4f798a 1790 Job *j, *a;
663996b3
MS
1791 int r;
1792
bb4f798a
MB
1793 if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
1794 affected = set_new(NULL);
1795 if (!affected)
1796 return -ENOMEM;
1797 }
1798
1799 r = manager_add_job(u->manager, type, u, mode, affected, error, &j);
663996b3 1800 if (r < 0)
60f067b4 1801 return r;
663996b3 1802
ea0999c9
MB
1803 if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RETURN_SKIP_ON_CONDITION_FAIL))
1804 j->return_skip_on_cond_failure = true;
1805
2897b343
MP
1806 r = bus_job_track_sender(j, message);
1807 if (r < 0)
1808 return r;
663996b3 1809
6e866b33
MB
1810 /* Before we send the method reply, force out the announcement JobNew for this job */
1811 bus_job_send_pending_change_signal(j, true);
1812
bb4f798a
MB
1813 job_path = job_dbus_path(j);
1814 if (!job_path)
1815 return -ENOMEM;
1816
1817 /* The classic response is just a job object path */
1818 if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
3a6ce677 1819 return sd_bus_message_append(reply, "o", job_path);
bb4f798a
MB
1820
1821 /* In verbose mode respond with the anchor job plus everything that has been affected */
bb4f798a
MB
1822
1823 unit_path = unit_dbus_path(j->unit);
1824 if (!unit_path)
1825 return -ENOMEM;
1826
1827 r = sd_bus_message_append(reply, "uosos",
1828 j->id, job_path,
1829 j->unit->id, unit_path,
1830 job_type_to_string(j->type));
1831 if (r < 0)
1832 return r;
1833
1834 r = sd_bus_message_open_container(reply, 'a', "(uosos)");
1835 if (r < 0)
1836 return r;
1837
a032b68d 1838 SET_FOREACH(a, affected) {
bb4f798a
MB
1839 if (a->id == j->id)
1840 continue;
1841
1842 /* Free paths from previous iteration */
1843 job_path = mfree(job_path);
1844 unit_path = mfree(unit_path);
1845
1846 job_path = job_dbus_path(a);
1847 if (!job_path)
1848 return -ENOMEM;
1849
1850 unit_path = unit_dbus_path(a->unit);
1851 if (!unit_path)
1852 return -ENOMEM;
1853
1854 r = sd_bus_message_append(reply, "(uosos)",
1855 a->id, job_path,
1856 a->unit->id, unit_path,
1857 job_type_to_string(a->type));
1858 if (r < 0)
1859 return r;
1860 }
1861
3a6ce677
BR
1862 return sd_bus_message_close_container(reply);
1863}
1864
1865int bus_unit_queue_job(
1866 sd_bus_message *message,
1867 Unit *u,
1868 JobType type,
1869 JobMode mode,
1870 BusUnitQueueFlags flags,
1871 sd_bus_error *error) {
1872
1873 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1874 int r;
1875
1876 assert(message);
1877 assert(u);
1878 assert(type >= 0 && type < _JOB_TYPE_MAX);
1879 assert(mode >= 0 && mode < _JOB_MODE_MAX);
1880
1881 r = mac_selinux_unit_access_check(
1882 u, message,
1883 job_type_to_access_method(type),
1884 error);
1885 if (r < 0)
1886 return r;
1887
1888 if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) {
1889 if (type == JOB_RESTART)
1890 type = JOB_RELOAD_OR_START;
1891 else if (type == JOB_TRY_RESTART)
1892 type = JOB_TRY_RELOAD;
1893 }
1894
1895 if (type == JOB_STOP &&
1896 IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR, UNIT_BAD_SETTING) &&
1897 unit_active_state(u) == UNIT_INACTIVE)
1898 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
1899
1900 if ((type == JOB_START && u->refuse_manual_start) ||
1901 (type == JOB_STOP && u->refuse_manual_stop) ||
1902 (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
1903 (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
1904 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
1905
1906 r = sd_bus_message_new_method_return(message, &reply);
1907 if (r < 0)
1908 return r;
1909
1910 r = bus_unit_queue_job_one(message, u, type, mode, flags, reply, error);
bb4f798a
MB
1911 if (r < 0)
1912 return r;
1913
1914 return sd_bus_send(NULL, reply, NULL);
663996b3
MS
1915}
1916
52ad194e 1917static int bus_unit_set_live_property(
14228c0d
MB
1918 Unit *u,
1919 const char *name,
60f067b4 1920 sd_bus_message *message,
52ad194e 1921 UnitWriteFlags flags,
60f067b4 1922 sd_bus_error *error) {
663996b3 1923
663996b3
MS
1924 int r;
1925
1926 assert(u);
14228c0d 1927 assert(name);
60f067b4 1928 assert(message);
663996b3 1929
3a6ce677
BR
1930 /* Handles setting properties both "live" (i.e. at any time during runtime), and during creation (for
1931 * transient units that are being created). */
52ad194e 1932
14228c0d 1933 if (streq(name, "Description")) {
60f067b4 1934 const char *d;
663996b3 1935
60f067b4
JS
1936 r = sd_bus_message_read(message, "s", &d);
1937 if (r < 0)
1938 return r;
663996b3 1939
52ad194e 1940 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
60f067b4 1941 r = unit_set_description(u, d);
14228c0d
MB
1942 if (r < 0)
1943 return r;
663996b3 1944
52ad194e 1945 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "Description=%s", d);
14228c0d 1946 }
663996b3 1947
14228c0d 1948 return 1;
52ad194e 1949 }
e735f4d4 1950
3a6ce677
BR
1951 /* A setting that only applies to active units. We don't actually write this to /run, this state is
1952 * managed internally. "+foo" sets flag foo, "-foo" unsets flag foo, just "foo" resets flags to
1953 * foo. The last type cannot be mixed with "+" or "-". */
1954
1955 if (streq(name, "Markers")) {
1956 unsigned settings = 0, mask = 0;
1957 bool some_plus_minus = false, some_absolute = false;
1958
1959 r = sd_bus_message_enter_container(message, 'a', "s");
1960 if (r < 0)
1961 return r;
1962
1963 for (;;) {
1964 const char *word;
1965 bool b;
1966
1967 r = sd_bus_message_read(message, "s", &word);
1968 if (r < 0)
1969 return r;
1970 if (r == 0)
1971 break;
1972
1973 if (IN_SET(word[0], '+', '-')) {
1974 b = word[0] == '+';
1975 word++;
1976 some_plus_minus = true;
1977 } else {
1978 b = true;
1979 some_absolute = true;
1980 }
1981
1982 UnitMarker m = unit_marker_from_string(word);
1983 if (m < 0)
1984 return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING,
1985 "Unknown marker \"%s\".", word);
1986
1987 SET_FLAG(settings, 1u << m, b);
1988 SET_FLAG(mask, 1u << m, true);
1989 }
1990
1991 r = sd_bus_message_exit_container(message);
1992 if (r < 0)
1993 return r;
1994
1995 if (some_plus_minus && some_absolute)
8b3d4ff0 1996 return sd_bus_error_set(error, BUS_ERROR_BAD_UNIT_SETTING, "Bad marker syntax.");
3a6ce677
BR
1997
1998 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1999 if (some_absolute)
2000 u->markers = settings;
2001 else
2002 u->markers = settings | (u->markers & ~mask);
2003 }
2004
2005 return 1;
2006 }
2007
52ad194e
MB
2008 return 0;
2009}
2010
6e866b33
MB
2011static int bus_set_transient_emergency_action(
2012 Unit *u,
2013 const char *name,
2014 EmergencyAction *p,
2015 sd_bus_message *message,
2016 UnitWriteFlags flags,
2017 sd_bus_error *error) {
2018
2019 const char *s;
2020 EmergencyAction v;
2021 int r;
2022 bool system;
2023
2024 assert(p);
2025
2026 r = sd_bus_message_read(message, "s", &s);
2027 if (r < 0)
2028 return r;
2029
2030 system = MANAGER_IS_SYSTEM(u->manager);
2031 r = parse_emergency_action(s, system, &v);
7c20daf6 2032 if (r < 0)
6e866b33 2033 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
7c20daf6 2034 r == -EOPNOTSUPP ? "%s setting invalid for manager type: %s"
6e866b33
MB
2035 : "Invalid %s setting: %s",
2036 name, s);
2037
2038 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2039 *p = v;
2040 unit_write_settingf(u, flags, name,
2041 "%s=%s", name, s);
2042 }
2043
2044 return 1;
2045}
2046
2047static int bus_set_transient_exit_status(
2048 Unit *u,
2049 const char *name,
2050 int *p,
2051 sd_bus_message *message,
2052 UnitWriteFlags flags,
2053 sd_bus_error *error) {
2054
2055 int32_t k;
2056 int r;
2057
2058 assert(p);
2059
2060 r = sd_bus_message_read(message, "i", &k);
2061 if (r < 0)
2062 return r;
2063
2064 if (k > 255)
8b3d4ff0 2065 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Exit status must be in range 0…255 or negative.");
6e866b33
MB
2066
2067 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2068 *p = k < 0 ? -1 : k;
2069
2070 if (k < 0)
2071 unit_write_settingf(u, flags, name, "%s=", name);
2072 else
2073 unit_write_settingf(u, flags, name, "%s=%i", name, k);
2074 }
2075
2076 return 1;
2077}
2078
1d42b86d 2079static BUS_DEFINE_SET_TRANSIENT_PARSE(collect_mode, CollectMode, collect_mode_from_string);
1d42b86d
MB
2080static BUS_DEFINE_SET_TRANSIENT_PARSE(job_mode, JobMode, job_mode_from_string);
2081
2082static int bus_set_transient_conditions(
2083 Unit *u,
2084 const char *name,
2085 Condition **list,
2086 bool is_condition,
2087 sd_bus_message *message,
2088 UnitWriteFlags flags,
2089 sd_bus_error *error) {
2090
2091 const char *type_name, *param;
2092 int trigger, negate, r;
2093 bool empty = true;
2094
2095 assert(list);
2096
2097 r = sd_bus_message_enter_container(message, 'a', "(sbbs)");
2098 if (r < 0)
2099 return r;
2100
2101 while ((r = sd_bus_message_read(message, "(sbbs)", &type_name, &trigger, &negate, &param)) > 0) {
2102 ConditionType t;
2103
2104 t = is_condition ? condition_type_from_string(type_name) : assert_type_from_string(type_name);
2105 if (t < 0)
2106 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid condition type: %s", type_name);
2107
a032b68d
MB
2108 if (isempty(param))
2109 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Condition parameter in %s is empty", type_name);
1d42b86d 2110
a032b68d
MB
2111 if (condition_takes_path(t) && !path_is_absolute(param))
2112 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path in condition %s is not absolute: %s", type_name, param);
1d42b86d
MB
2113
2114 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2115 Condition *c;
2116
2117 c = condition_new(t, param, trigger, negate);
2118 if (!c)
2119 return -ENOMEM;
2120
2121 LIST_PREPEND(conditions, *list, c);
2122
a032b68d
MB
2123 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name,
2124 "%s=%s%s%s", type_name,
2125 trigger ? "|" : "", negate ? "!" : "", param);
1d42b86d
MB
2126 }
2127
2128 empty = false;
2129 }
2130 if (r < 0)
2131 return r;
2132
2133 r = sd_bus_message_exit_container(message);
2134 if (r < 0)
2135 return r;
2136
2137 if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
2138 *list = condition_free_list(*list);
2139 unit_write_settingf(u, flags, name, "%sNull=", is_condition ? "Condition" : "Assert");
2140 }
2141
2142 return 1;
2143}
2144
52ad194e
MB
2145static int bus_unit_set_transient_property(
2146 Unit *u,
2147 const char *name,
2148 sd_bus_message *message,
2149 UnitWriteFlags flags,
2150 sd_bus_error *error) {
2151
3a6ce677 2152 UnitDependency d;
52ad194e
MB
2153 int r;
2154
2155 assert(u);
2156 assert(name);
2157 assert(message);
2158
3a6ce677
BR
2159 /* Handles settings when transient units are created. This settings cannot be altered anymore after
2160 * the unit has been created. */
52ad194e 2161
1d42b86d
MB
2162 if (streq(name, "SourcePath"))
2163 return bus_set_transient_path(u, name, &u->source_path, message, flags, error);
e735f4d4 2164
1d42b86d
MB
2165 if (streq(name, "StopWhenUnneeded"))
2166 return bus_set_transient_bool(u, name, &u->stop_when_unneeded, message, flags, error);
e735f4d4 2167
1d42b86d
MB
2168 if (streq(name, "RefuseManualStart"))
2169 return bus_set_transient_bool(u, name, &u->refuse_manual_start, message, flags, error);
52ad194e 2170
1d42b86d
MB
2171 if (streq(name, "RefuseManualStop"))
2172 return bus_set_transient_bool(u, name, &u->refuse_manual_stop, message, flags, error);
52ad194e 2173
1d42b86d
MB
2174 if (streq(name, "AllowIsolate"))
2175 return bus_set_transient_bool(u, name, &u->allow_isolate, message, flags, error);
52ad194e 2176
1d42b86d
MB
2177 if (streq(name, "DefaultDependencies"))
2178 return bus_set_transient_bool(u, name, &u->default_dependencies, message, flags, error);
2179
8b3d4ff0
MB
2180 if (streq(name, "OnSuccessJobMode"))
2181 return bus_set_transient_job_mode(u, name, &u->on_success_job_mode, message, flags, error);
2182
1d42b86d
MB
2183 if (streq(name, "OnFailureJobMode"))
2184 return bus_set_transient_job_mode(u, name, &u->on_failure_job_mode, message, flags, error);
2185
2186 if (streq(name, "IgnoreOnIsolate"))
2187 return bus_set_transient_bool(u, name, &u->ignore_on_isolate, message, flags, error);
2188
2189 if (streq(name, "JobTimeoutUSec")) {
2190 r = bus_set_transient_usec_fix_0(u, name, &u->job_timeout, message, flags, error);
2191 if (r >= 0 && !UNIT_WRITE_FLAGS_NOOP(flags) && !u->job_running_timeout_set)
2192 u->job_running_timeout = u->job_timeout;
2193 }
2194
2195 if (streq(name, "JobRunningTimeoutUSec")) {
2196 r = bus_set_transient_usec_fix_0(u, name, &u->job_running_timeout, message, flags, error);
2197 if (r >= 0 && !UNIT_WRITE_FLAGS_NOOP(flags))
2198 u->job_running_timeout_set = true;
2199
2200 return r;
2201 }
2202
2203 if (streq(name, "JobTimeoutAction"))
2204 return bus_set_transient_emergency_action(u, name, &u->job_timeout_action, message, flags, error);
2205
2206 if (streq(name, "JobTimeoutRebootArgument"))
2207 return bus_set_transient_string(u, name, &u->job_timeout_reboot_arg, message, flags, error);
2208
2209 if (streq(name, "StartLimitIntervalUSec"))
e1f67bc7 2210 return bus_set_transient_usec(u, name, &u->start_ratelimit.interval, message, flags, error);
1d42b86d
MB
2211
2212 if (streq(name, "StartLimitBurst"))
e1f67bc7 2213 return bus_set_transient_unsigned(u, name, &u->start_ratelimit.burst, message, flags, error);
1d42b86d
MB
2214
2215 if (streq(name, "StartLimitAction"))
2216 return bus_set_transient_emergency_action(u, name, &u->start_limit_action, message, flags, error);
2217
2218 if (streq(name, "FailureAction"))
2219 return bus_set_transient_emergency_action(u, name, &u->failure_action, message, flags, error);
2220
2221 if (streq(name, "SuccessAction"))
2222 return bus_set_transient_emergency_action(u, name, &u->success_action, message, flags, error);
2223
6e866b33
MB
2224 if (streq(name, "FailureActionExitStatus"))
2225 return bus_set_transient_exit_status(u, name, &u->failure_action_exit_status, message, flags, error);
2226
2227 if (streq(name, "SuccessActionExitStatus"))
2228 return bus_set_transient_exit_status(u, name, &u->success_action_exit_status, message, flags, error);
2229
1d42b86d
MB
2230 if (streq(name, "RebootArgument"))
2231 return bus_set_transient_string(u, name, &u->reboot_arg, message, flags, error);
2232
2233 if (streq(name, "CollectMode"))
2234 return bus_set_transient_collect_mode(u, name, &u->collect_mode, message, flags, error);
2235
2236 if (streq(name, "Conditions"))
2237 return bus_set_transient_conditions(u, name, &u->conditions, true, message, flags, error);
2238
2239 if (streq(name, "Asserts"))
2240 return bus_set_transient_conditions(u, name, &u->asserts, false, message, flags, error);
2241
2242 if (streq(name, "Documentation")) {
2243 _cleanup_strv_free_ char **l = NULL;
2244 char **p;
2245
2246 r = sd_bus_message_read_strv(message, &l);
52ad194e
MB
2247 if (r < 0)
2248 return r;
2249
1d42b86d
MB
2250 STRV_FOREACH(p, l) {
2251 if (!documentation_url_is_valid(*p))
2252 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid URL in %s: %s", name, *p);
2253 }
52ad194e
MB
2254
2255 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1d42b86d
MB
2256 if (strv_isempty(l)) {
2257 u->documentation = strv_free(u->documentation);
2258 unit_write_settingf(u, flags, name, "%s=", name);
2259 } else {
2260 strv_extend_strv(&u->documentation, l, false);
2261
2262 STRV_FOREACH(p, l)
2263 unit_write_settingf(u, flags, name, "%s=%s", name, *p);
2264 }
e735f4d4
MP
2265 }
2266
2267 return 1;
663996b3 2268
d9dfd233
MP
2269 } else if (streq(name, "Slice")) {
2270 Unit *slice;
14228c0d 2271 const char *s;
663996b3 2272
d9dfd233 2273 if (!UNIT_HAS_CGROUP_CONTEXT(u))
8b3d4ff0 2274 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups.");
d9dfd233 2275 if (u->type == UNIT_SLICE)
8b3d4ff0 2276 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units.");
d9dfd233 2277 if (unit_has_name(u, SPECIAL_INIT_SCOPE))
8b3d4ff0 2278 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope");
d9dfd233 2279
60f067b4
JS
2280 r = sd_bus_message_read(message, "s", &s);
2281 if (r < 0)
2282 return r;
663996b3 2283
d9dfd233
MP
2284 if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
2285 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s);
663996b3 2286
aa27b158
MP
2287 /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be
2288 * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare()
2289 * instead of manager_load_unit() on purpose, here. */
2290 r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice);
d9dfd233
MP
2291 if (r < 0)
2292 return r;
663996b3 2293
d9dfd233
MP
2294 if (slice->type != UNIT_SLICE)
2295 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s);
2296
52ad194e 2297 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
ea0999c9 2298 r = unit_set_slice(u, slice);
14228c0d
MB
2299 if (r < 0)
2300 return r;
663996b3 2301
52ad194e 2302 unit_write_settingf(u, flags|UNIT_PRIVATE, name, "Slice=%s", s);
14228c0d 2303 }
663996b3 2304
14228c0d 2305 return 1;
d9dfd233 2306
1d42b86d
MB
2307 } else if (streq(name, "RequiresMountsFor")) {
2308 _cleanup_strv_free_ char **l = NULL;
2309 char **p;
2310
2311 r = sd_bus_message_read_strv(message, &l);
2312 if (r < 0)
2313 return r;
2314
2315 STRV_FOREACH(p, l) {
8b3d4ff0 2316 path_simplify(*p);
bb4f798a 2317
1d42b86d
MB
2318 if (!path_is_absolute(*p))
2319 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path specified in %s is not absolute: %s", name, *p);
2320
bb4f798a
MB
2321 if (!path_is_valid(*p))
2322 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path specified in %s has invalid length: %s", name, *p);
2323
2324 if (!path_is_normalized(*p))
2325 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path specified in %s is not normalized: %s", name, *p);
2326
1d42b86d
MB
2327 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2328 r = unit_require_mounts_for(u, *p, UNIT_DEPENDENCY_FILE);
2329 if (r < 0)
2330 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to add required mount \"%s\": %m", *p);
14228c0d 2331
1d42b86d
MB
2332 unit_write_settingf(u, flags, name, "%s=%s", name, *p);
2333 }
db2df898 2334 }
663996b3 2335
1d42b86d
MB
2336 return 1;
2337 }
2338
2339 if (streq(name, "RequiresOverridable"))
2340 d = UNIT_REQUIRES; /* redirect for obsolete unit dependency type */
2341 else if (streq(name, "RequisiteOverridable"))
2342 d = UNIT_REQUISITE; /* same here */
2343 else
2344 d = unit_dependency_from_string(name);
2345
2346 if (d >= 0) {
2347 const char *other;
2348
97e5042f
MB
2349 if (!IN_SET(d,
2350 UNIT_REQUIRES,
2351 UNIT_REQUISITE,
2352 UNIT_WANTS,
2353 UNIT_BINDS_TO,
2354 UNIT_PART_OF,
8b3d4ff0 2355 UNIT_UPHOLDS,
97e5042f
MB
2356 UNIT_CONFLICTS,
2357 UNIT_BEFORE,
2358 UNIT_AFTER,
8b3d4ff0 2359 UNIT_ON_SUCCESS,
97e5042f
MB
2360 UNIT_ON_FAILURE,
2361 UNIT_PROPAGATES_RELOAD_TO,
2362 UNIT_RELOAD_PROPAGATED_FROM,
8b3d4ff0
MB
2363 UNIT_PROPAGATES_STOP_TO,
2364 UNIT_STOP_PROPAGATED_FROM,
97e5042f
MB
2365 UNIT_JOINS_NAMESPACE_OF))
2366 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Dependency type %s may not be created transiently.", unit_dependency_to_string(d));
2367
60f067b4
JS
2368 r = sd_bus_message_enter_container(message, 'a', "s");
2369 if (r < 0)
2370 return r;
663996b3 2371
60f067b4 2372 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
e3bff60a 2373 if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
60f067b4 2374 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
663996b3 2375
52ad194e 2376 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
14228c0d 2377 _cleanup_free_ char *label = NULL;
663996b3 2378
6e866b33 2379 r = unit_add_dependency_by_name(u, d, other, true, UNIT_DEPENDENCY_FILE);
14228c0d
MB
2380 if (r < 0)
2381 return r;
663996b3 2382
2897b343 2383 label = strjoin(name, "-", other);
14228c0d
MB
2384 if (!label)
2385 return -ENOMEM;
663996b3 2386
1d42b86d 2387 unit_write_settingf(u, flags, label, "%s=%s", unit_dependency_to_string(d), other);
14228c0d 2388 }
663996b3 2389
14228c0d 2390 }
60f067b4
JS
2391 if (r < 0)
2392 return r;
2393
2394 r = sd_bus_message_exit_container(message);
2395 if (r < 0)
2396 return r;
663996b3 2397
14228c0d 2398 return 1;
8a584da2
MP
2399
2400 } else if (streq(name, "AddRef")) {
2401
2402 int b;
2403
2404 /* Why is this called "AddRef" rather than just "Ref", or "Reference"? There's already a "Ref()" method
2405 * on the Unit interface, and it's probably not a good idea to expose a property and a method on the
2406 * same interface (well, strictly speaking AddRef isn't exposed as full property, we just read it for
2407 * transient units, but still). And "References" and "ReferencedBy" is already used as unit reference
2408 * dependency type, hence let's not confuse things with that.
2409 *
f2dec872 2410 * Note that we don't actually add the reference to the bus track. We do that only after the setup of
8a584da2
MP
2411 * the transient unit is complete, so that setting this property multiple times in the same transient
2412 * unit creation call doesn't count as individual references. */
2413
2414 r = sd_bus_message_read(message, "b", &b);
2415 if (r < 0)
2416 return r;
2417
52ad194e 2418 if (!UNIT_WRITE_FLAGS_NOOP(flags))
8a584da2
MP
2419 u->bus_track_add = b;
2420
2421 return 1;
663996b3
MS
2422 }
2423
2424 return 0;
2425}
2426
14228c0d
MB
2427int bus_unit_set_properties(
2428 Unit *u,
60f067b4 2429 sd_bus_message *message,
52ad194e 2430 UnitWriteFlags flags,
14228c0d 2431 bool commit,
60f067b4 2432 sd_bus_error *error) {
14228c0d
MB
2433
2434 bool for_real = false;
14228c0d 2435 unsigned n = 0;
663996b3
MS
2436 int r;
2437
2438 assert(u);
60f067b4 2439 assert(message);
663996b3 2440
14228c0d
MB
2441 /* We iterate through the array twice. First run we just check
2442 * if all passed data is valid, second run actually applies
2443 * it. This is to implement transaction-like behaviour without
2444 * actually providing full transactions. */
663996b3 2445
60f067b4
JS
2446 r = sd_bus_message_enter_container(message, 'a', "(sv)");
2447 if (r < 0)
2448 return r;
663996b3 2449
14228c0d 2450 for (;;) {
14228c0d 2451 const char *name;
52ad194e 2452 UnitWriteFlags f;
663996b3 2453
60f067b4
JS
2454 r = sd_bus_message_enter_container(message, 'r', "sv");
2455 if (r < 0)
2456 return r;
2457 if (r == 0) {
52ad194e 2458 if (for_real || UNIT_WRITE_FLAGS_NOOP(flags))
14228c0d 2459 break;
663996b3 2460
14228c0d 2461 /* Reached EOF. Let's try again, and this time for realz... */
60f067b4
JS
2462 r = sd_bus_message_rewind(message, false);
2463 if (r < 0)
2464 return r;
2465
14228c0d 2466 for_real = true;
663996b3 2467 continue;
663996b3 2468 }
663996b3 2469
60f067b4
JS
2470 r = sd_bus_message_read(message, "s", &name);
2471 if (r < 0)
2472 return r;
663996b3 2473
60f067b4 2474 if (!UNIT_VTABLE(u)->bus_set_property)
3a6ce677
BR
2475 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY,
2476 "Objects of this type do not support setting properties.");
663996b3 2477
60f067b4
JS
2478 r = sd_bus_message_enter_container(message, 'v', NULL);
2479 if (r < 0)
2480 return r;
663996b3 2481
52ad194e
MB
2482 /* If not for real, then mask out the two target flags */
2483 f = for_real ? flags : (flags & ~(UNIT_RUNTIME|UNIT_PERSISTENT));
2484
2485 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, f, error);
14228c0d 2486 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
52ad194e
MB
2487 r = bus_unit_set_transient_property(u, name, message, f, error);
2488 if (r == 0)
2489 r = bus_unit_set_live_property(u, name, message, f, error);
663996b3
MS
2490 if (r < 0)
2491 return r;
52ad194e 2492
60f067b4 2493 if (r == 0)
3a6ce677
BR
2494 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY,
2495 "Cannot set property %s, or unknown property.", name);
663996b3 2496
60f067b4
JS
2497 r = sd_bus_message_exit_container(message);
2498 if (r < 0)
2499 return r;
2500
2501 r = sd_bus_message_exit_container(message);
2502 if (r < 0)
2503 return r;
663996b3 2504
14228c0d
MB
2505 n += for_real;
2506 }
663996b3 2507
60f067b4
JS
2508 r = sd_bus_message_exit_container(message);
2509 if (r < 0)
2510 return r;
2511
14228c0d
MB
2512 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
2513 UNIT_VTABLE(u)->bus_commit_properties(u);
663996b3 2514
14228c0d 2515 return n;
663996b3 2516}
4c89c718 2517
b012e921 2518int bus_unit_validate_load_state(Unit *u, sd_bus_error *error) {
aa27b158 2519 assert(u);
4c89c718 2520
b012e921 2521 /* Generates a pretty error if a unit isn't properly loaded. */
4c89c718 2522
b012e921
MB
2523 switch (u->load_state) {
2524
2525 case UNIT_LOADED:
2526 return 0;
4c89c718 2527
b012e921 2528 case UNIT_NOT_FOUND:
4c89c718
MP
2529 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not found.", u->id);
2530
b012e921
MB
2531 case UNIT_BAD_SETTING:
2532 return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING, "Unit %s has a bad unit file setting.", u->id);
2533
2534 case UNIT_ERROR: /* Only show .load_error in UNIT_ERROR state */
3a6ce677
BR
2535 return sd_bus_error_set_errnof(error, u->load_error,
2536 "Unit %s failed to load properly, please adjust/correct and reload service manager: %m", u->id);
b012e921
MB
2537
2538 case UNIT_MASKED:
2539 return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id);
2540
2541 case UNIT_STUB:
2542 case UNIT_MERGED:
2543 default:
2544 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unexpected load state of unit %s", u->id);
2545 }
4c89c718 2546}
8a584da2 2547
2897b343 2548static int bus_unit_track_handler(sd_bus_track *t, void *userdata) {
8a584da2
MP
2549 Unit *u = userdata;
2550
2551 assert(t);
2552 assert(u);
2553
2554 u->bus_track = sd_bus_track_unref(u->bus_track); /* make sure we aren't called again */
2555
6e866b33
MB
2556 /* If the client that tracks us disappeared, then there's reason to believe that the cgroup is empty now too,
2557 * let's see */
2558 unit_add_to_cgroup_empty_queue(u);
2559
2560 /* Also add the unit to the GC queue, after all if the client left it might be time to GC this unit */
8a584da2 2561 unit_add_to_gc_queue(u);
6e866b33 2562
8a584da2
MP
2563 return 0;
2564}
2565
2897b343 2566static int bus_unit_allocate_bus_track(Unit *u) {
8a584da2
MP
2567 int r;
2568
2569 assert(u);
2570
2571 if (u->bus_track)
2572 return 0;
2573
2897b343 2574 r = sd_bus_track_new(u->manager->api_bus, &u->bus_track, bus_unit_track_handler, u);
8a584da2
MP
2575 if (r < 0)
2576 return r;
2577
2578 r = sd_bus_track_set_recursive(u->bus_track, true);
2579 if (r < 0) {
2580 u->bus_track = sd_bus_track_unref(u->bus_track);
2581 return r;
2582 }
2583
2584 return 0;
2585}
2586
2587int bus_unit_track_add_name(Unit *u, const char *name) {
2588 int r;
2589
2590 assert(u);
2591
2897b343 2592 r = bus_unit_allocate_bus_track(u);
8a584da2
MP
2593 if (r < 0)
2594 return r;
2595
2596 return sd_bus_track_add_name(u->bus_track, name);
2597}
2598
2599int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) {
2600 int r;
2601
2602 assert(u);
2603
2897b343 2604 r = bus_unit_allocate_bus_track(u);
8a584da2
MP
2605 if (r < 0)
2606 return r;
2607
2608 return sd_bus_track_add_sender(u->bus_track, m);
2609}
2610
2611int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) {
2612 assert(u);
2613
3a6ce677
BR
2614 /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet,
2615 * return an error */
8a584da2
MP
2616 if (!u->bus_track)
2617 return -EUNATCH;
2618
2619 return sd_bus_track_remove_sender(u->bus_track, m);
2620}