]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-manager.c
Merge pull request #1490 from poettering/machinectl-shell-race-fix
[thirdparty/systemd.git] / src / core / dbus-manager.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ea430986 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ea430986 22#include <errno.h>
871c44a7 23#include <unistd.h>
ea430986 24
ea430986 25#include "log.h"
1137a57c 26#include "strv.h"
09bde77f 27#include "build.h"
c0576cd6 28#include "install.h"
e2417e41 29#include "selinux-access.h"
c757a65b 30#include "watchdog.h"
24efb112 31#include "clock-util.h"
664f88a7 32#include "path-util.h"
dfae3488 33#include "virt.h"
7452394e 34#include "architecture.h"
4d1a6904 35#include "env-util.h"
718db961 36#include "dbus.h"
2ea31e5b 37#include "dbus-job.h"
718db961
LP
38#include "dbus-manager.h"
39#include "dbus-unit.h"
40#include "dbus-snapshot.h"
718db961 41#include "dbus-execute.h"
96aad8d1 42#include "bus-common-errors.h"
6482f626 43#include "formats-util.h"
ea430986 44
718db961
LP
45static int property_get_version(
46 sd_bus *bus,
47 const char *path,
48 const char *interface,
49 const char *property,
50 sd_bus_message *reply,
ebcf1f97
LP
51 void *userdata,
52 sd_bus_error *error) {
718db961
LP
53
54 assert(bus);
55 assert(reply);
56
57 return sd_bus_message_append(reply, "s", PACKAGE_VERSION);
58}
c5d34390 59
718db961
LP
60static int property_get_features(
61 sd_bus *bus,
62 const char *path,
63 const char *interface,
64 const char *property,
65 sd_bus_message *reply,
ebcf1f97
LP
66 void *userdata,
67 sd_bus_error *error) {
718db961
LP
68
69 assert(bus);
70 assert(reply);
71
72 return sd_bus_message_append(reply, "s", SYSTEMD_FEATURES);
73}
74
75static int property_get_virtualization(
76 sd_bus *bus,
77 const char *path,
78 const char *interface,
79 const char *property,
80 sd_bus_message *reply,
ebcf1f97
LP
81 void *userdata,
82 sd_bus_error *error) {
718db961 83
5c22925a
LP
84 int v;
85
718db961
LP
86 assert(bus);
87 assert(reply);
88
5c22925a
LP
89 v = detect_virtualization();
90
91 /* Make sure to return the empty string when we detect no virtualization, as that is the API.
92 *
93 * https://github.com/systemd/systemd/issues/1423
94 */
95
96 return sd_bus_message_append(
97 reply, "s",
98 v == VIRTUALIZATION_NONE ? "" : virtualization_to_string(v));
718db961
LP
99}
100
7452394e
LP
101static int property_get_architecture(
102 sd_bus *bus,
103 const char *path,
104 const char *interface,
105 const char *property,
106 sd_bus_message *reply,
107 void *userdata,
108 sd_bus_error *error) {
109
110 assert(bus);
111 assert(reply);
112
113 return sd_bus_message_append(reply, "s", architecture_to_string(uname_architecture()));
114}
115
718db961
LP
116static int property_get_tainted(
117 sd_bus *bus,
118 const char *path,
119 const char *interface,
120 const char *property,
121 sd_bus_message *reply,
ebcf1f97
LP
122 void *userdata,
123 sd_bus_error *error) {
718db961 124
ebcf1f97 125 char buf[sizeof("split-usr:mtab-not-symlink:cgroups-missing:local-hwclock:")] = "", *e = buf;
718db961
LP
126 _cleanup_free_ char *p = NULL;
127 Manager *m = userdata;
128
129 assert(bus);
130 assert(reply);
bfebab7f 131 assert(m);
c5d34390 132
72bc8d00 133 if (m->taint_usr)
e677bf7e 134 e = stpcpy(e, "split-usr:");
c5d34390 135
871c44a7 136 if (readlink_malloc("/etc/mtab", &p) < 0)
e677bf7e 137 e = stpcpy(e, "mtab-not-symlink:");
c5d34390 138
871c44a7 139 if (access("/proc/cgroups", F_OK) < 0)
1ebf0cb7 140 e = stpcpy(e, "cgroups-missing:");
871c44a7 141
24efb112 142 if (clock_is_localtime() > 0)
1ebf0cb7 143 e = stpcpy(e, "local-hwclock:");
e677bf7e 144
1ebf0cb7
MS
145 /* remove the last ':' */
146 if (e != buf)
147 e[-1] = 0;
e677bf7e 148
718db961 149 return sd_bus_message_append(reply, "s", buf);
c5d34390
LP
150}
151
718db961
LP
152static int property_get_log_target(
153 sd_bus *bus,
154 const char *path,
155 const char *interface,
156 const char *property,
157 sd_bus_message *reply,
ebcf1f97
LP
158 void *userdata,
159 sd_bus_error *error) {
1adf1049 160
718db961
LP
161 assert(bus);
162 assert(reply);
1adf1049 163
718db961 164 return sd_bus_message_append(reply, "s", log_target_to_string(log_get_target()));
1adf1049
LP
165}
166
718db961
LP
167static int property_set_log_target(
168 sd_bus *bus,
169 const char *path,
170 const char *interface,
171 const char *property,
172 sd_bus_message *value,
ebcf1f97
LP
173 void *userdata,
174 sd_bus_error *error) {
718db961 175
c826cda4 176 const char *t;
718db961 177 int r;
c826cda4 178
718db961
LP
179 assert(bus);
180 assert(value);
c826cda4 181
718db961
LP
182 r = sd_bus_message_read(value, "s", &t);
183 if (r < 0)
184 return r;
c826cda4
AB
185
186 return log_set_target_from_string(t);
187}
188
718db961
LP
189static int property_get_log_level(
190 sd_bus *bus,
191 const char *path,
192 const char *interface,
193 const char *property,
194 sd_bus_message *reply,
ebcf1f97
LP
195 void *userdata,
196 sd_bus_error *error) {
718db961 197
68eda4bd 198 _cleanup_free_ char *t = NULL;
f8b69d1d 199 int r;
1adf1049 200
718db961
LP
201 assert(bus);
202 assert(reply);
1adf1049 203
f8b69d1d
MS
204 r = log_level_to_string_alloc(log_get_max_level(), &t);
205 if (r < 0)
206 return r;
1adf1049 207
718db961 208 return sd_bus_message_append(reply, "s", t);
1adf1049
LP
209}
210
718db961
LP
211static int property_set_log_level(
212 sd_bus *bus,
213 const char *path,
214 const char *interface,
215 const char *property,
216 sd_bus_message *value,
ebcf1f97
LP
217 void *userdata,
218 sd_bus_error *error) {
718db961 219
c826cda4 220 const char *t;
718db961 221 int r;
c826cda4 222
718db961
LP
223 assert(bus);
224 assert(value);
c826cda4 225
718db961
LP
226 r = sd_bus_message_read(value, "s", &t);
227 if (r < 0)
228 return r;
c826cda4
AB
229
230 return log_set_max_level_from_string(t);
231}
232
718db961
LP
233static int property_get_n_names(
234 sd_bus *bus,
235 const char *path,
236 const char *interface,
237 const char *property,
238 sd_bus_message *reply,
ebcf1f97
LP
239 void *userdata,
240 sd_bus_error *error) {
4f0f902f 241
718db961 242 Manager *m = userdata;
4f0f902f 243
718db961
LP
244 assert(bus);
245 assert(reply);
246 assert(m);
4f0f902f 247
718db961 248 return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->units));
4f0f902f
LP
249}
250
f755e3b7
LP
251static int property_get_n_failed_units(
252 sd_bus *bus,
253 const char *path,
254 const char *interface,
255 const char *property,
256 sd_bus_message *reply,
257 void *userdata,
258 sd_bus_error *error) {
259
260 Manager *m = userdata;
261
262 assert(bus);
263 assert(reply);
264 assert(m);
265
266 return sd_bus_message_append(reply, "u", (uint32_t) set_size(m->failed_units));
267}
268
718db961
LP
269static int property_get_n_jobs(
270 sd_bus *bus,
271 const char *path,
272 const char *interface,
273 const char *property,
274 sd_bus_message *reply,
ebcf1f97
LP
275 void *userdata,
276 sd_bus_error *error) {
4f0f902f 277
718db961 278 Manager *m = userdata;
4f0f902f 279
718db961
LP
280 assert(bus);
281 assert(reply);
282 assert(m);
4f0f902f 283
718db961 284 return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->jobs));
4f0f902f
LP
285}
286
718db961
LP
287static int property_get_progress(
288 sd_bus *bus,
289 const char *path,
290 const char *interface,
291 const char *property,
292 sd_bus_message *reply,
ebcf1f97
LP
293 void *userdata,
294 sd_bus_error *error) {
718db961
LP
295
296 Manager *m = userdata;
05d6a3b6
LP
297 double d;
298
718db961
LP
299 assert(bus);
300 assert(reply);
bfebab7f 301 assert(m);
05d6a3b6
LP
302
303 if (dual_timestamp_is_set(&m->finish_timestamp))
304 d = 1.0;
305 else
306 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
307
718db961
LP
308 return sd_bus_message_append(reply, "d", d);
309}
310
f755e3b7
LP
311static int property_get_system_state(
312 sd_bus *bus,
313 const char *path,
314 const char *interface,
315 const char *property,
316 sd_bus_message *reply,
317 void *userdata,
318 sd_bus_error *error) {
319
320 Manager *m = userdata;
321
322 assert(bus);
323 assert(reply);
324 assert(m);
325
326 return sd_bus_message_append(reply, "s", manager_state_to_string(manager_state(m)));
327}
328
718db961
LP
329static int property_set_runtime_watchdog(
330 sd_bus *bus,
331 const char *path,
332 const char *interface,
333 const char *property,
334 sd_bus_message *value,
ebcf1f97
LP
335 void *userdata,
336 sd_bus_error *error) {
05d6a3b6 337
718db961
LP
338 usec_t *t = userdata;
339 int r;
340
341 assert(bus);
342 assert(value);
343
344 assert_cc(sizeof(usec_t) == sizeof(uint64_t));
345
346 r = sd_bus_message_read(value, "t", t);
347 if (r < 0)
348 return r;
349
350 return watchdog_set_timeout(t);
05d6a3b6
LP
351}
352
19070062 353static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
354 _cleanup_free_ char *path = NULL;
355 Manager *m = userdata;
356 const char *name;
357 Unit *u;
358 int r;
dfae3488 359
718db961 360 assert(message);
dfae3488
LP
361 assert(m);
362
283868e1
SW
363 /* Anyone can call this method */
364
718db961
LP
365 r = sd_bus_message_read(message, "s", &name);
366 if (r < 0)
ebcf1f97 367 return r;
dfae3488 368
1d22e906
LP
369 if (isempty(name)) {
370 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
371 pid_t pid;
372
373 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
374 if (r < 0)
375 return r;
376
377 r = sd_bus_creds_get_pid(creds, &pid);
378 if (r < 0)
379 return r;
380
381 u = manager_get_unit_by_pid(m, pid);
382 if (!u)
383 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
384 } else {
385 u = manager_get_unit(m, name);
386 if (!u)
387 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
388 }
dfae3488 389
8a188de9 390 r = mac_selinux_unit_access_check(u, message, "status", error);
ebcf1f97
LP
391 if (r < 0)
392 return r;
dfae3488 393
718db961
LP
394 path = unit_dbus_path(u);
395 if (!path)
ebcf1f97 396 return -ENOMEM;
729e3769 397
df2d202e 398 return sd_bus_reply_method_return(message, "o", path);
718db961 399}
c0576cd6 400
19070062 401static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
402 _cleanup_free_ char *path = NULL;
403 Manager *m = userdata;
404 pid_t pid;
405 Unit *u;
406 int r;
c0576cd6 407
718db961
LP
408 assert(message);
409 assert(m);
c0576cd6 410
718db961 411 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
729e3769 412
283868e1
SW
413 /* Anyone can call this method */
414
718db961
LP
415 r = sd_bus_message_read(message, "u", &pid);
416 if (r < 0)
ebcf1f97 417 return r;
1d22e906
LP
418 if (pid < 0)
419 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PID " PID_FMT, pid);
718db961
LP
420
421 if (pid == 0) {
5b12334d
LP
422 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
423
424 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
425 if (r < 0)
426 return r;
427
428 r = sd_bus_creds_get_pid(creds, &pid);
718db961 429 if (r < 0)
ebcf1f97 430 return r;
729e3769
LP
431 }
432
718db961
LP
433 u = manager_get_unit_by_pid(m, pid);
434 if (!u)
1fa2f38f 435 return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID "PID_FMT" does not belong to any loaded unit.", pid);
c0576cd6 436
8a188de9 437 r = mac_selinux_unit_access_check(u, message, "status", error);
ebcf1f97
LP
438 if (r < 0)
439 return r;
718db961
LP
440
441 path = unit_dbus_path(u);
442 if (!path)
ebcf1f97 443 return -ENOMEM;
718db961 444
df2d202e 445 return sd_bus_reply_method_return(message, "o", path);
718db961
LP
446}
447
19070062 448static int method_load_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
449 _cleanup_free_ char *path = NULL;
450 Manager *m = userdata;
451 const char *name;
452 Unit *u;
453 int r;
c0576cd6 454
718db961
LP
455 assert(message);
456 assert(m);
457
283868e1
SW
458 /* Anyone can call this method */
459
718db961
LP
460 r = sd_bus_message_read(message, "s", &name);
461 if (r < 0)
ebcf1f97 462 return r;
c0576cd6 463
1d22e906
LP
464 if (isempty(name)) {
465 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
466 pid_t pid;
467
468 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
469 if (r < 0)
470 return r;
471
472 r = sd_bus_creds_get_pid(creds, &pid);
473 if (r < 0)
474 return r;
475
476 u = manager_get_unit_by_pid(m, pid);
477 if (!u)
478 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
479 } else {
480 r = manager_load_unit(m, name, NULL, error, &u);
481 if (r < 0)
482 return r;
483 }
718db961 484
8a188de9 485 r = mac_selinux_unit_access_check(u, message, "status", error);
ebcf1f97
LP
486 if (r < 0)
487 return r;
c0576cd6 488
718db961
LP
489 path = unit_dbus_path(u);
490 if (!path)
ebcf1f97 491 return -ENOMEM;
718db961 492
df2d202e 493 return sd_bus_reply_method_return(message, "o", path);
c0576cd6
LP
494}
495
19070062 496static int method_start_unit_generic(sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
718db961
LP
497 const char *name;
498 Unit *u;
c0576cd6
LP
499 int r;
500
718db961
LP
501 assert(message);
502 assert(m);
c0576cd6 503
718db961
LP
504 r = sd_bus_message_read(message, "s", &name);
505 if (r < 0)
ebcf1f97 506 return r;
c0576cd6 507
ebcf1f97 508 r = manager_load_unit(m, name, NULL, error, &u);
718db961 509 if (r < 0)
ebcf1f97 510 return r;
718db961 511
19070062 512 return bus_unit_method_start_generic(message, u, job_type, reload_if_possible, error);
c0576cd6
LP
513}
514
19070062
LP
515static int method_start_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
516 return method_start_unit_generic(message, userdata, JOB_START, false, error);
718db961 517}
c757a65b 518
19070062
LP
519static int method_stop_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
520 return method_start_unit_generic(message, userdata, JOB_STOP, false, error);
718db961 521}
c757a65b 522
19070062
LP
523static int method_reload_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
524 return method_start_unit_generic(message, userdata, JOB_RELOAD, false, error);
718db961 525}
c757a65b 526
19070062
LP
527static int method_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
528 return method_start_unit_generic(message, userdata, JOB_RESTART, false, error);
c757a65b
LP
529}
530
19070062
LP
531static int method_try_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
532 return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, false, error);
718db961 533}
d200735e 534
19070062
LP
535static int method_reload_or_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
536 return method_start_unit_generic(message, userdata, JOB_RESTART, true, error);
718db961 537}
d200735e 538
19070062
LP
539static int method_reload_or_try_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
540 return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, true, error);
718db961 541}
d200735e 542
19070062 543static int method_start_unit_replace(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
544 Manager *m = userdata;
545 const char *old_name;
546 Unit *u;
1adf1049 547 int r;
ea430986 548
ea430986
LP
549 assert(message);
550 assert(m);
551
718db961
LP
552 r = sd_bus_message_read(message, "s", &old_name);
553 if (r < 0)
ebcf1f97 554 return r;
ea430986 555
718db961
LP
556 u = manager_get_unit(m, old_name);
557 if (!u || !u->job || u->job->type != JOB_START)
ebcf1f97 558 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
c0576cd6 559
19070062 560 return method_start_unit_generic(message, m, JOB_START, false, error);
718db961 561}
ea430986 562
19070062 563static int method_kill_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
564 Manager *m = userdata;
565 const char *name;
566 Unit *u;
567 int r;
ea430986 568
718db961
LP
569 assert(message);
570 assert(m);
ea430986 571
718db961
LP
572 r = sd_bus_message_read(message, "s", &name);
573 if (r < 0)
ebcf1f97 574 return r;
598b557b 575
718db961
LP
576 u = manager_get_unit(m, name);
577 if (!u)
ebcf1f97 578 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
0a524ba7 579
19070062 580 return bus_unit_method_kill(message, u, error);
718db961 581}
8a0867d6 582
19070062 583static int method_reset_failed_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
584 Manager *m = userdata;
585 const char *name;
586 Unit *u;
587 int r;
8a0867d6 588
718db961
LP
589 assert(message);
590 assert(m);
cad45ba1 591
718db961
LP
592 r = sd_bus_message_read(message, "s", &name);
593 if (r < 0)
ebcf1f97 594 return r;
ea430986 595
718db961
LP
596 u = manager_get_unit(m, name);
597 if (!u)
ebcf1f97 598 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
5dd9014f 599
19070062 600 return bus_unit_method_reset_failed(message, u, error);
718db961 601}
5dd9014f 602
19070062 603static int method_set_unit_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
604 Manager *m = userdata;
605 const char *name;
606 Unit *u;
607 int r;
5dd9014f 608
718db961
LP
609 assert(message);
610 assert(m);
611
612 r = sd_bus_message_read(message, "s", &name);
613 if (r < 0)
ebcf1f97 614 return r;
718db961
LP
615
616 u = manager_get_unit(m, name);
617 if (!u)
ebcf1f97 618 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
ea430986 619
19070062 620 return bus_unit_method_set_properties(message, u, error);
718db961
LP
621}
622
ab31f6b8
WC
623static int transient_unit_from_message(
624 Manager *m,
625 sd_bus_message *message,
626 const char *name,
627 Unit **unit,
628 sd_bus_error *error) {
629
630 Unit *u;
631 int r;
632
633 assert(m);
634 assert(message);
635 assert(name);
636
637 r = manager_load_unit(m, name, NULL, error, &u);
638 if (r < 0)
639 return r;
640
641 if (u->load_state != UNIT_NOT_FOUND ||
642 set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0)
643 return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
644
645 /* OK, the unit failed to load and is unreferenced, now let's
646 * fill in the transient data instead */
647 r = unit_make_transient(u);
648 if (r < 0)
649 return r;
650
651 /* Set our properties */
652 r = bus_unit_set_properties(u, message, UNIT_RUNTIME, false, error);
653 if (r < 0)
654 return r;
655
656 *unit = u;
657
658 return 0;
659}
660
661static int transient_aux_units_from_message(
662 Manager *m,
663 sd_bus_message *message,
664 sd_bus_error *error) {
665
666 Unit *u;
667 char *name = NULL;
668 int r;
669
670 assert(m);
671 assert(message);
672
673 r = sd_bus_message_enter_container(message, 'a', "(sa(sv))");
674 if (r < 0)
675 return r;
676
677 while ((r = sd_bus_message_enter_container(message, 'r', "sa(sv)")) > 0) {
ab31f6b8
WC
678 r = sd_bus_message_read(message, "s", &name);
679 if (r < 0)
680 return r;
681
682 r = transient_unit_from_message(m, message, name, &u, error);
683 if (r < 0 && r != -EEXIST)
684 return r;
685
4c213d6c
WC
686 if (r != -EEXIST) {
687 r = unit_load(u);
688 if (r < 0)
689 return r;
690 }
ab31f6b8
WC
691
692 r = sd_bus_message_exit_container(message);
693 if (r < 0)
694 return r;
695 }
696 if (r < 0)
697 return r;
698
699 r = sd_bus_message_exit_container(message);
700 if (r < 0)
701 return r;
702
703 return 0;
704}
705
19070062 706static int method_start_transient_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
707 const char *name, *smode;
708 Manager *m = userdata;
709 JobMode mode;
710 UnitType t;
711 Unit *u;
712 int r;
ea430986 713
718db961
LP
714 assert(message);
715 assert(m);
ea430986 716
1d22e906 717 r = mac_selinux_access_check(message, "start", error);
283868e1
SW
718 if (r < 0)
719 return r;
283868e1 720
718db961
LP
721 r = sd_bus_message_read(message, "ss", &name, &smode);
722 if (r < 0)
ebcf1f97 723 return r;
5632e374 724
718db961
LP
725 t = unit_name_to_type(name);
726 if (t < 0)
ebcf1f97 727 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type.");
cad45ba1 728
718db961 729 if (!unit_vtable[t]->can_transient)
d14ab08b 730 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
5632e374 731
718db961
LP
732 mode = job_mode_from_string(smode);
733 if (mode < 0)
ebcf1f97 734 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode);
5632e374 735
1d22e906 736 r = bus_verify_manage_units_async(m, message, error);
718db961 737 if (r < 0)
ebcf1f97 738 return r;
1d22e906
LP
739 if (r == 0)
740 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
5632e374 741
ab31f6b8 742 r = transient_unit_from_message(m, message, name, &u, error);
ebcf1f97
LP
743 if (r < 0)
744 return r;
5632e374 745
ab31f6b8 746 r = transient_aux_units_from_message(m, message, error);
718db961 747 if (r < 0)
ebcf1f97 748 return r;
ea430986 749
718db961
LP
750 /* And load this stub fully */
751 r = unit_load(u);
752 if (r < 0)
ebcf1f97 753 return r;
ea430986 754
718db961 755 manager_dispatch_load_queue(m);
cad45ba1 756
718db961 757 /* Finally, start it */
19070062 758 return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
718db961 759}
ea430986 760
19070062 761static int method_get_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
762 _cleanup_free_ char *path = NULL;
763 Manager *m = userdata;
764 uint32_t id;
765 Job *j;
766 int r;
ea430986 767
718db961
LP
768 assert(message);
769 assert(m);
ea430986 770
283868e1
SW
771 /* Anyone can call this method */
772
718db961
LP
773 r = sd_bus_message_read(message, "u", &id);
774 if (r < 0)
ebcf1f97 775 return r;
ea430986 776
718db961
LP
777 j = manager_get_job(m, id);
778 if (!j)
ebcf1f97 779 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
ea430986 780
8a188de9 781 r = mac_selinux_unit_access_check(j->unit, message, "status", error);
ebcf1f97
LP
782 if (r < 0)
783 return r;
ea430986 784
718db961
LP
785 path = job_dbus_path(j);
786 if (!path)
ebcf1f97 787 return -ENOMEM;
ea430986 788
df2d202e 789 return sd_bus_reply_method_return(message, "o", path);
718db961 790}
ea430986 791
19070062 792static int method_cancel_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
793 Manager *m = userdata;
794 uint32_t id;
795 Job *j;
796 int r;
ea430986 797
718db961
LP
798 assert(message);
799 assert(m);
ea430986 800
718db961
LP
801 r = sd_bus_message_read(message, "u", &id);
802 if (r < 0)
ebcf1f97 803 return r;
ea430986 804
718db961
LP
805 j = manager_get_job(m, id);
806 if (!j)
ebcf1f97 807 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
ea430986 808
19070062 809 return bus_job_method_cancel(message, j, error);
718db961 810}
c1e1601e 811
19070062 812static int method_clear_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 813 Manager *m = userdata;
ebcf1f97 814 int r;
c1e1601e 815
718db961
LP
816 assert(message);
817 assert(m);
c1e1601e 818
1d22e906 819 r = mac_selinux_access_check(message, "reload", error);
ebcf1f97
LP
820 if (r < 0)
821 return r;
822
1d22e906
LP
823 r = bus_verify_manage_units_async(m, message, error);
824 if (r < 0)
825 return r;
826 if (r == 0)
827 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
828
718db961 829 manager_clear_jobs(m);
c1e1601e 830
df2d202e 831 return sd_bus_reply_method_return(message, NULL);
718db961 832}
c1e1601e 833
19070062 834static int method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 835 Manager *m = userdata;
ebcf1f97 836 int r;
cad45ba1 837
718db961
LP
838 assert(message);
839 assert(m);
840
8a188de9 841 r = mac_selinux_access_check(message, "reload", error);
ebcf1f97
LP
842 if (r < 0)
843 return r;
844
1d22e906
LP
845 r = bus_verify_manage_units_async(m, message, error);
846 if (r < 0)
847 return r;
848 if (r == 0)
849 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
850
718db961 851 manager_reset_failed(m);
c1e1601e 852
df2d202e 853 return sd_bus_reply_method_return(message, NULL);
718db961 854}
c1e1601e 855
19070062 856static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states) {
718db961
LP
857 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
858 Manager *m = userdata;
859 const char *k;
860 Iterator i;
861 Unit *u;
862 int r;
c1e1601e 863
718db961
LP
864 assert(message);
865 assert(m);
b152adec 866
283868e1
SW
867 /* Anyone can call this method */
868
8a188de9 869 r = mac_selinux_access_check(message, "status", error);
ebcf1f97
LP
870 if (r < 0)
871 return r;
cad45ba1 872
df2d202e 873 r = sd_bus_message_new_method_return(message, &reply);
718db961 874 if (r < 0)
ebcf1f97 875 return r;
b152adec 876
718db961
LP
877 r = sd_bus_message_open_container(reply, 'a', "(ssssssouso)");
878 if (r < 0)
ebcf1f97 879 return r;
b152adec 880
718db961
LP
881 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
882 _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
883 Unit *following;
b152adec 884
718db961
LP
885 if (k != u->id)
886 continue;
b152adec 887
718db961 888 following = unit_following(u);
b152adec 889
cdc06ed7
DS
890 if (!strv_isempty(states) &&
891 !strv_contains(states, unit_load_state_to_string(u->load_state)) &&
892 !strv_contains(states, unit_active_state_to_string(unit_active_state(u))) &&
893 !strv_contains(states, unit_sub_state_to_string(u)))
894 continue;
895
718db961
LP
896 unit_path = unit_dbus_path(u);
897 if (!unit_path)
ebcf1f97 898 return -ENOMEM;
718db961
LP
899
900 if (u->job) {
901 job_path = job_dbus_path(u->job);
902 if (!job_path)
ebcf1f97 903 return -ENOMEM;
b152adec
LP
904 }
905
718db961
LP
906 r = sd_bus_message_append(
907 reply, "(ssssssouso)",
908 u->id,
909 unit_description(u),
910 unit_load_state_to_string(u->load_state),
911 unit_active_state_to_string(unit_active_state(u)),
912 unit_sub_state_to_string(u),
913 following ? following->id : "",
914 unit_path,
915 u->job ? u->job->id : 0,
916 u->job ? job_type_to_string(u->job->type) : "",
917 job_path ? job_path : "/");
918 if (r < 0)
ebcf1f97 919 return r;
718db961 920 }
4139c1b2 921
718db961
LP
922 r = sd_bus_message_close_container(reply);
923 if (r < 0)
ebcf1f97 924 return r;
cad45ba1 925
9030ca46 926 return sd_bus_send(NULL, reply, NULL);
718db961 927}
4139c1b2 928
19070062
LP
929static int method_list_units(sd_bus_message *message, void *userdata, sd_bus_error *error) {
930 return list_units_filtered(message, userdata, error, NULL);
cdc06ed7
DS
931}
932
19070062 933static int method_list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cdc06ed7
DS
934 _cleanup_strv_free_ char **states = NULL;
935 int r;
936
937 r = sd_bus_message_read_strv(message, &states);
938 if (r < 0)
939 return r;
940
19070062 941 return list_units_filtered(message, userdata, error, states);
cdc06ed7
DS
942}
943
19070062 944static int method_list_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
945 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
946 Manager *m = userdata;
947 Iterator i;
948 Job *j;
949 int r;
4139c1b2 950
718db961
LP
951 assert(message);
952 assert(m);
953
283868e1
SW
954 /* Anyone can call this method */
955
8a188de9 956 r = mac_selinux_access_check(message, "status", error);
ebcf1f97
LP
957 if (r < 0)
958 return r;
718db961 959
df2d202e 960 r = sd_bus_message_new_method_return(message, &reply);
718db961 961 if (r < 0)
ebcf1f97 962 return r;
718db961
LP
963
964 r = sd_bus_message_open_container(reply, 'a', "(usssoo)");
965 if (r < 0)
ebcf1f97 966 return r;
718db961
LP
967
968 HASHMAP_FOREACH(j, m->jobs, i) {
969 _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
970
971 job_path = job_dbus_path(j);
972 if (!job_path)
ebcf1f97 973 return -ENOMEM;
718db961
LP
974
975 unit_path = unit_dbus_path(j->unit);
976 if (!unit_path)
ebcf1f97 977 return -ENOMEM;
718db961
LP
978
979 r = sd_bus_message_append(
980 reply, "(usssoo)",
981 j->id,
1302759d 982 j->unit->id,
718db961 983 job_type_to_string(j->type),
1302759d 984 job_state_to_string(j->state),
718db961
LP
985 job_path,
986 unit_path);
cad45ba1 987 if (r < 0)
ebcf1f97 988 return r;
718db961 989 }
5dd9014f 990
718db961
LP
991 r = sd_bus_message_close_container(reply);
992 if (r < 0)
ebcf1f97 993 return r;
5dd9014f 994
9030ca46 995 return sd_bus_send(NULL, reply, NULL);
718db961 996}
5dd9014f 997
19070062 998static int method_subscribe(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
999 Manager *m = userdata;
1000 int r;
5dd9014f 1001
718db961
LP
1002 assert(message);
1003 assert(m);
ea430986 1004
283868e1
SW
1005 /* Anyone can call this method */
1006
8a188de9 1007 r = mac_selinux_access_check(message, "status", error);
ebcf1f97
LP
1008 if (r < 0)
1009 return r;
cad45ba1 1010
19070062 1011 if (sd_bus_message_get_bus(message) == m->api_bus) {
8f8f05a9
LP
1012
1013 /* Note that direct bus connection subscribe by
1014 * default, we only track peers on the API bus here */
1015
1016 if (!m->subscribed) {
19070062 1017 r = sd_bus_track_new(sd_bus_message_get_bus(message), &m->subscribed, NULL, NULL);
8f8f05a9
LP
1018 if (r < 0)
1019 return r;
1020 }
1021
1022 r = sd_bus_track_add_sender(m->subscribed, message);
1023 if (r < 0)
1024 return r;
1025 if (r == 0)
1026 return sd_bus_error_setf(error, BUS_ERROR_ALREADY_SUBSCRIBED, "Client is already subscribed.");
1027 }
ea430986 1028
df2d202e 1029 return sd_bus_reply_method_return(message, NULL);
718db961 1030}
ea430986 1031
19070062 1032static int method_unsubscribe(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1033 Manager *m = userdata;
1034 int r;
ea430986 1035
718db961
LP
1036 assert(message);
1037 assert(m);
ea430986 1038
283868e1
SW
1039 /* Anyone can call this method */
1040
8a188de9 1041 r = mac_selinux_access_check(message, "status", error);
ebcf1f97
LP
1042 if (r < 0)
1043 return r;
ea430986 1044
19070062 1045 if (sd_bus_message_get_bus(message) == m->api_bus) {
8f8f05a9
LP
1046 r = sd_bus_track_remove_sender(m->subscribed, message);
1047 if (r < 0)
1048 return r;
1049 if (r == 0)
1050 return sd_bus_error_setf(error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1051 }
ea430986 1052
df2d202e 1053 return sd_bus_reply_method_return(message, NULL);
718db961 1054}
ea430986 1055
19070062 1056static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1057 _cleanup_free_ char *dump = NULL;
1058 _cleanup_fclose_ FILE *f = NULL;
1059 Manager *m = userdata;
1060 size_t size;
ebcf1f97 1061 int r;
ea430986 1062
718db961
LP
1063 assert(message);
1064 assert(m);
ea430986 1065
283868e1
SW
1066 /* Anyone can call this method */
1067
8a188de9 1068 r = mac_selinux_access_check(message, "status", error);
ebcf1f97
LP
1069 if (r < 0)
1070 return r;
ea430986 1071
718db961
LP
1072 f = open_memstream(&dump, &size);
1073 if (!f)
ebcf1f97 1074 return -ENOMEM;
ea430986 1075
718db961
LP
1076 manager_dump_units(m, f, NULL);
1077 manager_dump_jobs(m, f, NULL);
ea430986 1078
dacd6cee
LP
1079 r = fflush_and_check(f);
1080 if (r < 0)
1081 return r;
a16e1123 1082
df2d202e 1083 return sd_bus_reply_method_return(message, "s", dump);
718db961 1084}
cad45ba1 1085
19070062 1086static int method_create_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1087 _cleanup_free_ char *path = NULL;
1088 Manager *m = userdata;
1089 const char *name;
1090 int cleanup;
39883f62 1091 Snapshot *s = NULL;
718db961 1092 int r;
a16e1123 1093
718db961
LP
1094 assert(message);
1095 assert(m);
a16e1123 1096
8a188de9 1097 r = mac_selinux_access_check(message, "start", error);
ebcf1f97
LP
1098 if (r < 0)
1099 return r;
a16e1123 1100
718db961
LP
1101 r = sd_bus_message_read(message, "sb", &name, &cleanup);
1102 if (r < 0)
ebcf1f97 1103 return r;
a16e1123 1104
718db961
LP
1105 if (isempty(name))
1106 name = NULL;
a16e1123 1107
1d22e906
LP
1108 r = bus_verify_manage_units_async(m, message, error);
1109 if (r < 0)
1110 return r;
1111 if (r == 0)
1112 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1113
ebcf1f97 1114 r = snapshot_create(m, name, cleanup, error, &s);
718db961 1115 if (r < 0)
ebcf1f97 1116 return r;
cad45ba1 1117
718db961
LP
1118 path = unit_dbus_path(UNIT(s));
1119 if (!path)
ebcf1f97 1120 return -ENOMEM;
a16e1123 1121
df2d202e 1122 return sd_bus_reply_method_return(message, "o", path);
718db961 1123}
a16e1123 1124
19070062 1125static int method_remove_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1126 Manager *m = userdata;
1127 const char *name;
1128 Unit *u;
1129 int r;
a16e1123 1130
718db961
LP
1131 assert(message);
1132 assert(m);
cad45ba1 1133
718db961
LP
1134 r = sd_bus_message_read(message, "s", &name);
1135 if (r < 0)
ebcf1f97 1136 return r;
a16e1123 1137
718db961
LP
1138 u = manager_get_unit(m, name);
1139 if (!u)
ebcf1f97 1140 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
a16e1123 1141
718db961 1142 if (u->type != UNIT_SNAPSHOT)
ebcf1f97 1143 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name);
6652a2b9 1144
19070062 1145 return bus_snapshot_method_remove(message, u, error);
718db961 1146}
cad45ba1 1147
19070062 1148static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1149 Manager *m = userdata;
1150 int r;
6652a2b9 1151
718db961
LP
1152 assert(message);
1153 assert(m);
6652a2b9 1154
1d22e906 1155 r = mac_selinux_access_check(message, "reload", error);
283868e1
SW
1156 if (r < 0)
1157 return r;
283868e1 1158
1d22e906 1159 r = bus_verify_reload_daemon_async(m, message, error);
ebcf1f97
LP
1160 if (r < 0)
1161 return r;
1d22e906
LP
1162 if (r == 0)
1163 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
6652a2b9 1164
718db961
LP
1165 /* Instead of sending the reply back right away, we just
1166 * remember that we need to and then send it after the reload
1167 * is finished. That way the caller knows when the reload
1168 * finished. */
6652a2b9 1169
718db961 1170 assert(!m->queued_message);
df2d202e 1171 r = sd_bus_message_new_method_return(message, &m->queued_message);
718db961 1172 if (r < 0)
ebcf1f97 1173 return r;
cad45ba1 1174
718db961 1175 m->exit_code = MANAGER_RELOAD;
6652a2b9 1176
718db961
LP
1177 return 1;
1178}
6652a2b9 1179
19070062 1180static int method_reexecute(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 1181 Manager *m = userdata;
ebcf1f97 1182 int r;
6652a2b9 1183
718db961
LP
1184 assert(message);
1185 assert(m);
6652a2b9 1186
1d22e906 1187 r = mac_selinux_access_check(message, "reload", error);
283868e1
SW
1188 if (r < 0)
1189 return r;
283868e1 1190
1d22e906 1191 r = bus_verify_reload_daemon_async(m, message, error);
ebcf1f97
LP
1192 if (r < 0)
1193 return r;
1d22e906
LP
1194 if (r == 0)
1195 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
cad45ba1 1196
718db961
LP
1197 /* We don't send a reply back here, the client should
1198 * just wait for us disconnecting. */
6652a2b9 1199
718db961
LP
1200 m->exit_code = MANAGER_REEXECUTE;
1201 return 1;
1202}
6652a2b9 1203
19070062 1204static int method_exit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 1205 Manager *m = userdata;
ebcf1f97 1206 int r;
6652a2b9 1207
718db961
LP
1208 assert(message);
1209 assert(m);
6652a2b9 1210
8a188de9 1211 r = mac_selinux_access_check(message, "halt", error);
ebcf1f97
LP
1212 if (r < 0)
1213 return r;
cad45ba1 1214
287419c1
AC
1215 /* Exit() (in contrast to SetExitCode()) is actually allowed even if
1216 * we are running on the host. It will fall back on reboot() in
1217 * systemd-shutdown if it cannot do the exit() because it isn't a
1218 * container. */
6652a2b9 1219
718db961 1220 m->exit_code = MANAGER_EXIT;
6652a2b9 1221
df2d202e 1222 return sd_bus_reply_method_return(message, NULL);
718db961 1223}
6652a2b9 1224
19070062 1225static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 1226 Manager *m = userdata;
ebcf1f97 1227 int r;
664f88a7 1228
718db961
LP
1229 assert(message);
1230 assert(m);
cad45ba1 1231
8a188de9 1232 r = mac_selinux_access_check(message, "reboot", error);
ebcf1f97
LP
1233 if (r < 0)
1234 return r;
664f88a7 1235
b2c23da8 1236 if (m->running_as != MANAGER_SYSTEM)
ebcf1f97 1237 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
664f88a7 1238
718db961 1239 m->exit_code = MANAGER_REBOOT;
664f88a7 1240
df2d202e 1241 return sd_bus_reply_method_return(message, NULL);
718db961 1242}
664f88a7 1243
19070062 1244static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 1245 Manager *m = userdata;
ebcf1f97 1246 int r;
50913bc0 1247
718db961
LP
1248 assert(message);
1249 assert(m);
1137a57c 1250
8a188de9 1251 r = mac_selinux_access_check(message, "halt", error);
ebcf1f97
LP
1252 if (r < 0)
1253 return r;
1137a57c 1254
b2c23da8 1255 if (m->running_as != MANAGER_SYSTEM)
ebcf1f97 1256 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1137a57c 1257
718db961 1258 m->exit_code = MANAGER_POWEROFF;
1137a57c 1259
df2d202e 1260 return sd_bus_reply_method_return(message, NULL);
718db961 1261}
1137a57c 1262
19070062 1263static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 1264 Manager *m = userdata;
ebcf1f97 1265 int r;
1137a57c 1266
718db961
LP
1267 assert(message);
1268 assert(m);
8d0e38a2 1269
8a188de9 1270 r = mac_selinux_access_check(message, "halt", error);
ebcf1f97
LP
1271 if (r < 0)
1272 return r;
cad45ba1 1273
b2c23da8 1274 if (m->running_as != MANAGER_SYSTEM)
ebcf1f97 1275 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
8d0e38a2 1276
718db961 1277 m->exit_code = MANAGER_HALT;
8d0e38a2 1278
df2d202e 1279 return sd_bus_reply_method_return(message, NULL);
718db961 1280}
8d0e38a2 1281
19070062 1282static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 1283 Manager *m = userdata;
ebcf1f97 1284 int r;
8d0e38a2 1285
718db961
LP
1286 assert(message);
1287 assert(m);
c0576cd6 1288
8a188de9 1289 r = mac_selinux_access_check(message, "reboot", error);
ebcf1f97
LP
1290 if (r < 0)
1291 return r;
cad45ba1 1292
b2c23da8 1293 if (m->running_as != MANAGER_SYSTEM)
ebcf1f97 1294 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
c0576cd6 1295
718db961 1296 m->exit_code = MANAGER_KEXEC;
c0576cd6 1297
df2d202e 1298 return sd_bus_reply_method_return(message, NULL);
718db961 1299}
c0576cd6 1300
19070062 1301static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1302 char *ri = NULL, *rt = NULL;
1303 const char *root, *init;
1304 Manager *m = userdata;
1305 int r;
c0576cd6 1306
718db961
LP
1307 assert(message);
1308 assert(m);
c0576cd6 1309
8a188de9 1310 r = mac_selinux_access_check(message, "reboot", error);
ebcf1f97
LP
1311 if (r < 0)
1312 return r;
c0576cd6 1313
b2c23da8 1314 if (m->running_as != MANAGER_SYSTEM)
6ad3b2b6 1315 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager.");
c0576cd6 1316
718db961
LP
1317 r = sd_bus_message_read(message, "ss", &root, &init);
1318 if (r < 0)
ebcf1f97 1319 return r;
c0576cd6 1320
718db961 1321 if (path_equal(root, "/") || !path_is_absolute(root))
ebcf1f97 1322 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid switch root path %s", root);
c0576cd6 1323
718db961
LP
1324 /* Safety check */
1325 if (isempty(init)) {
6ad3b2b6 1326 if (!path_is_os_tree(root))
5ae4d543 1327 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path %s does not seem to be an OS tree. os-release file is missing.", root);
718db961
LP
1328 } else {
1329 _cleanup_free_ char *p = NULL;
c0576cd6 1330
718db961 1331 if (!path_is_absolute(init))
ebcf1f97 1332 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid init path %s", init);
c0576cd6 1333
718db961
LP
1334 p = strappend(root, init);
1335 if (!p)
ebcf1f97 1336 return -ENOMEM;
c0576cd6 1337
718db961 1338 if (access(p, X_OK) < 0)
ebcf1f97 1339 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified init binary %s does not exist.", p);
718db961
LP
1340 }
1341
1342 rt = strdup(root);
1343 if (!rt)
ebcf1f97 1344 return -ENOMEM;
718db961
LP
1345
1346 if (!isempty(init)) {
1347 ri = strdup(init);
1348 if (!ri) {
92b315df 1349 free(rt);
ebcf1f97 1350 return -ENOMEM;
c0576cd6 1351 }
718db961 1352 }
c0576cd6 1353
718db961
LP
1354 free(m->switch_root);
1355 m->switch_root = rt;
c0576cd6 1356
718db961
LP
1357 free(m->switch_root_init);
1358 m->switch_root_init = ri;
c0576cd6 1359
92b315df
LP
1360 m->exit_code = MANAGER_SWITCH_ROOT;
1361
df2d202e 1362 return sd_bus_reply_method_return(message, NULL);
718db961 1363}
c0576cd6 1364
19070062 1365static int method_set_environment(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1366 _cleanup_strv_free_ char **plus = NULL;
1367 Manager *m = userdata;
1368 int r;
c0576cd6 1369
718db961
LP
1370 assert(message);
1371 assert(m);
cad45ba1 1372
8a188de9 1373 r = mac_selinux_access_check(message, "reload", error);
ebcf1f97
LP
1374 if (r < 0)
1375 return r;
c0576cd6 1376
718db961
LP
1377 r = sd_bus_message_read_strv(message, &plus);
1378 if (r < 0)
ebcf1f97 1379 return r;
718db961 1380 if (!strv_env_is_valid(plus))
ebcf1f97 1381 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
c0576cd6 1382
1d22e906
LP
1383 r = bus_verify_set_environment_async(m, message, error);
1384 if (r < 0)
1385 return r;
1386 if (r == 0)
1387 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1388
718db961
LP
1389 r = manager_environment_add(m, NULL, plus);
1390 if (r < 0)
ebcf1f97 1391 return r;
c0576cd6 1392
df2d202e 1393 return sd_bus_reply_method_return(message, NULL);
718db961
LP
1394}
1395
19070062 1396static int method_unset_environment(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1397 _cleanup_strv_free_ char **minus = NULL;
1398 Manager *m = userdata;
1399 int r;
1400
718db961
LP
1401 assert(message);
1402 assert(m);
1403
8a188de9 1404 r = mac_selinux_access_check(message, "reload", error);
ebcf1f97
LP
1405 if (r < 0)
1406 return r;
c0576cd6 1407
718db961
LP
1408 r = sd_bus_message_read_strv(message, &minus);
1409 if (r < 0)
ebcf1f97 1410 return r;
718db961
LP
1411
1412 if (!strv_env_name_or_assignment_is_valid(minus))
ebcf1f97 1413 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
718db961 1414
1d22e906
LP
1415 r = bus_verify_set_environment_async(m, message, error);
1416 if (r < 0)
1417 return r;
1418 if (r == 0)
1419 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1420
718db961
LP
1421 r = manager_environment_add(m, minus, NULL);
1422 if (r < 0)
ebcf1f97 1423 return r;
718db961 1424
df2d202e 1425 return sd_bus_reply_method_return(message, NULL);
718db961
LP
1426}
1427
19070062 1428static int method_unset_and_set_environment(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1429 _cleanup_strv_free_ char **minus = NULL, **plus = NULL;
1430 Manager *m = userdata;
1431 int r;
1432
718db961
LP
1433 assert(message);
1434 assert(m);
1435
8a188de9 1436 r = mac_selinux_access_check(message, "reload", error);
ebcf1f97
LP
1437 if (r < 0)
1438 return r;
718db961 1439
eb6c7d20 1440 r = sd_bus_message_read_strv(message, &minus);
718db961 1441 if (r < 0)
ebcf1f97 1442 return r;
718db961 1443
eb6c7d20 1444 r = sd_bus_message_read_strv(message, &plus);
718db961 1445 if (r < 0)
ebcf1f97 1446 return r;
718db961 1447
718db961 1448 if (!strv_env_name_or_assignment_is_valid(minus))
ebcf1f97 1449 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
eb6c7d20
ZJS
1450 if (!strv_env_is_valid(plus))
1451 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
718db961 1452
1d22e906
LP
1453 r = bus_verify_set_environment_async(m, message, error);
1454 if (r < 0)
1455 return r;
1456 if (r == 0)
1457 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1458
718db961
LP
1459 r = manager_environment_add(m, minus, plus);
1460 if (r < 0)
ebcf1f97 1461 return r;
718db961 1462
df2d202e 1463 return sd_bus_reply_method_return(message, NULL);
718db961
LP
1464}
1465
287419c1
AC
1466static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1467 uint8_t code;
1468 Manager *m = userdata;
1469 int r;
1470
1471 assert(message);
1472 assert(m);
1473
1474 r = mac_selinux_access_check(message, "exit", error);
1475 if (r < 0)
1476 return r;
1477
1478 r = sd_bus_message_read_basic(message, 'y', &code);
1479 if (r < 0)
1480 return r;
1481
1482 if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0)
1483 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers.");
1484
1485 m->return_value = code;
1486
1487 return sd_bus_reply_method_return(message, NULL);
1488}
1489
19070062 1490static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1491 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1492 Manager *m = userdata;
1493 UnitFileList *item;
1494 Hashmap *h;
1495 Iterator i;
1496 int r;
1497
718db961
LP
1498 assert(message);
1499 assert(m);
1500
283868e1
SW
1501 /* Anyone can call this method */
1502
8a188de9 1503 r = mac_selinux_access_check(message, "status", error);
ebcf1f97
LP
1504 if (r < 0)
1505 return r;
718db961 1506
df2d202e 1507 r = sd_bus_message_new_method_return(message, &reply);
718db961 1508 if (r < 0)
ebcf1f97 1509 return r;
c0576cd6 1510
d5099efc 1511 h = hashmap_new(&string_hash_ops);
718db961 1512 if (!h)
ebcf1f97 1513 return -ENOMEM;
c0576cd6 1514
b2c23da8 1515 r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
ebcf1f97 1516 if (r < 0)
718db961 1517 goto fail;
718db961
LP
1518
1519 r = sd_bus_message_open_container(reply, 'a', "(ss)");
ebcf1f97 1520 if (r < 0)
718db961 1521 goto fail;
718db961
LP
1522
1523 HASHMAP_FOREACH(item, h, i) {
1524
1525 r = sd_bus_message_append(reply, "(ss)", item->path, unit_file_state_to_string(item->state));
ebcf1f97 1526 if (r < 0)
718db961 1527 goto fail;
718db961 1528 }
c0576cd6 1529
718db961 1530 unit_file_list_free(h);
c0576cd6 1531
718db961
LP
1532 r = sd_bus_message_close_container(reply);
1533 if (r < 0)
ebcf1f97 1534 return r;
8d0e38a2 1535
9030ca46 1536 return sd_bus_send(NULL, reply, NULL);
99504dd4 1537
718db961
LP
1538fail:
1539 unit_file_list_free(h);
1540 return r;
1541}
99504dd4 1542
19070062 1543static int method_get_unit_file_state(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1544 Manager *m = userdata;
1545 const char *name;
1546 UnitFileState state;
1547 UnitFileScope scope;
1548 int r;
99504dd4 1549
718db961
LP
1550 assert(message);
1551 assert(m);
8e2af478 1552
283868e1
SW
1553 /* Anyone can call this method */
1554
8a188de9 1555 r = mac_selinux_access_check(message, "status", error);
ebcf1f97
LP
1556 if (r < 0)
1557 return r;
8e2af478 1558
718db961
LP
1559 r = sd_bus_message_read(message, "s", &name);
1560 if (r < 0)
ebcf1f97 1561 return r;
8e2af478 1562
b2c23da8 1563 scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
8e2af478 1564
718db961
LP
1565 state = unit_file_get_state(scope, NULL, name);
1566 if (state < 0)
ebcf1f97 1567 return state;
8e2af478 1568
df2d202e 1569 return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state));
718db961 1570}
8e2af478 1571
19070062 1572static int method_get_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1573 _cleanup_free_ char *default_target = NULL;
1574 Manager *m = userdata;
1575 UnitFileScope scope;
1576 int r;
c2756a68 1577
718db961
LP
1578 assert(message);
1579 assert(m);
c2756a68 1580
283868e1
SW
1581 /* Anyone can call this method */
1582
8a188de9 1583 r = mac_selinux_access_check(message, "status", error);
ebcf1f97
LP
1584 if (r < 0)
1585 return r;
c2756a68 1586
b2c23da8 1587 scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
c2756a68 1588
718db961
LP
1589 r = unit_file_get_default(scope, NULL, &default_target);
1590 if (r < 0)
ebcf1f97 1591 return r;
c2756a68 1592
df2d202e 1593 return sd_bus_reply_method_return(message, "s", default_target);
718db961 1594}
c2756a68 1595
8f8f05a9 1596static int send_unit_files_changed(sd_bus *bus, void *userdata) {
718db961
LP
1597 _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
1598 int r;
1599
1600 assert(bus);
1601
151b9b96 1602 r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
718db961
LP
1603 if (r < 0)
1604 return r;
1605
8f8f05a9 1606 return sd_bus_send(bus, message, NULL);
718db961
LP
1607}
1608
1609static int reply_unit_file_changes_and_free(
1610 Manager *m,
718db961
LP
1611 sd_bus_message *message,
1612 int carries_install_info,
1613 UnitFileChange *changes,
1614 unsigned n_changes) {
1615
1616 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1617 unsigned i;
1618 int r;
1619
fe7f06f1
LP
1620 if (n_changes > 0) {
1621 r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL);
1622 if (r < 0)
da927ba9 1623 log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m");
fe7f06f1 1624 }
718db961 1625
df2d202e 1626 r = sd_bus_message_new_method_return(message, &reply);
718db961
LP
1627 if (r < 0)
1628 goto fail;
1629
1630 if (carries_install_info >= 0) {
1631 r = sd_bus_message_append(reply, "b", carries_install_info);
c2756a68 1632 if (r < 0)
718db961
LP
1633 goto fail;
1634 }
1635
1636 r = sd_bus_message_open_container(reply, 'a', "(sss)");
1637 if (r < 0)
1638 goto fail;
c2756a68 1639
718db961
LP
1640 for (i = 0; i < n_changes; i++) {
1641 r = sd_bus_message_append(
21586b77 1642 reply, "(sss)",
718db961
LP
1643 unit_file_change_type_to_string(changes[i].type),
1644 changes[i].path,
1645 changes[i].source);
c2756a68 1646 if (r < 0)
718db961
LP
1647 goto fail;
1648 }
c2756a68 1649
718db961
LP
1650 r = sd_bus_message_close_container(reply);
1651 if (r < 0)
1652 goto fail;
c2756a68 1653
9030ca46 1654 return sd_bus_send(NULL, reply, NULL);
c2756a68 1655
718db961
LP
1656fail:
1657 unit_file_changes_free(changes, n_changes);
ebcf1f97 1658 return r;
718db961 1659}
cad45ba1 1660
718db961 1661static int method_enable_unit_files_generic(
718db961 1662 sd_bus_message *message,
d309c1c3
LP
1663 Manager *m,
1664 const char *verb,
718db961 1665 int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes),
ebcf1f97
LP
1666 bool carries_install_info,
1667 sd_bus_error *error) {
718db961
LP
1668
1669 _cleanup_strv_free_ char **l = NULL;
1670 UnitFileChange *changes = NULL;
1671 unsigned n_changes = 0;
1672 UnitFileScope scope;
1673 int runtime, force, r;
1674
718db961
LP
1675 assert(message);
1676 assert(m);
cad45ba1 1677
718db961
LP
1678 r = sd_bus_message_read_strv(message, &l);
1679 if (r < 0)
ebcf1f97 1680 return r;
90bb85e1 1681
d309c1c3
LP
1682 r = sd_bus_message_read(message, "bb", &runtime, &force);
1683 if (r < 0)
1684 return r;
1685
1d22e906
LP
1686 r = bus_verify_manage_unit_files_async(m, message, error);
1687 if (r < 0)
1688 return r;
1689 if (r == 0)
1690 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1691
b2c23da8 1692 scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
c87eba54 1693
718db961
LP
1694 r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
1695 if (r < 0)
ebcf1f97 1696 return r;
718db961 1697
19070062 1698 return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes);
718db961 1699}
c87eba54 1700
19070062
LP
1701static int method_enable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1702 return method_enable_unit_files_generic(message, userdata, "enable", unit_file_enable, true, error);
718db961 1703}
ea430986 1704
19070062
LP
1705static int method_reenable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1706 return method_enable_unit_files_generic(message, userdata, "enable", unit_file_reenable, true, error);
718db961
LP
1707}
1708
19070062
LP
1709static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1710 return method_enable_unit_files_generic(message, userdata, "enable", unit_file_link, false, error);
718db961
LP
1711}
1712
d309c1c3
LP
1713static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes) {
1714 return unit_file_preset(scope, runtime, root_dir, files, UNIT_FILE_PRESET_FULL, force, changes, n_changes);
1715}
1716
19070062
LP
1717static int method_preset_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1718 return method_enable_unit_files_generic(message, userdata, "enable", unit_file_preset_without_mode, true, error);
718db961
LP
1719}
1720
19070062
LP
1721static int method_mask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1722 return method_enable_unit_files_generic(message, userdata, "disable", unit_file_mask, false, error);
718db961 1723}
ea430986 1724
19070062 1725static int method_preset_unit_files_with_mode(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d309c1c3
LP
1726
1727 _cleanup_strv_free_ char **l = NULL;
d309c1c3
LP
1728 UnitFileChange *changes = NULL;
1729 unsigned n_changes = 0;
1730 Manager *m = userdata;
1731 UnitFilePresetMode mm;
1732 UnitFileScope scope;
1733 int runtime, force, r;
1734 const char *mode;
1735
d309c1c3
LP
1736 assert(message);
1737 assert(m);
1738
1739 r = sd_bus_message_read_strv(message, &l);
1740 if (r < 0)
1741 return r;
1742
1743 r = sd_bus_message_read(message, "sbb", &mode, &runtime, &force);
1744 if (r < 0)
1745 return r;
1746
1747 if (isempty(mode))
1748 mm = UNIT_FILE_PRESET_FULL;
1749 else {
1750 mm = unit_file_preset_mode_from_string(mode);
1751 if (mm < 0)
1752 return -EINVAL;
1753 }
1754
1d22e906
LP
1755 r = bus_verify_manage_unit_files_async(m, message, error);
1756 if (r < 0)
1757 return r;
1758 if (r == 0)
1759 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1760
b2c23da8 1761 scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
d309c1c3
LP
1762
1763 r = unit_file_preset(scope, runtime, NULL, l, mm, force, &changes, &n_changes);
1764 if (r < 0)
1765 return r;
1766
19070062 1767 return reply_unit_file_changes_and_free(m, message, r, changes, n_changes);
d309c1c3
LP
1768}
1769
718db961 1770static int method_disable_unit_files_generic(
718db961
LP
1771 sd_bus_message *message,
1772 Manager *m, const
1773 char *verb,
ebcf1f97
LP
1774 int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
1775 sd_bus_error *error) {
718db961
LP
1776
1777 _cleanup_strv_free_ char **l = NULL;
1778 UnitFileChange *changes = NULL;
1779 unsigned n_changes = 0;
1780 UnitFileScope scope;
1781 int r, runtime;
1782
718db961
LP
1783 assert(message);
1784 assert(m);
1785
df823e23 1786 r = sd_bus_message_read_strv(message, &l);
ebcf1f97
LP
1787 if (r < 0)
1788 return r;
718db961 1789
df823e23 1790 r = sd_bus_message_read(message, "b", &runtime);
718db961 1791 if (r < 0)
ebcf1f97 1792 return r;
718db961 1793
b2c23da8 1794 scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
718db961 1795
1d22e906
LP
1796 r = bus_verify_manage_unit_files_async(m, message, error);
1797 if (r < 0)
1798 return r;
1799 if (r == 0)
1800 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1801
718db961
LP
1802 r = call(scope, runtime, NULL, l, &changes, &n_changes);
1803 if (r < 0)
ebcf1f97 1804 return r;
718db961 1805
19070062 1806 return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
718db961 1807}
ea430986 1808
19070062
LP
1809static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1810 return method_disable_unit_files_generic(message, userdata, "disable", unit_file_disable, error);
ea430986
LP
1811}
1812
19070062
LP
1813static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1814 return method_disable_unit_files_generic(message, userdata, "enable", unit_file_unmask, error);
718db961
LP
1815}
1816
19070062 1817static int method_set_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
1818 UnitFileChange *changes = NULL;
1819 unsigned n_changes = 0;
1820 Manager *m = userdata;
1821 UnitFileScope scope;
1822 const char *name;
1823 int force, r;
1824
718db961
LP
1825 assert(message);
1826 assert(m);
1827
1d22e906 1828 r = mac_selinux_access_check(message, "enable", error);
283868e1
SW
1829 if (r < 0)
1830 return r;
283868e1 1831
1d22e906 1832 r = sd_bus_message_read(message, "sb", &name, &force);
ebcf1f97
LP
1833 if (r < 0)
1834 return r;
718db961 1835
1d22e906 1836 r = bus_verify_manage_unit_files_async(m, message, error);
718db961 1837 if (r < 0)
ebcf1f97 1838 return r;
1d22e906
LP
1839 if (r == 0)
1840 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
718db961 1841
b2c23da8 1842 scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
718db961
LP
1843
1844 r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes);
1845 if (r < 0)
ebcf1f97 1846 return r;
718db961 1847
19070062 1848 return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
718db961
LP
1849}
1850
19070062 1851static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d309c1c3
LP
1852 UnitFileChange *changes = NULL;
1853 unsigned n_changes = 0;
1854 Manager *m = userdata;
1855 UnitFilePresetMode mm;
1856 UnitFileScope scope;
1857 const char *mode;
1858 int force, runtime, r;
1859
d309c1c3
LP
1860 assert(message);
1861 assert(m);
1862
8a188de9 1863 r = mac_selinux_access_check(message, "enable", error);
d309c1c3
LP
1864 if (r < 0)
1865 return r;
1866
1867 r = sd_bus_message_read(message, "sbb", &mode, &runtime, &force);
1868 if (r < 0)
1869 return r;
1870
1871 if (isempty(mode))
1872 mm = UNIT_FILE_PRESET_FULL;
1873 else {
1874 mm = unit_file_preset_mode_from_string(mode);
1875 if (mm < 0)
1876 return -EINVAL;
1877 }
1878
1d22e906
LP
1879 r = bus_verify_manage_unit_files_async(m, message, error);
1880 if (r < 0)
1881 return r;
1882 if (r == 0)
1883 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1884
b2c23da8 1885 scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
d309c1c3
LP
1886
1887 r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes);
1888 if (r < 0)
1889 return r;
1890
19070062 1891 return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
d309c1c3
LP
1892}
1893
19070062 1894static int method_add_dependency_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
e94937df
LN
1895 _cleanup_strv_free_ char **l = NULL;
1896 Manager *m = userdata;
1897 UnitFileChange *changes = NULL;
1898 unsigned n_changes = 0;
1899 UnitFileScope scope;
1900 int runtime, force, r;
1901 char *target;
1902 char *type;
1903 UnitDependency dep;
1904
e94937df
LN
1905 assert(message);
1906 assert(m);
1907
1908 r = bus_verify_manage_unit_files_async(m, message, error);
1909 if (r < 0)
1910 return r;
1911 if (r == 0)
1912 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1913
1914 r = sd_bus_message_read_strv(message, &l);
1915 if (r < 0)
1916 return r;
1917
1918 r = sd_bus_message_read(message, "ssbb", &target, &type, &runtime, &force);
1919 if (r < 0)
1920 return r;
1921
1922 dep = unit_dependency_from_string(type);
1923 if (dep < 0)
1924 return -EINVAL;
1925
b2c23da8 1926 scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
e94937df
LN
1927
1928 r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
1929 if (r < 0)
1930 return r;
1931
19070062 1932 return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
e94937df
LN
1933}
1934
718db961
LP
1935const sd_bus_vtable bus_manager_vtable[] = {
1936 SD_BUS_VTABLE_START(0),
1937
556089dc
LP
1938 SD_BUS_PROPERTY("Version", "s", property_get_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1939 SD_BUS_PROPERTY("Features", "s", property_get_features, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1940 SD_BUS_PROPERTY("Virtualization", "s", property_get_virtualization, 0, SD_BUS_VTABLE_PROPERTY_CONST),
7452394e 1941 SD_BUS_PROPERTY("Architecture", "s", property_get_architecture, 0, SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
1942 SD_BUS_PROPERTY("Tainted", "s", property_get_tainted, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1943 BUS_PROPERTY_DUAL_TIMESTAMP("FirmwareTimestamp", offsetof(Manager, firmware_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1944 BUS_PROPERTY_DUAL_TIMESTAMP("LoaderTimestamp", offsetof(Manager, loader_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1945 BUS_PROPERTY_DUAL_TIMESTAMP("KernelTimestamp", offsetof(Manager, kernel_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1946 BUS_PROPERTY_DUAL_TIMESTAMP("InitRDTimestamp", offsetof(Manager, initrd_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1947 BUS_PROPERTY_DUAL_TIMESTAMP("UserspaceTimestamp", offsetof(Manager, userspace_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1948 BUS_PROPERTY_DUAL_TIMESTAMP("FinishTimestamp", offsetof(Manager, finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1949 BUS_PROPERTY_DUAL_TIMESTAMP("SecurityStartTimestamp", offsetof(Manager, security_start_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1950 BUS_PROPERTY_DUAL_TIMESTAMP("SecurityFinishTimestamp", offsetof(Manager, security_finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1951 BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsStartTimestamp", offsetof(Manager, generators_start_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1952 BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, generators_finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1953 BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, units_load_start_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1954 BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, units_load_finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
718db961
LP
1955 SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0),
1956 SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0),
1957 SD_BUS_PROPERTY("NNames", "u", property_get_n_names, 0, 0),
03455c28 1958 SD_BUS_PROPERTY("NFailedUnits", "u", property_get_n_failed_units, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
718db961
LP
1959 SD_BUS_PROPERTY("NJobs", "u", property_get_n_jobs, 0, 0),
1960 SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0),
1961 SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0),
1962 SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
1963 SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0),
556089dc
LP
1964 SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), SD_BUS_VTABLE_PROPERTY_CONST),
1965 SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), SD_BUS_VTABLE_PROPERTY_CONST),
1966 SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), SD_BUS_VTABLE_PROPERTY_CONST),
1967 SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
1968 SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
4c3f1641
LP
1969 SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
1970 SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0),
b272b74d 1971 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
f755e3b7 1972 SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
287419c1 1973 SD_BUS_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0),
718db961 1974
adacb957
LP
1975 SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1976 SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
1977 SD_BUS_METHOD("LoadUnit", "s", "o", method_load_unit, SD_BUS_VTABLE_UNPRIVILEGED),
283868e1
SW
1978 SD_BUS_METHOD("StartUnit", "ss", "o", method_start_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1979 SD_BUS_METHOD("StartUnitReplace", "sss", "o", method_start_unit_replace, SD_BUS_VTABLE_UNPRIVILEGED),
1980 SD_BUS_METHOD("StopUnit", "ss", "o", method_stop_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1981 SD_BUS_METHOD("ReloadUnit", "ss", "o", method_reload_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1982 SD_BUS_METHOD("RestartUnit", "ss", "o", method_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1983 SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1984 SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1985 SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1986 SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1987 SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
1988 SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
1989 SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957 1990 SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED),
283868e1 1991 SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, SD_BUS_VTABLE_UNPRIVILEGED),
1d22e906
LP
1992 SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
1993 SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957 1994 SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, SD_BUS_VTABLE_UNPRIVILEGED),
cdc06ed7 1995 SD_BUS_METHOD("ListUnitsFiltered", "as", "a(ssssssouso)", method_list_units_filtered, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
1996 SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
1997 SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED),
1998 SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED),
1999 SD_BUS_METHOD("Dump", NULL, "s", method_dump, SD_BUS_VTABLE_UNPRIVILEGED),
1d22e906
LP
2000 SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
2001 SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
283868e1
SW
2002 SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
2003 SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, SD_BUS_VTABLE_UNPRIVILEGED),
718db961 2004 SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),
adacb957
LP
2005 SD_BUS_METHOD("Reboot", NULL, NULL, method_reboot, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
2006 SD_BUS_METHOD("PowerOff", NULL, NULL, method_poweroff, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
2007 SD_BUS_METHOD("Halt", NULL, NULL, method_halt, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
2008 SD_BUS_METHOD("KExec", NULL, NULL, method_kexec, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
2009 SD_BUS_METHOD("SwitchRoot", "ss", NULL, method_switch_root, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
1d22e906
LP
2010 SD_BUS_METHOD("SetEnvironment", "as", NULL, method_set_environment, SD_BUS_VTABLE_UNPRIVILEGED),
2011 SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, SD_BUS_VTABLE_UNPRIVILEGED),
2012 SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
2013 SD_BUS_METHOD("ListUnitFiles", NULL, "a(ss)", method_list_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
2014 SD_BUS_METHOD("GetUnitFileState", "s", "s", method_get_unit_file_state, SD_BUS_VTABLE_UNPRIVILEGED),
283868e1
SW
2015 SD_BUS_METHOD("EnableUnitFiles", "asbb", "ba(sss)", method_enable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
2016 SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", method_disable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
2017 SD_BUS_METHOD("ReenableUnitFiles", "asbb", "ba(sss)", method_reenable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
2018 SD_BUS_METHOD("LinkUnitFiles", "asbb", "a(sss)", method_link_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
2019 SD_BUS_METHOD("PresetUnitFiles", "asbb", "ba(sss)", method_preset_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
2020 SD_BUS_METHOD("PresetUnitFilesWithMode", "assbb", "ba(sss)", method_preset_unit_files_with_mode, SD_BUS_VTABLE_UNPRIVILEGED),
2021 SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
2022 SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
2023 SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957 2024 SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
283868e1 2025 SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
e94937df 2026 SD_BUS_METHOD("AddDependencyUnitFiles", "asssbb", "a(sss)", method_add_dependency_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
287419c1 2027 SD_BUS_METHOD("SetExitCode", "y", NULL, method_set_exit_code, SD_BUS_VTABLE_UNPRIVILEGED),
718db961
LP
2028
2029 SD_BUS_SIGNAL("UnitNew", "so", 0),
2030 SD_BUS_SIGNAL("UnitRemoved", "so", 0),
2031 SD_BUS_SIGNAL("JobNew", "uos", 0),
2032 SD_BUS_SIGNAL("JobRemoved", "uoss", 0),
2033 SD_BUS_SIGNAL("StartupFinished", "tttttt", 0),
2034 SD_BUS_SIGNAL("UnitFilesChanged", NULL, 0),
2035 SD_BUS_SIGNAL("Reloading", "b", 0),
2036
2037 SD_BUS_VTABLE_END
ea430986 2038};
718db961 2039
8f8f05a9 2040static int send_finished(sd_bus *bus, void *userdata) {
718db961
LP
2041 _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
2042 usec_t *times = userdata;
2043 int r;
2044
2045 assert(bus);
2046 assert(times);
2047
151b9b96 2048 r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
718db961
LP
2049 if (r < 0)
2050 return r;
2051
2052 r = sd_bus_message_append(message, "tttttt", times[0], times[1], times[2], times[3], times[4], times[5]);
2053 if (r < 0)
2054 return r;
2055
8f8f05a9 2056 return sd_bus_send(bus, message, NULL);
718db961
LP
2057}
2058
39abcaee 2059void bus_manager_send_finished(
718db961
LP
2060 Manager *m,
2061 usec_t firmware_usec,
2062 usec_t loader_usec,
2063 usec_t kernel_usec,
2064 usec_t initrd_usec,
2065 usec_t userspace_usec,
2066 usec_t total_usec) {
2067
39abcaee
LP
2068 int r;
2069
718db961
LP
2070 assert(m);
2071
8f8f05a9
LP
2072 r = bus_foreach_bus(
2073 m,
2074 NULL,
2075 send_finished,
2076 (usec_t[6]) {
2077 firmware_usec,
2078 loader_usec,
2079 kernel_usec,
2080 initrd_usec,
2081 userspace_usec,
2082 total_usec
2083 });
39abcaee 2084 if (r < 0)
da927ba9 2085 log_debug_errno(r, "Failed to send finished signal: %m");
718db961
LP
2086}
2087
8f8f05a9 2088static int send_reloading(sd_bus *bus, void *userdata) {
718db961
LP
2089 _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
2090 int r;
2091
2092 assert(bus);
2093
151b9b96 2094 r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reloading");
718db961
LP
2095 if (r < 0)
2096 return r;
2097
2098 r = sd_bus_message_append(message, "b", PTR_TO_INT(userdata));
2099 if (r < 0)
2100 return r;
2101
8f8f05a9 2102 return sd_bus_send(bus, message, NULL);
718db961
LP
2103}
2104
39abcaee
LP
2105void bus_manager_send_reloading(Manager *m, bool active) {
2106 int r;
2107
718db961
LP
2108 assert(m);
2109
8f8f05a9 2110 r = bus_foreach_bus(m, NULL, send_reloading, INT_TO_PTR(active));
39abcaee 2111 if (r < 0)
da927ba9 2112 log_debug_errno(r, "Failed to send reloading signal: %m");
03455c28
LDM
2113}
2114
2115static int send_changed_signal(sd_bus *bus, void *userdata) {
2116 assert(bus);
2117
2118 return sd_bus_emit_properties_changed_strv(bus,
2119 "/org/freedesktop/systemd1",
2120 "org.freedesktop.systemd1.Manager",
2121 NULL);
2122}
39abcaee 2123
03455c28
LDM
2124void bus_manager_send_change_signal(Manager *m) {
2125 int r;
2126
2127 assert(m);
2128
2129 r = bus_foreach_bus(m, NULL, send_changed_signal, NULL);
2130 if (r < 0)
2131 log_debug_errno(r, "Failed to send manager change signal: %m");
718db961 2132}