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