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