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