]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-manager.c
core: convert PID 1 to libsystemd-bus
[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"
bbc98d32 31#include "hwclock.h"
664f88a7 32#include "path-util.h"
dfae3488 33#include "virt.h"
4d1a6904 34#include "env-util.h"
718db961
LP
35#include "dbus.h"
36#include "dbus-manager.h"
37#include "dbus-unit.h"
38#include "dbus-snapshot.h"
39#include "dbus-client-track.h"
40#include "dbus-execute.h"
41#include "bus-errors.h"
ea430986 42
718db961
LP
43static int property_get_version(
44 sd_bus *bus,
45 const char *path,
46 const char *interface,
47 const char *property,
48 sd_bus_message *reply,
49 sd_bus_error *error,
50 void *userdata) {
51
52 assert(bus);
53 assert(reply);
54
55 return sd_bus_message_append(reply, "s", PACKAGE_VERSION);
56}
c5d34390 57
718db961
LP
58static int property_get_features(
59 sd_bus *bus,
60 const char *path,
61 const char *interface,
62 const char *property,
63 sd_bus_message *reply,
64 sd_bus_error *error,
65 void *userdata) {
66
67 assert(bus);
68 assert(reply);
69
70 return sd_bus_message_append(reply, "s", SYSTEMD_FEATURES);
71}
72
73static int property_get_virtualization(
74 sd_bus *bus,
75 const char *path,
76 const char *interface,
77 const char *property,
78 sd_bus_message *reply,
79 sd_bus_error *error,
80 void *userdata) {
81
82 const char *id = NULL;
83
84 assert(bus);
85 assert(reply);
86
87 detect_virtualization(&id);
88
89 return sd_bus_message_append(reply, "s", id);
90}
91
92static int property_get_tainted(
93 sd_bus *bus,
94 const char *path,
95 const char *interface,
96 const char *property,
97 sd_bus_message *reply,
98 sd_bus_error *error,
99 void *userdata) {
100
101 char buf[LINE_MAX] = "", *e = buf;
102 _cleanup_free_ char *p = NULL;
103 Manager *m = userdata;
104
105 assert(bus);
106 assert(reply);
bfebab7f 107 assert(m);
c5d34390 108
72bc8d00 109 if (m->taint_usr)
e677bf7e 110 e = stpcpy(e, "split-usr:");
c5d34390 111
871c44a7 112 if (readlink_malloc("/etc/mtab", &p) < 0)
e677bf7e 113 e = stpcpy(e, "mtab-not-symlink:");
c5d34390 114
871c44a7 115 if (access("/proc/cgroups", F_OK) < 0)
1ebf0cb7 116 e = stpcpy(e, "cgroups-missing:");
871c44a7 117
e677bf7e 118 if (hwclock_is_localtime() > 0)
1ebf0cb7 119 e = stpcpy(e, "local-hwclock:");
e677bf7e 120
1ebf0cb7
MS
121 /* remove the last ':' */
122 if (e != buf)
123 e[-1] = 0;
e677bf7e 124
718db961 125 return sd_bus_message_append(reply, "s", buf);
c5d34390
LP
126}
127
718db961
LP
128static int property_get_log_target(
129 sd_bus *bus,
130 const char *path,
131 const char *interface,
132 const char *property,
133 sd_bus_message *reply,
134 sd_bus_error *error,
135 void *userdata) {
1adf1049 136
718db961
LP
137 assert(bus);
138 assert(reply);
1adf1049 139
718db961 140 return sd_bus_message_append(reply, "s", log_target_to_string(log_get_target()));
1adf1049
LP
141}
142
718db961
LP
143static int property_set_log_target(
144 sd_bus *bus,
145 const char *path,
146 const char *interface,
147 const char *property,
148 sd_bus_message *value,
149 sd_bus_error *error,
150 void *userdata) {
151
c826cda4 152 const char *t;
718db961 153 int r;
c826cda4 154
718db961
LP
155 assert(bus);
156 assert(value);
c826cda4 157
718db961
LP
158 r = sd_bus_message_read(value, "s", &t);
159 if (r < 0)
160 return r;
c826cda4
AB
161
162 return log_set_target_from_string(t);
163}
164
718db961
LP
165static int property_get_log_level(
166 sd_bus *bus,
167 const char *path,
168 const char *interface,
169 const char *property,
170 sd_bus_message *reply,
171 sd_bus_error *error,
172 void *userdata) {
173
68eda4bd 174 _cleanup_free_ char *t = NULL;
f8b69d1d 175 int r;
1adf1049 176
718db961
LP
177 assert(bus);
178 assert(reply);
1adf1049 179
f8b69d1d
MS
180 r = log_level_to_string_alloc(log_get_max_level(), &t);
181 if (r < 0)
182 return r;
1adf1049 183
718db961 184 return sd_bus_message_append(reply, "s", t);
1adf1049
LP
185}
186
718db961
LP
187static int property_set_log_level(
188 sd_bus *bus,
189 const char *path,
190 const char *interface,
191 const char *property,
192 sd_bus_message *value,
193 sd_bus_error *error,
194 void *userdata) {
195
c826cda4 196 const char *t;
718db961 197 int r;
c826cda4 198
718db961
LP
199 assert(bus);
200 assert(value);
c826cda4 201
718db961
LP
202 r = sd_bus_message_read(value, "s", &t);
203 if (r < 0)
204 return r;
c826cda4
AB
205
206 return log_set_max_level_from_string(t);
207}
208
718db961
LP
209static int property_get_n_names(
210 sd_bus *bus,
211 const char *path,
212 const char *interface,
213 const char *property,
214 sd_bus_message *reply,
215 sd_bus_error *error,
216 void *userdata) {
4f0f902f 217
718db961 218 Manager *m = userdata;
4f0f902f 219
718db961
LP
220 assert(bus);
221 assert(reply);
222 assert(m);
4f0f902f 223
718db961 224 return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->units));
4f0f902f
LP
225}
226
718db961
LP
227static int property_get_n_jobs(
228 sd_bus *bus,
229 const char *path,
230 const char *interface,
231 const char *property,
232 sd_bus_message *reply,
233 sd_bus_error *error,
234 void *userdata) {
4f0f902f 235
718db961 236 Manager *m = userdata;
4f0f902f 237
718db961
LP
238 assert(bus);
239 assert(reply);
240 assert(m);
4f0f902f 241
718db961 242 return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->jobs));
4f0f902f
LP
243}
244
718db961
LP
245static int property_get_progress(
246 sd_bus *bus,
247 const char *path,
248 const char *interface,
249 const char *property,
250 sd_bus_message *reply,
251 sd_bus_error *error,
252 void *userdata) {
253
254 Manager *m = userdata;
05d6a3b6
LP
255 double d;
256
718db961
LP
257 assert(bus);
258 assert(reply);
bfebab7f 259 assert(m);
05d6a3b6
LP
260
261 if (dual_timestamp_is_set(&m->finish_timestamp))
262 d = 1.0;
263 else
264 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
265
718db961
LP
266 return sd_bus_message_append(reply, "d", d);
267}
268
269static int property_set_runtime_watchdog(
270 sd_bus *bus,
271 const char *path,
272 const char *interface,
273 const char *property,
274 sd_bus_message *value,
275 sd_bus_error *error,
276 void *userdata) {
05d6a3b6 277
718db961
LP
278 usec_t *t = userdata;
279 int r;
280
281 assert(bus);
282 assert(value);
283
284 assert_cc(sizeof(usec_t) == sizeof(uint64_t));
285
286 r = sd_bus_message_read(value, "t", t);
287 if (r < 0)
288 return r;
289
290 return watchdog_set_timeout(t);
05d6a3b6
LP
291}
292
718db961
LP
293static int method_get_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
294 _cleanup_free_ char *path = NULL;
295 Manager *m = userdata;
296 const char *name;
297 Unit *u;
298 int r;
dfae3488 299
718db961
LP
300 assert(bus);
301 assert(message);
dfae3488
LP
302 assert(m);
303
718db961
LP
304 r = sd_bus_message_read(message, "s", &name);
305 if (r < 0)
306 return sd_bus_reply_method_errno(bus, message, r, NULL);
dfae3488 307
718db961
LP
308 u = manager_get_unit(m, name);
309 if (!u)
310 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
dfae3488 311
718db961 312 SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "status");
dfae3488 313
718db961
LP
314 path = unit_dbus_path(u);
315 if (!path)
316 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
729e3769 317
718db961
LP
318 return sd_bus_reply_method_return(bus, message, "o", path);
319}
c0576cd6 320
718db961
LP
321static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata) {
322 _cleanup_free_ char *path = NULL;
323 Manager *m = userdata;
324 pid_t pid;
325 Unit *u;
326 int r;
c0576cd6 327
718db961
LP
328 assert(bus);
329 assert(message);
330 assert(m);
c0576cd6 331
718db961 332 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
729e3769 333
718db961
LP
334 r = sd_bus_message_read(message, "u", &pid);
335 if (r < 0)
336 return sd_bus_reply_method_errno(bus, message, r, NULL);
337
338 if (pid == 0) {
339 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
340 if (r < 0)
341 return sd_bus_reply_method_errno(bus, message, r, NULL);
729e3769
LP
342 }
343
718db961
LP
344 u = manager_get_unit_by_pid(m, pid);
345 if (!u)
346 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_UNIT_FOR_PID, "PID %u does not belong to any loaded unit.", pid);
c0576cd6 347
718db961
LP
348 SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "status");
349
350 path = unit_dbus_path(u);
351 if (!path)
352 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
353
354 return sd_bus_reply_method_return(bus, message, "o", path);
355}
356
357static int method_load_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
358 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
359 _cleanup_free_ char *path = NULL;
360 Manager *m = userdata;
361 const char *name;
362 Unit *u;
363 int r;
c0576cd6 364
718db961
LP
365 assert(bus);
366 assert(message);
367 assert(m);
368
369 r = sd_bus_message_read(message, "s", &name);
370 if (r < 0)
371 return sd_bus_reply_method_errno(bus, message, r, NULL);
c0576cd6 372
718db961
LP
373 r = manager_load_unit(m, name, NULL, &error, &u);
374 if (r < 0)
375 return sd_bus_reply_method_errno(bus, message, r, &error);
376
377 SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "status");
c0576cd6 378
718db961
LP
379 path = unit_dbus_path(u);
380 if (!path)
381 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
382
383 return sd_bus_reply_method_return(bus, message, "o", path);
c0576cd6
LP
384}
385
718db961
LP
386static int method_start_unit_generic(sd_bus *bus, sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible) {
387 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
388 const char *name;
389 Unit *u;
c0576cd6
LP
390 int r;
391
718db961
LP
392 assert(bus);
393 assert(message);
394 assert(m);
c0576cd6 395
718db961
LP
396 r = sd_bus_message_read(message, "s", &name);
397 if (r < 0)
398 return sd_bus_reply_method_errno(bus, message, r, NULL);
c0576cd6 399
718db961
LP
400 r = manager_load_unit(m, name, NULL, &error, &u);
401 if (r < 0)
402 return sd_bus_reply_method_errno(bus, message, r, &error);
403
404 return bus_unit_method_start_generic(bus, message, u, job_type, reload_if_possible);
c0576cd6
LP
405}
406
718db961
LP
407static int method_start_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
408 return method_start_unit_generic(bus, message, userdata, JOB_START, false);
409}
c757a65b 410
718db961
LP
411static int method_stop_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
412 return method_start_unit_generic(bus, message, userdata, JOB_STOP, false);
413}
c757a65b 414
718db961
LP
415static int method_reload_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
416 return method_start_unit_generic(bus, message, userdata, JOB_RELOAD, false);
417}
c757a65b 418
718db961
LP
419static int method_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
420 return method_start_unit_generic(bus, message, userdata, JOB_RESTART, false);
c757a65b
LP
421}
422
718db961
LP
423static int method_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
424 return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, false);
425}
d200735e 426
718db961
LP
427static int method_reload_or_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
428 return method_start_unit_generic(bus, message, userdata, JOB_RESTART, true);
429}
d200735e 430
718db961
LP
431static int method_reload_or_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
432 return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, true);
433}
d200735e 434
718db961
LP
435static int method_start_unit_replace(sd_bus *bus, sd_bus_message *message, void *userdata) {
436 Manager *m = userdata;
437 const char *old_name;
438 Unit *u;
1adf1049 439 int r;
ea430986 440
718db961 441 assert(bus);
ea430986
LP
442 assert(message);
443 assert(m);
444
718db961
LP
445 r = sd_bus_message_read(message, "s", &old_name);
446 if (r < 0)
447 return sd_bus_reply_method_errno(bus, message, r, NULL);
ea430986 448
718db961
LP
449 u = manager_get_unit(m, old_name);
450 if (!u || !u->job || u->job->type != JOB_START)
451 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
c0576cd6 452
718db961
LP
453 return method_start_unit_generic(bus, message, m, JOB_START, false);
454}
ea430986 455
718db961
LP
456static int method_kill_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
457 Manager *m = userdata;
458 const char *name;
459 Unit *u;
460 int r;
ea430986 461
718db961
LP
462 assert(bus);
463 assert(message);
464 assert(m);
ea430986 465
718db961
LP
466 r = sd_bus_message_read(message, "s", &name);
467 if (r < 0)
468 return sd_bus_reply_method_errno(bus, message, r, NULL);
598b557b 469
718db961
LP
470 u = manager_get_unit(m, name);
471 if (!u)
472 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
0a524ba7 473
718db961
LP
474 return bus_unit_method_kill(bus, message, u);
475}
8a0867d6 476
718db961
LP
477static int method_reset_failed_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
478 Manager *m = userdata;
479 const char *name;
480 Unit *u;
481 int r;
8a0867d6 482
718db961
LP
483 assert(bus);
484 assert(message);
485 assert(m);
cad45ba1 486
718db961
LP
487 r = sd_bus_message_read(message, "s", &name);
488 if (r < 0)
489 return sd_bus_reply_method_errno(bus, message, r, NULL);
ea430986 490
718db961
LP
491 u = manager_get_unit(m, name);
492 if (!u)
493 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
5dd9014f 494
718db961
LP
495 return bus_unit_method_reset_failed(bus, message, u);
496}
5dd9014f 497
718db961
LP
498static int method_set_unit_properties(sd_bus *bus, sd_bus_message *message, void *userdata) {
499 Manager *m = userdata;
500 const char *name;
501 Unit *u;
502 int r;
5dd9014f 503
718db961
LP
504 assert(bus);
505 assert(message);
506 assert(m);
507
508 r = sd_bus_message_read(message, "s", &name);
509 if (r < 0)
510 return sd_bus_reply_method_errno(bus, message, r, NULL);
511
512 u = manager_get_unit(m, name);
513 if (!u)
514 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
ea430986 515
718db961
LP
516 return bus_unit_method_set_properties(bus, message, u);
517}
518
519static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, void *userdata) {
520 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
521 const char *name, *smode;
522 Manager *m = userdata;
523 JobMode mode;
524 UnitType t;
525 Unit *u;
526 int r;
ea430986 527
718db961
LP
528 assert(bus);
529 assert(message);
530 assert(m);
ea430986 531
718db961
LP
532 r = sd_bus_message_read(message, "ss", &name, &smode);
533 if (r < 0)
534 return sd_bus_reply_method_errno(bus, message, r, NULL);
5632e374 535
718db961
LP
536 t = unit_name_to_type(name);
537 if (t < 0)
538 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type.");
cad45ba1 539
718db961
LP
540 if (!unit_vtable[t]->can_transient)
541 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.");
5632e374 542
718db961
LP
543 mode = job_mode_from_string(smode);
544 if (mode < 0)
545 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode);
5632e374 546
718db961
LP
547 r = manager_load_unit(m, name, NULL, &error, &u);
548 if (r < 0)
549 return sd_bus_reply_method_errno(bus, message, r, &error);
5632e374 550
718db961 551 SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "start");
5632e374 552
718db961
LP
553 if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0)
554 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
5632e374 555
718db961
LP
556 /* OK, the unit failed to load and is unreferenced, now let's
557 * fill in the transient data instead */
558 r = unit_make_transient(u);
559 if (r < 0)
560 return sd_bus_reply_method_errno(bus, message, r, NULL);
ea430986 561
718db961
LP
562 /* Set our properties */
563 r = bus_unit_set_properties(u, message, UNIT_RUNTIME, false, &error);
564 if (r < 0)
565 return sd_bus_reply_method_errno(bus, message, r, &error);
ea430986 566
718db961
LP
567 /* And load this stub fully */
568 r = unit_load(u);
569 if (r < 0)
570 return sd_bus_reply_method_errno(bus, message, r, &error);
ea430986 571
718db961 572 manager_dispatch_load_queue(m);
cad45ba1 573
718db961
LP
574 /* Finally, start it */
575 return bus_unit_queue_job(bus, message, u, JOB_START, mode, false);
576}
ea430986 577
718db961
LP
578static int method_get_job(sd_bus *bus, sd_bus_message *message, void *userdata) {
579 _cleanup_free_ char *path = NULL;
580 Manager *m = userdata;
581 uint32_t id;
582 Job *j;
583 int r;
ea430986 584
718db961
LP
585 assert(bus);
586 assert(message);
587 assert(m);
ea430986 588
718db961
LP
589 r = sd_bus_message_read(message, "u", &id);
590 if (r < 0)
591 return sd_bus_reply_method_errno(bus, message, r, NULL);
ea430986 592
718db961
LP
593 j = manager_get_job(m, id);
594 if (!j)
595 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
ea430986 596
718db961 597 SELINUX_UNIT_ACCESS_CHECK(j->unit, bus, message, "status");
ea430986 598
718db961
LP
599 path = job_dbus_path(j);
600 if (!path)
601 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
ea430986 602
718db961
LP
603 return sd_bus_reply_method_return(bus, message, "o", path);
604}
ea430986 605
718db961
LP
606static int method_cancel_job(sd_bus *bus, sd_bus_message *message, void *userdata) {
607 Manager *m = userdata;
608 uint32_t id;
609 Job *j;
610 int r;
ea430986 611
718db961
LP
612 assert(bus);
613 assert(message);
614 assert(m);
ea430986 615
718db961
LP
616 r = sd_bus_message_read(message, "u", &id);
617 if (r < 0)
618 return sd_bus_reply_method_errno(bus, message, r, NULL);
ea430986 619
718db961
LP
620 j = manager_get_job(m, id);
621 if (!j)
622 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
ea430986 623
718db961 624 SELINUX_UNIT_ACCESS_CHECK(j->unit, bus, message, "stop");
a567261a 625
718db961 626 job_finish_and_invalidate(j, JOB_CANCELED, true);
cad45ba1 627
718db961
LP
628 return sd_bus_reply_method_return(bus, message, NULL);
629}
c1e1601e 630
718db961
LP
631static int method_clear_jobs(sd_bus *bus, sd_bus_message *message, void *userdata) {
632 Manager *m = userdata;
c1e1601e 633
718db961
LP
634 assert(bus);
635 assert(message);
636 assert(m);
c1e1601e 637
718db961
LP
638 SELINUX_ACCESS_CHECK(bus, message, "reboot");
639 manager_clear_jobs(m);
c1e1601e 640
718db961
LP
641 return sd_bus_reply_method_return(bus, message, NULL);
642}
c1e1601e 643
718db961
LP
644static int method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata) {
645 Manager *m = userdata;
cad45ba1 646
718db961
LP
647 assert(bus);
648 assert(message);
649 assert(m);
650
651 SELINUX_ACCESS_CHECK(bus, message, "reload");
652 manager_reset_failed(m);
c1e1601e 653
718db961
LP
654 return sd_bus_reply_method_return(bus, message, NULL);
655}
c1e1601e 656
718db961
LP
657static int method_list_units(sd_bus *bus, sd_bus_message *message, void *userdata) {
658 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
659 Manager *m = userdata;
660 const char *k;
661 Iterator i;
662 Unit *u;
663 int r;
c1e1601e 664
718db961
LP
665 assert(bus);
666 assert(message);
667 assert(m);
b152adec 668
718db961 669 SELINUX_ACCESS_CHECK(bus, message, "status");
cad45ba1 670
718db961
LP
671 r = sd_bus_message_new_method_return(bus, message, &reply);
672 if (r < 0)
673 return sd_bus_reply_method_errno(bus, message, r, NULL);
b152adec 674
718db961
LP
675 r = sd_bus_message_open_container(reply, 'a', "(ssssssouso)");
676 if (r < 0)
677 return sd_bus_reply_method_errno(bus, message, r, NULL);
b152adec 678
718db961
LP
679 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
680 _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
681 Unit *following;
b152adec 682
718db961
LP
683 if (k != u->id)
684 continue;
b152adec 685
718db961 686 following = unit_following(u);
b152adec 687
718db961
LP
688 unit_path = unit_dbus_path(u);
689 if (!unit_path)
690 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
691
692 if (u->job) {
693 job_path = job_dbus_path(u->job);
694 if (!job_path)
695 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
b152adec
LP
696 }
697
718db961
LP
698 r = sd_bus_message_append(
699 reply, "(ssssssouso)",
700 u->id,
701 unit_description(u),
702 unit_load_state_to_string(u->load_state),
703 unit_active_state_to_string(unit_active_state(u)),
704 unit_sub_state_to_string(u),
705 following ? following->id : "",
706 unit_path,
707 u->job ? u->job->id : 0,
708 u->job ? job_type_to_string(u->job->type) : "",
709 job_path ? job_path : "/");
710 if (r < 0)
711 return sd_bus_reply_method_errno(bus, message, r, NULL);
712 }
4139c1b2 713
718db961
LP
714 r = sd_bus_message_close_container(reply);
715 if (r < 0)
716 return sd_bus_reply_method_errno(bus, message, r, NULL);
cad45ba1 717
718db961
LP
718 return sd_bus_send(bus, reply, NULL);
719}
4139c1b2 720
718db961
LP
721static int method_list_jobs(sd_bus *bus, sd_bus_message *message, void *userdata) {
722 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
723 Manager *m = userdata;
724 Iterator i;
725 Job *j;
726 int r;
4139c1b2 727
718db961
LP
728 assert(bus);
729 assert(message);
730 assert(m);
731
732 SELINUX_ACCESS_CHECK(bus, message, "status");
733
734 r = sd_bus_message_new_method_return(bus, message, &reply);
735 if (r < 0)
736 return sd_bus_reply_method_errno(bus, message, r, NULL);
737
738 r = sd_bus_message_open_container(reply, 'a', "(usssoo)");
739 if (r < 0)
740 return sd_bus_reply_method_errno(bus, message, r, NULL);
741
742 HASHMAP_FOREACH(j, m->jobs, i) {
743 _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
744
745 job_path = job_dbus_path(j);
746 if (!job_path)
747 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
748
749 unit_path = unit_dbus_path(j->unit);
750 if (!unit_path)
751 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
752
753 r = sd_bus_message_append(
754 reply, "(usssoo)",
755 j->id,
756 job_state_to_string(j->state),
757 job_type_to_string(j->type),
758 job_path,
759 unit_path);
cad45ba1 760 if (r < 0)
718db961
LP
761 return sd_bus_reply_method_errno(bus, message, r, NULL);
762 }
5dd9014f 763
718db961
LP
764 r = sd_bus_message_close_container(reply);
765 if (r < 0)
766 return sd_bus_reply_method_errno(bus, message, r, NULL);
5dd9014f 767
718db961
LP
768 return sd_bus_send(bus, reply, NULL);
769}
5dd9014f 770
718db961
LP
771static int method_subscribe(sd_bus *bus, sd_bus_message *message, void *userdata) {
772 Manager *m = userdata;
773 int r;
5dd9014f 774
718db961
LP
775 assert(bus);
776 assert(message);
777 assert(m);
ea430986 778
718db961 779 SELINUX_ACCESS_CHECK(bus, message, "status");
cad45ba1 780
718db961
LP
781 r = bus_client_track(&m->subscribed, bus, sd_bus_message_get_sender(message));
782 if (r < 0)
783 return sd_bus_reply_method_errno(bus, message, r, NULL);
784 if (r == 0)
785 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_ALREADY_SUBSCRIBED, "Client is already subscribed.");
ea430986 786
718db961
LP
787 return sd_bus_reply_method_return(bus, message, NULL);
788}
ea430986 789
718db961
LP
790static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userdata) {
791 Manager *m = userdata;
792 int r;
ea430986 793
718db961
LP
794 assert(bus);
795 assert(message);
796 assert(m);
ea430986 797
718db961 798 SELINUX_ACCESS_CHECK(bus, message, "status");
ea430986 799
718db961
LP
800 r = bus_client_untrack(m->subscribed, bus, sd_bus_message_get_sender(message));
801 if (r < 0)
802 return sd_bus_reply_method_errno(bus, message, r, NULL);
803 if (r == 0)
804 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
ea430986 805
718db961
LP
806 return sd_bus_reply_method_return(bus, message, NULL);
807}
ea430986 808
718db961
LP
809static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata) {
810 _cleanup_free_ char *dump = NULL;
811 _cleanup_fclose_ FILE *f = NULL;
812 Manager *m = userdata;
813 size_t size;
ea430986 814
718db961
LP
815 assert(bus);
816 assert(message);
817 assert(m);
ea430986 818
718db961 819 SELINUX_ACCESS_CHECK(bus, message, "status");
ea430986 820
718db961
LP
821 f = open_memstream(&dump, &size);
822 if (!f)
823 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
ea430986 824
718db961
LP
825 manager_dump_units(m, f, NULL);
826 manager_dump_jobs(m, f, NULL);
ea430986 827
718db961 828 fflush(f);
ea430986 829
718db961
LP
830 if (ferror(f))
831 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
a16e1123 832
718db961
LP
833 return sd_bus_reply_method_return(bus, message, "s", dump);
834}
cad45ba1 835
718db961
LP
836static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata) {
837 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
838 _cleanup_free_ char *path = NULL;
839 Manager *m = userdata;
840 const char *name;
841 int cleanup;
842 Snapshot *s;
843 int r;
a16e1123 844
718db961
LP
845 assert(bus);
846 assert(message);
847 assert(m);
a16e1123 848
718db961 849 SELINUX_ACCESS_CHECK(bus, message, "start");
a16e1123 850
718db961
LP
851 r = sd_bus_message_read(message, "sb", &name, &cleanup);
852 if (r < 0)
853 return sd_bus_reply_method_errno(bus, message, r, NULL);
a16e1123 854
718db961
LP
855 if (isempty(name))
856 name = NULL;
a16e1123 857
718db961
LP
858 r = snapshot_create(m, name, cleanup, &error, &s);
859 if (r < 0)
860 return sd_bus_reply_method_errno(bus, message, r, &error);
cad45ba1 861
718db961
LP
862 path = unit_dbus_path(UNIT(s));
863 if (!path)
864 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
a16e1123 865
718db961
LP
866 return sd_bus_reply_method_return(bus, message, "o", path);
867}
a16e1123 868
718db961
LP
869static int method_remove_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata) {
870 Manager *m = userdata;
871 const char *name;
872 Unit *u;
873 int r;
a16e1123 874
718db961
LP
875 assert(bus);
876 assert(message);
877 assert(m);
cad45ba1 878
718db961 879 SELINUX_ACCESS_CHECK(bus, message, "start");
a16e1123 880
718db961
LP
881 r = sd_bus_message_read(message, "s", &name);
882 if (r < 0)
883 return sd_bus_reply_method_errno(bus, message, r, NULL);
a16e1123 884
718db961
LP
885 u = manager_get_unit(m, name);
886 if (!u)
887 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
a16e1123 888
718db961
LP
889 if (u->type != UNIT_SNAPSHOT)
890 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name);
6652a2b9 891
718db961
LP
892 return bus_snapshot_method_remove(bus, message, u);
893}
cad45ba1 894
718db961
LP
895static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata) {
896 Manager *m = userdata;
897 int r;
6652a2b9 898
718db961
LP
899 assert(bus);
900 assert(message);
901 assert(m);
6652a2b9 902
718db961 903 SELINUX_ACCESS_CHECK(bus, message, "reload");
6652a2b9 904
718db961
LP
905 /* Instead of sending the reply back right away, we just
906 * remember that we need to and then send it after the reload
907 * is finished. That way the caller knows when the reload
908 * finished. */
6652a2b9 909
718db961
LP
910 assert(!m->queued_message);
911 r = sd_bus_message_new_method_return(bus, message, &m->queued_message);
912 if (r < 0)
913 return sd_bus_reply_method_errno(bus, message, r, NULL);
cad45ba1 914
718db961
LP
915 m->queued_message_bus = sd_bus_ref(bus);
916 m->exit_code = MANAGER_RELOAD;
6652a2b9 917
718db961
LP
918 return 1;
919}
6652a2b9 920
718db961
LP
921static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata) {
922 Manager *m = userdata;
6652a2b9 923
718db961
LP
924 assert(bus);
925 assert(message);
926 assert(m);
6652a2b9 927
718db961 928 SELINUX_ACCESS_CHECK(bus, message, "reload");
cad45ba1 929
718db961
LP
930 /* We don't send a reply back here, the client should
931 * just wait for us disconnecting. */
6652a2b9 932
718db961
LP
933 m->exit_code = MANAGER_REEXECUTE;
934 return 1;
935}
6652a2b9 936
718db961
LP
937static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata) {
938 Manager *m = userdata;
6652a2b9 939
718db961
LP
940 assert(bus);
941 assert(message);
942 assert(m);
6652a2b9 943
718db961 944 SELINUX_ACCESS_CHECK(bus, message, "halt");
cad45ba1 945
718db961
LP
946 if (m->running_as == SYSTEMD_SYSTEM)
947 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
6652a2b9 948
718db961 949 m->exit_code = MANAGER_EXIT;
6652a2b9 950
718db961
LP
951 return sd_bus_reply_method_return(bus, message, NULL);
952}
6652a2b9 953
718db961
LP
954static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata) {
955 Manager *m = userdata;
664f88a7 956
718db961
LP
957 assert(bus);
958 assert(message);
959 assert(m);
cad45ba1 960
718db961 961 SELINUX_ACCESS_CHECK(bus, message, "reboot");
664f88a7 962
718db961
LP
963 if (m->running_as != SYSTEMD_SYSTEM)
964 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
664f88a7 965
718db961 966 m->exit_code = MANAGER_REBOOT;
664f88a7 967
718db961
LP
968 return sd_bus_reply_method_return(bus, message, NULL);
969}
664f88a7 970
50913bc0 971
718db961
LP
972static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata) {
973 Manager *m = userdata;
50913bc0 974
718db961
LP
975 assert(bus);
976 assert(message);
977 assert(m);
1137a57c 978
718db961 979 SELINUX_ACCESS_CHECK(bus, message, "halt");
1137a57c 980
718db961
LP
981 if (m->running_as != SYSTEMD_SYSTEM)
982 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1137a57c 983
718db961 984 m->exit_code = MANAGER_POWEROFF;
1137a57c 985
718db961
LP
986 return sd_bus_reply_method_return(bus, message, NULL);
987}
1137a57c 988
718db961
LP
989static int method_halt(sd_bus *bus, sd_bus_message *message, void *userdata) {
990 Manager *m = userdata;
1137a57c 991
718db961
LP
992 assert(bus);
993 assert(message);
994 assert(m);
8d0e38a2 995
718db961 996 SELINUX_ACCESS_CHECK(bus, message, "halt");
cad45ba1 997
718db961
LP
998 if (m->running_as != SYSTEMD_SYSTEM)
999 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
8d0e38a2 1000
718db961 1001 m->exit_code = MANAGER_HALT;
8d0e38a2 1002
718db961
LP
1003 return sd_bus_reply_method_return(bus, message, NULL);
1004}
8d0e38a2 1005
718db961
LP
1006static int method_kexec(sd_bus *bus, sd_bus_message *message, void *userdata) {
1007 Manager *m = userdata;
8d0e38a2 1008
718db961
LP
1009 assert(bus);
1010 assert(message);
1011 assert(m);
c0576cd6 1012
718db961 1013 SELINUX_ACCESS_CHECK(bus, message, "reboot");
cad45ba1 1014
718db961
LP
1015 if (m->running_as != SYSTEMD_SYSTEM)
1016 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
c0576cd6 1017
718db961 1018 m->exit_code = MANAGER_KEXEC;
c0576cd6 1019
718db961
LP
1020 return sd_bus_reply_method_return(bus, message, NULL);
1021}
c0576cd6 1022
718db961
LP
1023static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userdata) {
1024 char *ri = NULL, *rt = NULL;
1025 const char *root, *init;
1026 Manager *m = userdata;
1027 int r;
c0576cd6 1028
718db961
LP
1029 assert(bus);
1030 assert(message);
1031 assert(m);
c0576cd6 1032
718db961 1033 SELINUX_ACCESS_CHECK(bus, message, "reboot");
c0576cd6 1034
718db961
LP
1035 if (m->running_as != SYSTEMD_SYSTEM)
1036 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
c0576cd6 1037
718db961
LP
1038 r = sd_bus_message_read(message, "ss", &root, &init);
1039 if (r < 0)
1040 return sd_bus_reply_method_errno(bus, message, r, NULL);
c0576cd6 1041
718db961
LP
1042 if (path_equal(root, "/") || !path_is_absolute(root))
1043 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid switch root path %s", root);
c0576cd6 1044
718db961
LP
1045 /* Safety check */
1046 if (isempty(init)) {
1047 if (! path_is_os_tree(root))
1048 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path %s does not seem to be an OS tree. /etc/os-release is missing.", root);
1049 } else {
1050 _cleanup_free_ char *p = NULL;
c0576cd6 1051
718db961
LP
1052 if (!path_is_absolute(init))
1053 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid init path %s", init);
c0576cd6 1054
718db961
LP
1055 p = strappend(root, init);
1056 if (!p)
1057 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
c0576cd6 1058
718db961
LP
1059 if (access(p, X_OK) < 0)
1060 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Specified init binary %s does not exist.", p);
1061 }
1062
1063 rt = strdup(root);
1064 if (!rt)
1065 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
1066
1067 if (!isempty(init)) {
1068 ri = strdup(init);
1069 if (!ri) {
1070 free(ri);
1071 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
c0576cd6 1072 }
718db961 1073 }
c0576cd6 1074
718db961
LP
1075 free(m->switch_root);
1076 m->switch_root = rt;
c0576cd6 1077
718db961
LP
1078 free(m->switch_root_init);
1079 m->switch_root_init = ri;
c0576cd6 1080
718db961
LP
1081 return sd_bus_reply_method_return(bus, message, NULL);
1082}
c0576cd6 1083
718db961
LP
1084static int method_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata) {
1085 _cleanup_strv_free_ char **plus = NULL;
1086 Manager *m = userdata;
1087 int r;
c0576cd6 1088
718db961
LP
1089 assert(bus);
1090 assert(message);
1091 assert(m);
cad45ba1 1092
718db961 1093 SELINUX_ACCESS_CHECK(bus, message, "reload");
c0576cd6 1094
718db961
LP
1095 r = sd_bus_message_read_strv(message, &plus);
1096 if (r < 0)
1097 return sd_bus_reply_method_errno(bus, message, r, NULL);
1098 if (!strv_env_is_valid(plus))
1099 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
c0576cd6 1100
718db961
LP
1101 r = manager_environment_add(m, NULL, plus);
1102 if (r < 0)
1103 return sd_bus_reply_method_errno(bus, message, r, NULL);
c0576cd6 1104
718db961
LP
1105 return sd_bus_reply_method_return(bus, message, NULL);
1106}
1107
1108static int method_unset_environment(sd_bus *bus, sd_bus_message *message, void *userdata) {
1109 _cleanup_strv_free_ char **minus = NULL;
1110 Manager *m = userdata;
1111 int r;
1112
1113 assert(bus);
1114 assert(message);
1115 assert(m);
1116
1117 SELINUX_ACCESS_CHECK(bus, message, "reload");
c0576cd6 1118
718db961
LP
1119 r = sd_bus_message_read_strv(message, &minus);
1120 if (r < 0)
1121 return sd_bus_reply_method_errno(bus, message, r, NULL);
1122
1123 if (!strv_env_name_or_assignment_is_valid(minus))
1124 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
1125
1126 r = manager_environment_add(m, minus, NULL);
1127 if (r < 0)
1128 return sd_bus_reply_method_errno(bus, message, r, NULL);
1129
1130 return sd_bus_reply_method_return(bus, message, NULL);
1131}
1132
1133static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata) {
1134 _cleanup_strv_free_ char **minus = NULL, **plus = NULL;
1135 Manager *m = userdata;
1136 int r;
1137
1138 assert(bus);
1139 assert(message);
1140 assert(m);
1141
1142 SELINUX_ACCESS_CHECK(bus, message, "reload");
1143
1144 r = sd_bus_message_read_strv(message, &plus);
1145 if (r < 0)
1146 return sd_bus_reply_method_errno(bus, message, r, NULL);
1147
1148 r = sd_bus_message_read_strv(message, &minus);
1149 if (r < 0)
1150 return sd_bus_reply_method_errno(bus, message, r, NULL);
1151
1152 if (!strv_env_is_valid(plus))
1153 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
1154 if (!strv_env_name_or_assignment_is_valid(minus))
1155 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
1156
1157 r = manager_environment_add(m, minus, plus);
1158 if (r < 0)
1159 return sd_bus_reply_method_errno(bus, message, r, NULL);
1160
1161 return sd_bus_reply_method_return(bus, message, NULL);
1162}
1163
1164static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
1165 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1166 Manager *m = userdata;
1167 UnitFileList *item;
1168 Hashmap *h;
1169 Iterator i;
1170 int r;
1171
1172 assert(bus);
1173 assert(message);
1174 assert(m);
1175
1176 SELINUX_ACCESS_CHECK(bus, message, "status");
1177
1178 r = sd_bus_message_new_method_return(bus, message, &reply);
1179 if (r < 0)
1180 return sd_bus_reply_method_errno(bus, message, r, NULL);
c0576cd6 1181
718db961
LP
1182 h = hashmap_new(string_hash_func, string_compare_func);
1183 if (!h)
1184 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
c0576cd6 1185
718db961
LP
1186 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1187 if (r < 0) {
1188 r = sd_bus_reply_method_errno(bus, message, r, NULL);
1189 goto fail;
1190 }
1191
1192 r = sd_bus_message_open_container(reply, 'a', "(ss)");
1193 if (r < 0) {
1194 r = sd_bus_reply_method_errno(bus, message, r, NULL);
1195 goto fail;
1196 }
1197
1198 HASHMAP_FOREACH(item, h, i) {
1199
1200 r = sd_bus_message_append(reply, "(ss)", item->path, unit_file_state_to_string(item->state));
c0576cd6 1201 if (r < 0) {
718db961
LP
1202 r = sd_bus_reply_method_errno(bus, message, r, NULL);
1203 goto fail;
c0576cd6 1204 }
718db961 1205 }
c0576cd6 1206
718db961 1207 unit_file_list_free(h);
c0576cd6 1208
718db961
LP
1209 r = sd_bus_message_close_container(reply);
1210 if (r < 0)
1211 return sd_bus_reply_method_errno(bus, message, r, NULL);
8d0e38a2 1212
718db961 1213 return sd_bus_send(bus, reply, NULL);
99504dd4 1214
718db961
LP
1215fail:
1216 unit_file_list_free(h);
1217 return r;
1218}
99504dd4 1219
718db961
LP
1220static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void *userdata) {
1221 Manager *m = userdata;
1222 const char *name;
1223 UnitFileState state;
1224 UnitFileScope scope;
1225 int r;
99504dd4 1226
718db961
LP
1227 assert(bus);
1228 assert(message);
1229 assert(m);
8e2af478 1230
718db961 1231 SELINUX_ACCESS_CHECK(bus, message, "status");
8e2af478 1232
718db961
LP
1233 r = sd_bus_message_read(message, "s", &name);
1234 if (r < 0)
1235 return sd_bus_reply_method_errno(bus, message, r, NULL);
8e2af478 1236
718db961 1237 scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
8e2af478 1238
718db961
LP
1239 state = unit_file_get_state(scope, NULL, name);
1240 if (state < 0)
1241 return sd_bus_reply_method_errno(bus, message, state, NULL);
8e2af478 1242
718db961
LP
1243 return sd_bus_reply_method_return(bus, message, "s", unit_file_state_to_string(state));
1244}
8e2af478 1245
718db961
LP
1246static int method_get_default_target(sd_bus *bus, sd_bus_message *message, void *userdata) {
1247 _cleanup_free_ char *default_target = NULL;
1248 Manager *m = userdata;
1249 UnitFileScope scope;
1250 int r;
c2756a68 1251
718db961
LP
1252 assert(bus);
1253 assert(message);
1254 assert(m);
c2756a68 1255
718db961 1256 SELINUX_ACCESS_CHECK(bus, message, "status");
c2756a68 1257
718db961 1258 scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
c2756a68 1259
718db961
LP
1260 r = unit_file_get_default(scope, NULL, &default_target);
1261 if (r < 0)
1262 return sd_bus_reply_method_errno(bus, message, r, NULL);
c2756a68 1263
718db961
LP
1264 return sd_bus_reply_method_return(bus, message, "s", default_target);
1265}
c2756a68 1266
718db961
LP
1267static int send_unit_files_changed(sd_bus *bus, const char *destination, void *userdata) {
1268 _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
1269 int r;
1270
1271 assert(bus);
1272
1273 r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged", &message);
1274 if (r < 0)
1275 return r;
1276
1277 return sd_bus_send_to(bus, message, destination, NULL);
1278}
1279
1280static int reply_unit_file_changes_and_free(
1281 Manager *m,
1282 sd_bus *bus,
1283 sd_bus_message *message,
1284 int carries_install_info,
1285 UnitFileChange *changes,
1286 unsigned n_changes) {
1287
1288 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1289 unsigned i;
1290 int r;
1291
1292 if (n_changes > 0)
1293 bus_manager_foreach_client(m, send_unit_files_changed, NULL);
1294
1295 r = sd_bus_message_new_method_return(bus, message, &reply);
1296 if (r < 0)
1297 goto fail;
1298
1299 if (carries_install_info >= 0) {
1300 r = sd_bus_message_append(reply, "b", carries_install_info);
c2756a68 1301 if (r < 0)
718db961
LP
1302 goto fail;
1303 }
1304
1305 r = sd_bus_message_open_container(reply, 'a', "(sss)");
1306 if (r < 0)
1307 goto fail;
c2756a68 1308
718db961
LP
1309 for (i = 0; i < n_changes; i++) {
1310 r = sd_bus_message_append(
1311 message, "(sss)",
1312 unit_file_change_type_to_string(changes[i].type),
1313 changes[i].path,
1314 changes[i].source);
c2756a68 1315 if (r < 0)
718db961
LP
1316 goto fail;
1317 }
c2756a68 1318
718db961
LP
1319 r = sd_bus_message_close_container(reply);
1320 if (r < 0)
1321 goto fail;
c2756a68 1322
718db961 1323 return sd_bus_send(bus, message, NULL);
c2756a68 1324
718db961
LP
1325fail:
1326 unit_file_changes_free(changes, n_changes);
1327 return sd_bus_reply_method_errno(bus, message, r, NULL);
1328}
cad45ba1 1329
718db961
LP
1330static int method_enable_unit_files_generic(
1331 sd_bus *bus,
1332 sd_bus_message *message,
1333 Manager *m, const
1334 char *verb,
1335 int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes),
1336 bool carries_install_info) {
1337
1338 _cleanup_strv_free_ char **l = NULL;
1339 UnitFileChange *changes = NULL;
1340 unsigned n_changes = 0;
1341 UnitFileScope scope;
1342 int runtime, force, r;
1343
1344 assert(bus);
1345 assert(message);
1346 assert(m);
cad45ba1 1347
718db961 1348 SELINUX_ACCESS_CHECK(bus, message, verb);
ea430986 1349
718db961
LP
1350 r = sd_bus_message_read_strv(message, &l);
1351 if (r < 0)
1352 return sd_bus_reply_method_errno(bus, message, r, NULL);
90bb85e1 1353
718db961
LP
1354 r = sd_bus_message_read(message, "bb", &runtime, &force);
1355 if (r < 0)
1356 return sd_bus_reply_method_errno(bus, message, r, NULL);
c87eba54 1357
718db961 1358 scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
c87eba54 1359
718db961
LP
1360 r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
1361 if (r < 0)
1362 return sd_bus_reply_method_errno(bus, message, r, NULL);
1363
1364 return reply_unit_file_changes_and_free(m, bus, message, carries_install_info ? r : -1, changes, n_changes);
1365}
c87eba54 1366
718db961
LP
1367static int method_enable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
1368 return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_enable, true);
1369}
ea430986 1370
718db961
LP
1371static int method_reenable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
1372 return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_reenable, true);
1373}
1374
1375static int method_link_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
1376 return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_link, false);
1377}
1378
1379static int method_preset_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
1380 return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_preset, true);
1381}
1382
1383static int method_mask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
1384 return method_enable_unit_files_generic(bus, message, userdata, "disable", unit_file_mask, false);
1385}
ea430986 1386
718db961
LP
1387static int method_disable_unit_files_generic(
1388 sd_bus *bus,
1389 sd_bus_message *message,
1390 Manager *m, const
1391 char *verb,
1392 int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes)) {
1393
1394 _cleanup_strv_free_ char **l = NULL;
1395 UnitFileChange *changes = NULL;
1396 unsigned n_changes = 0;
1397 UnitFileScope scope;
1398 int r, runtime;
1399
1400 assert(bus);
1401 assert(message);
1402 assert(m);
1403
1404 SELINUX_ACCESS_CHECK(bus, message, verb);
1405
1406 r = sd_bus_message_read_strv(message, &l);
1407 if (r < 0)
1408 return sd_bus_reply_method_errno(bus, message, r, NULL);
1409
1410 r = sd_bus_message_read(message, "b", &runtime);
1411 if (r < 0)
1412 return sd_bus_reply_method_errno(bus, message, r, NULL);
1413
1414 scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1415
1416 r = call(scope, runtime, NULL, l, &changes, &n_changes);
1417 if (r < 0)
1418 return sd_bus_reply_method_errno(bus, message, r, NULL);
1419
1420 return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
1421}
ea430986 1422
718db961
LP
1423static int method_disable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
1424 return method_disable_unit_files_generic(bus, message, userdata, "disable", unit_file_disable);
ea430986
LP
1425}
1426
718db961
LP
1427static int method_unmask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata) {
1428 return method_disable_unit_files_generic(bus, message, userdata, "enable", unit_file_unmask);
1429}
1430
1431static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void *userdata) {
1432 UnitFileChange *changes = NULL;
1433 unsigned n_changes = 0;
1434 Manager *m = userdata;
1435 UnitFileScope scope;
1436 const char *name;
1437 int force, r;
1438
1439 assert(bus);
1440 assert(message);
1441 assert(m);
1442
1443 SELINUX_ACCESS_CHECK(bus, message, "enable");
1444
1445 r = sd_bus_message_read(message, "sb", &name, &force);
1446 if (r < 0)
1447 return sd_bus_reply_method_errno(bus, message, r, NULL);
1448
1449 scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1450
1451 r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes);
1452 if (r < 0)
1453 return sd_bus_reply_method_errno(bus, message, r, NULL);
1454
1455 return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
1456}
1457
1458const sd_bus_vtable bus_manager_vtable[] = {
1459 SD_BUS_VTABLE_START(0),
1460
1461 SD_BUS_PROPERTY("Version", "s", property_get_version, 0, 0),
1462 SD_BUS_PROPERTY("Features", "s", property_get_features, 0, 0),
1463 SD_BUS_PROPERTY("Virtualization", "s", property_get_virtualization, 0, 0),
1464 SD_BUS_PROPERTY("Tainted", "s", property_get_tainted, 0, 0),
1465 BUS_PROPERTY_DUAL_TIMESTAMP("FirmwareTimestamp", offsetof(Manager, firmware_timestamp), 0),
1466 BUS_PROPERTY_DUAL_TIMESTAMP("LoaderTimestamp", offsetof(Manager, loader_timestamp), 0),
1467 BUS_PROPERTY_DUAL_TIMESTAMP("KernelTimestamp", offsetof(Manager, firmware_timestamp), 0),
1468 BUS_PROPERTY_DUAL_TIMESTAMP("InitRDTimestamp", offsetof(Manager, initrd_timestamp), 0),
1469 BUS_PROPERTY_DUAL_TIMESTAMP("UserspaceTimestamp", offsetof(Manager, userspace_timestamp), 0),
1470 BUS_PROPERTY_DUAL_TIMESTAMP("FinishTimestamp", offsetof(Manager, finish_timestamp), 0),
1471 BUS_PROPERTY_DUAL_TIMESTAMP("SecurityStartTimestamp", offsetof(Manager, security_start_timestamp), 0),
1472 BUS_PROPERTY_DUAL_TIMESTAMP("SecurityFinishTimestamp", offsetof(Manager, security_finish_timestamp), 0),
1473 BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsStartTimestamp", offsetof(Manager, generators_start_timestamp), 0),
1474 BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, generators_finish_timestamp), 0),
1475 BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, units_load_start_timestamp), 0),
1476 BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, units_load_finish_timestamp), 0),
1477 SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0),
1478 SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0),
1479 SD_BUS_PROPERTY("NNames", "u", property_get_n_names, 0, 0),
1480 SD_BUS_PROPERTY("NJobs", "u", property_get_n_jobs, 0, 0),
1481 SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0),
1482 SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0),
1483 SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
1484 SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0),
1485 SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), 0),
1486 SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), 0),
1487 SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), 0),
1488 SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), 0),
1489 SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), 0),
1490 SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
1491 SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0),
1492
1493 SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, 0),
1494 SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, 0),
1495 SD_BUS_METHOD("LoadUnit", "s", "o", method_load_unit, 0),
1496 SD_BUS_METHOD("StartUnit", "ss", "o", method_start_unit, 0),
1497 SD_BUS_METHOD("StartUnitReplace", "sss", "o", method_start_unit_replace, 0),
1498 SD_BUS_METHOD("StopUnit", "ss", "o", method_stop_unit, 0),
1499 SD_BUS_METHOD("ReloadUnit", "ss", "o", method_reload_unit, 0),
1500 SD_BUS_METHOD("RestartUnit", "ss", "o", method_restart_unit, 0),
1501 SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, 0),
1502 SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, 0),
1503 SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, 0),
1504 SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, 0),
1505 SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, 0),
1506 SD_BUS_METHOD("SetUnitProperties", "sb", "a(sv)", method_set_unit_properties, 0),
1507 SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, 0),
1508 SD_BUS_METHOD("GetJob", "u", "o", method_get_job, 0),
1509 SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, 0),
1510 SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, 0),
1511 SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, 0),
1512 SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, 0),
1513 SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, 0),
1514 SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, 0),
1515 SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, 0),
1516 SD_BUS_METHOD("Dump", NULL, "s", method_dump, 0),
1517 SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, 0),
1518 SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, 0),
1519 SD_BUS_METHOD("Reload", NULL, NULL, method_reload, 0),
1520 SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, 0),
1521 SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),
1522 SD_BUS_METHOD("Reboot", NULL, NULL, method_reboot, 0),
1523 SD_BUS_METHOD("PowerOff", NULL, NULL, method_poweroff, 0),
1524 SD_BUS_METHOD("Halt", NULL, NULL, method_halt, 0),
1525 SD_BUS_METHOD("KExec", NULL, NULL, method_kexec, 0),
1526 SD_BUS_METHOD("SwitchRoot", "ss", NULL, method_switch_root, 0),
1527 SD_BUS_METHOD("SetEnvironment", "as", NULL, method_set_environment, 0),
1528 SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, 0),
1529 SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, 0),
1530 SD_BUS_METHOD("ListUnitFiles", NULL, "a(ss)", method_list_unit_files, 0),
1531 SD_BUS_METHOD("GetUnitFileState", "s", "s", method_get_unit_file_state, 0),
1532 SD_BUS_METHOD("EnableUnitFiles", "asbb", "ba(sss)", method_enable_unit_files, 0),
1533 SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", method_disable_unit_files, 0),
1534 SD_BUS_METHOD("ReenableUnitFiles", "asbb", "ba(sss)", method_reenable_unit_files, 0),
1535 SD_BUS_METHOD("LinkUnitFiles", "asbb", "a(sss)", method_link_unit_files, 0),
1536 SD_BUS_METHOD("PresetUnitFiles", "asbb", "ba(sss)", method_preset_unit_files, 0),
1537 SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, 0),
1538 SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, 0),
1539 SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, 0),
1540 SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, 0),
1541
1542 SD_BUS_SIGNAL("UnitNew", "so", 0),
1543 SD_BUS_SIGNAL("UnitRemoved", "so", 0),
1544 SD_BUS_SIGNAL("JobNew", "uos", 0),
1545 SD_BUS_SIGNAL("JobRemoved", "uoss", 0),
1546 SD_BUS_SIGNAL("StartupFinished", "tttttt", 0),
1547 SD_BUS_SIGNAL("UnitFilesChanged", NULL, 0),
1548 SD_BUS_SIGNAL("Reloading", "b", 0),
1549
1550 SD_BUS_VTABLE_END
ea430986 1551};
718db961
LP
1552
1553int bus_manager_foreach_client(Manager *m, int (*send_message)(sd_bus *bus, const char *destination, void *userdata), void *userdata) {
1554 Iterator i;
1555 sd_bus *b;
1556 unsigned n;
1557 int r;
1558
1559 n = set_size(m->subscribed);
1560 if (n <= 0)
1561 return 0;
1562 if (n == 1) {
1563 BusTrackedClient *d;
1564
1565 assert_se(d = set_first(m->subscribed));
1566 return send_message(d->bus, isempty(d->name) ? NULL : d->name, userdata);
1567 }
1568
1569 /* Send to everybody */
1570 SET_FOREACH(b, m->private_buses, i) {
1571 r = send_message(b, NULL, userdata);
1572 if (r < 0)
1573 return r;
1574 }
1575
1576 if (m->api_bus)
1577 return send_message(m->api_bus, NULL, userdata);
1578
1579 return 0;
1580}
1581
1582static int send_finished(sd_bus *bus, const char *destination, void *userdata) {
1583 _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
1584 usec_t *times = userdata;
1585 int r;
1586
1587 assert(bus);
1588 assert(times);
1589
1590 r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished", &message);
1591 if (r < 0)
1592 return r;
1593
1594 r = sd_bus_message_append(message, "tttttt", times[0], times[1], times[2], times[3], times[4], times[5]);
1595 if (r < 0)
1596 return r;
1597
1598 return sd_bus_send_to(bus, message, destination, NULL);
1599}
1600
1601int bus_manager_send_finished(
1602 Manager *m,
1603 usec_t firmware_usec,
1604 usec_t loader_usec,
1605 usec_t kernel_usec,
1606 usec_t initrd_usec,
1607 usec_t userspace_usec,
1608 usec_t total_usec) {
1609
1610 assert(m);
1611
1612 return bus_manager_foreach_client(m, send_finished,
1613 (usec_t[6]) { firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec });
1614}
1615
1616static int send_reloading(sd_bus *bus, const char *destination, void *userdata) {
1617 _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
1618 int r;
1619
1620 assert(bus);
1621
1622 r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reloading", &message);
1623 if (r < 0)
1624 return r;
1625
1626 r = sd_bus_message_append(message, "b", PTR_TO_INT(userdata));
1627 if (r < 0)
1628 return r;
1629
1630 return sd_bus_send_to(bus, message, destination, NULL);
1631}
1632
1633int bus_manager_send_reloading(Manager *m, bool active) {
1634 assert(m);
1635
1636 return bus_manager_foreach_client(m, send_reloading, INT_TO_PTR(active));
1637}