]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
Make systemctl --root look for files in the proper places
[thirdparty/systemd.git] / src / machine / machined-dbus.c
CommitLineData
1ee306e1
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <string.h>
24#include <unistd.h>
25#include <pwd.h>
adacb957 26#include <sys/capability.h>
1ee306e1 27
c3350683
LP
28#include "sd-id128.h"
29#include "sd-messages.h"
1ee306e1 30
1ee306e1
LP
31#include "strv.h"
32#include "mkdir.h"
33#include "path-util.h"
34#include "special.h"
1ee306e1
LP
35#include "fileio-label.h"
36#include "label.h"
37#include "utf8.h"
38#include "unit-name.h"
c3350683 39#include "bus-util.h"
718db961 40#include "bus-errors.h"
c3350683 41#include "time-util.h"
23c80348 42#include "cgroup-util.h"
c3350683 43#include "machined.h"
1ee306e1
LP
44
45static bool valid_machine_name(const char *p) {
46 size_t l;
47
48 if (!filename_is_safe(p))
49 return false;
50
51 if (!ascii_is_valid(p))
52 return false;
53
54 l = strlen(p);
55
56 if (l < 1 || l> 64)
57 return false;
58
59 return true;
60}
61
ebcf1f97 62static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
63 _cleanup_free_ char *p = NULL;
64 Manager *m = userdata;
65 Machine *machine;
66 const char *name;
67 int r;
68
69 assert(bus);
70 assert(message);
71 assert(m);
72
73 r = sd_bus_message_read(message, "s", &name);
74 if (r < 0)
ebcf1f97 75 return r;
c3350683
LP
76
77 machine = hashmap_get(m->machines, name);
78 if (!machine)
ebcf1f97 79 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
c3350683
LP
80
81 p = machine_bus_path(machine);
82 if (!p)
ebcf1f97 83 return -ENOMEM;
c3350683 84
df2d202e 85 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
86}
87
ebcf1f97 88static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
89 _cleanup_free_ char *p = NULL;
90 Manager *m = userdata;
91 Machine *machine = NULL;
4e724d9c 92 pid_t pid;
c3350683
LP
93 int r;
94
95 assert(bus);
96 assert(message);
97 assert(m);
98
4e724d9c
LP
99 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
100
c3350683
LP
101 r = sd_bus_message_read(message, "u", &pid);
102 if (r < 0)
ebcf1f97 103 return r;
c3350683 104
4e724d9c 105 if (pid == 0) {
5b12334d
LP
106 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
107
108 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
109 if (r < 0)
110 return r;
111
112 r = sd_bus_creds_get_pid(creds, &pid);
4e724d9c 113 if (r < 0)
ebcf1f97 114 return r;
4e724d9c
LP
115 }
116
c3350683
LP
117 r = manager_get_machine_by_pid(m, pid, &machine);
118 if (r < 0)
ebcf1f97 119 return r;
c3350683 120 if (!machine)
ebcf1f97 121 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID %lu does not belong to any known machine", (unsigned long) pid);
c3350683
LP
122
123 p = machine_bus_path(machine);
124 if (!p)
ebcf1f97 125 return -ENOMEM;
c3350683 126
df2d202e 127 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
128}
129
ebcf1f97 130static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
131 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
132 Manager *m = userdata;
133 Machine *machine;
134 Iterator i;
135 int r;
136
137 assert(bus);
138 assert(message);
139 assert(m);
140
df2d202e 141 r = sd_bus_message_new_method_return(message, &reply);
c3350683 142 if (r < 0)
ebcf1f97 143 return sd_bus_error_set_errno(error, r);
c3350683
LP
144
145 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
146 if (r < 0)
ebcf1f97 147 return sd_bus_error_set_errno(error, r);
c3350683
LP
148
149 HASHMAP_FOREACH(machine, m->machines, i) {
150 _cleanup_free_ char *p = NULL;
151
152 p = machine_bus_path(machine);
153 if (!p)
ebcf1f97 154 return -ENOMEM;
c3350683
LP
155
156 r = sd_bus_message_append(reply, "(ssso)",
157 machine->name,
158 strempty(machine_class_to_string(machine->class)),
159 machine->service,
160 p);
161 if (r < 0)
ebcf1f97 162 return sd_bus_error_set_errno(error, r);
c3350683 163 }
1ee306e1 164
c3350683
LP
165 r = sd_bus_message_close_container(reply);
166 if (r < 0)
ebcf1f97 167 return sd_bus_error_set_errno(error, r);
c3350683
LP
168
169 return sd_bus_send(bus, reply, NULL);
170}
171
89f7c846 172static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, Machine **_m, sd_bus_error *error) {
8aec412f 173 const char *name, *service, *class, *root_directory;
1ee306e1
LP
174 MachineClass c;
175 uint32_t leader;
176 sd_id128_t id;
c3350683 177 const void *v;
1ee306e1 178 Machine *m;
c3350683
LP
179 size_t n;
180 int r;
1ee306e1 181
c3350683 182 assert(manager);
89f7c846
LP
183 assert(message);
184 assert(_m);
1ee306e1 185
c3350683
LP
186 r = sd_bus_message_read(message, "s", &name);
187 if (r < 0)
ebcf1f97 188 return r;
c3350683 189 if (!valid_machine_name(name))
ebcf1f97 190 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 191
c3350683
LP
192 r = sd_bus_message_read_array(message, 'y', &v, &n);
193 if (r < 0)
ebcf1f97 194 return r;
1ee306e1
LP
195 if (n == 0)
196 id = SD_ID128_NULL;
197 else if (n == 16)
198 memcpy(&id, v, n);
199 else
ebcf1f97 200 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 201
c3350683
LP
202 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
203 if (r < 0)
ebcf1f97 204 return r;
1ee306e1
LP
205
206 if (isempty(class))
207 c = _MACHINE_CLASS_INVALID;
208 else {
209 c = machine_class_from_string(class);
210 if (c < 0)
ebcf1f97 211 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
212 }
213
c3350683 214 if (leader == 1)
ebcf1f97 215 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 216
c3350683 217 if (!isempty(root_directory) && !path_is_absolute(root_directory))
ebcf1f97 218 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 219
c3350683 220 if (leader == 0) {
5b12334d
LP
221 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
222
223 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
224 if (r < 0)
225 return r;
226
c3350683 227 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
554604b3 228
5b12334d 229 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c3350683 230 if (r < 0)
ebcf1f97 231 return r;
c3350683 232 }
554604b3 233
1ee306e1 234 if (hashmap_get(manager->machines, name))
ebcf1f97 235 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1
LP
236
237 r = manager_add_machine(manager, name, &m);
238 if (r < 0)
ebcf1f97 239 return r;
1ee306e1
LP
240
241 m->leader = leader;
242 m->class = c;
243 m->id = id;
244
245 if (!isempty(service)) {
246 m->service = strdup(service);
247 if (!m->service) {
ebcf1f97 248 r = -ENOMEM;
1ee306e1
LP
249 goto fail;
250 }
251 }
252
253 if (!isempty(root_directory)) {
254 m->root_directory = strdup(root_directory);
255 if (!m->root_directory) {
ebcf1f97 256 r = -ENOMEM;
1ee306e1
LP
257 goto fail;
258 }
259 }
260
89f7c846
LP
261 *_m = m;
262
263 return 1;
264
265fail:
266 machine_add_to_gc_queue(m);
267 return r;
268}
269
270static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
271 Manager *manager = userdata;
272 Machine *m = NULL;
273 int r;
274
275 r = method_create_or_register_machine(manager, message, &m, error);
276 if (r < 0)
277 return r;
278
279 r = sd_bus_message_enter_container(message, 'a', "(sv)");
280 if (r < 0)
281 goto fail;
282
ebcf1f97
LP
283 r = machine_start(m, message, error);
284 if (r < 0)
1ee306e1
LP
285 goto fail;
286
c3350683 287 m->create_message = sd_bus_message_ref(message);
c3350683 288 return 1;
1ee306e1
LP
289
290fail:
a3e7f417 291 machine_add_to_gc_queue(m);
89f7c846
LP
292 return r;
293}
1ee306e1 294
89f7c846
LP
295static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
296 Manager *manager = userdata;
297 _cleanup_free_ char *p = NULL;
298 Machine *m = NULL;
299 int r;
300
301 r = method_create_or_register_machine(manager, message, &m, error);
302 if (r < 0)
303 return r;
304
305 r = cg_pid_get_unit(m->leader, &m->unit);
306 if (r < 0) {
307 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
308 goto fail;
309 }
310
311 r = machine_start(m, NULL, error);
312 if (r < 0)
313 goto fail;
314
315 p = machine_bus_path(m);
316 if (!p) {
317 r = -ENOMEM;
318 goto fail;
319 }
320
321 return sd_bus_reply_method_return(message, "o", p);
322
323fail:
324 machine_add_to_gc_queue(m);
1ee306e1
LP
325 return r;
326}
327
ebcf1f97 328static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 329 Manager *m = userdata;
c3350683
LP
330 Machine *machine;
331 const char *name;
1ee306e1
LP
332 int r;
333
c3350683 334 assert(bus);
1ee306e1
LP
335 assert(message);
336 assert(m);
337
c3350683
LP
338 r = sd_bus_message_read(message, "s", &name);
339 if (r < 0)
ebcf1f97 340 return sd_bus_error_set_errno(error, r);
1ee306e1 341
c3350683
LP
342 machine = hashmap_get(m->machines, name);
343 if (!machine)
ebcf1f97 344 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 345
c3350683
LP
346 r = machine_stop(machine);
347 if (r < 0)
ebcf1f97 348 return sd_bus_error_set_errno(error, r);
1ee306e1 349
df2d202e 350 return sd_bus_reply_method_return(message, NULL);
c3350683 351}
1ee306e1 352
ebcf1f97 353static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
354 Manager *m = userdata;
355 Machine *machine;
356 const char *name;
357 const char *swho;
358 int32_t signo;
359 KillWho who;
360 int r;
1ee306e1 361
c3350683
LP
362 assert(bus);
363 assert(message);
364 assert(m);
1ee306e1 365
c3350683
LP
366 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
367 if (r < 0)
ebcf1f97 368 return sd_bus_error_set_errno(error, r);
1ee306e1 369
c3350683
LP
370 if (isempty(swho))
371 who = KILL_ALL;
372 else {
373 who = kill_who_from_string(swho);
374 if (who < 0)
ebcf1f97 375 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
c3350683 376 }
1ee306e1 377
c3350683 378 if (signo <= 0 || signo >= _NSIG)
ebcf1f97 379 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
1ee306e1 380
c3350683
LP
381 machine = hashmap_get(m->machines, name);
382 if (!machine)
ebcf1f97 383 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 384
c3350683
LP
385 r = machine_kill(machine, who, signo);
386 if (r < 0)
ebcf1f97 387 return sd_bus_error_set_errno(error, r);
1ee306e1 388
df2d202e 389 return sd_bus_reply_method_return(message, NULL);
c3350683 390}
1ee306e1 391
c3350683
LP
392const sd_bus_vtable manager_vtable[] = {
393 SD_BUS_VTABLE_START(0),
adacb957
LP
394 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
395 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
396 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 397 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
89f7c846 398 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
adacb957
LP
399 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
400 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
c3350683
LP
401 SD_BUS_SIGNAL("MachineNew", "so", 0),
402 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
403 SD_BUS_VTABLE_END
404};
1ee306e1 405
ebcf1f97 406int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 407 const char *path, *result, *unit;
1ee306e1 408 Manager *m = userdata;
c3350683
LP
409 Machine *machine;
410 uint32_t id;
411 int r;
1ee306e1 412
c3350683 413 assert(bus);
1ee306e1 414 assert(message);
c3350683 415 assert(m);
1ee306e1 416
c3350683
LP
417 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
418 if (r < 0) {
ebcf1f97
LP
419 bus_log_parse_error(r);
420 return r;
c3350683 421 }
6797c324 422
c3350683
LP
423 machine = hashmap_get(m->machine_units, unit);
424 if (!machine)
425 return 0;
6797c324 426
c3350683
LP
427 if (streq_ptr(path, machine->scope_job)) {
428 free(machine->scope_job);
429 machine->scope_job = NULL;
6797c324 430
c3350683
LP
431 if (machine->started) {
432 if (streq(result, "done"))
433 machine_send_create_reply(machine, NULL);
434 else {
ebcf1f97 435 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 436
ebcf1f97 437 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 438
ebcf1f97 439 machine_send_create_reply(machine, &e);
c3350683
LP
440 }
441 } else
442 machine_save(machine);
1ee306e1
LP
443 }
444
c3350683
LP
445 machine_add_to_gc_queue(machine);
446 return 0;
1ee306e1
LP
447}
448
ebcf1f97 449int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
450 _cleanup_free_ char *unit = NULL;
451 Manager *m = userdata;
452 Machine *machine;
453 const char *path;
ebcf1f97 454 int r;
554604b3 455
c3350683
LP
456 assert(bus);
457 assert(message);
458 assert(m);
554604b3 459
c3350683
LP
460 path = sd_bus_message_get_path(message);
461 if (!path)
554604b3 462 return 0;
554604b3 463
ebcf1f97
LP
464 r = unit_name_from_dbus_path(path, &unit);
465 if (r < 0)
466 return r;
554604b3 467
c3350683
LP
468 machine = hashmap_get(m->machine_units, unit);
469 if (machine)
470 machine_add_to_gc_queue(machine);
554604b3 471
c3350683
LP
472 return 0;
473}
554604b3 474
ebcf1f97 475int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
476 const char *path, *unit;
477 Manager *m = userdata;
478 Machine *machine;
479 int r;
554604b3 480
c3350683
LP
481 assert(bus);
482 assert(message);
483 assert(m);
554604b3 484
c3350683
LP
485 r = sd_bus_message_read(message, "so", &unit, &path);
486 if (r < 0) {
ebcf1f97
LP
487 bus_log_parse_error(r);
488 return r;
554604b3
LP
489 }
490
c3350683
LP
491 machine = hashmap_get(m->machine_units, unit);
492 if (machine)
493 machine_add_to_gc_queue(machine);
554604b3 494
c3350683
LP
495 return 0;
496}
554604b3 497
ebcf1f97 498int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 499 Manager *m = userdata;
a658cafa
LP
500 Machine *machine;
501 Iterator i;
c3350683 502 int b, r;
554604b3 503
c3350683 504 assert(bus);
554604b3 505
c3350683
LP
506 r = sd_bus_message_read(message, "b", &b);
507 if (r < 0) {
ebcf1f97
LP
508 bus_log_parse_error(r);
509 return r;
554604b3 510 }
a658cafa
LP
511 if (b)
512 return 0;
554604b3 513
a658cafa
LP
514 /* systemd finished reloading, let's recheck all our machines */
515 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 516
a658cafa
LP
517 HASHMAP_FOREACH(machine, m->machines, i)
518 machine_add_to_gc_queue(machine);
554604b3
LP
519
520 return 0;
521}
522
1ee306e1
LP
523int manager_start_scope(
524 Manager *manager,
525 const char *scope,
526 pid_t pid,
527 const char *slice,
528 const char *description,
c3350683
LP
529 sd_bus_message *more_properties,
530 sd_bus_error *error,
1ee306e1
LP
531 char **job) {
532
c3350683 533 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 534 int r;
1ee306e1
LP
535
536 assert(manager);
537 assert(scope);
538 assert(pid > 1);
539
c3350683
LP
540 r = sd_bus_message_new_method_call(
541 manager->bus,
151b9b96 542 &m,
1ee306e1
LP
543 "org.freedesktop.systemd1",
544 "/org/freedesktop/systemd1",
545 "org.freedesktop.systemd1.Manager",
151b9b96 546 "StartTransientUnit");
c3350683
LP
547 if (r < 0)
548 return r;
1ee306e1 549
a658cafa 550 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
551 if (r < 0)
552 return r;
1ee306e1 553
c3350683
LP
554 r = sd_bus_message_open_container(m, 'a', "(sv)");
555 if (r < 0)
556 return r;
1ee306e1
LP
557
558 if (!isempty(slice)) {
c3350683
LP
559 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
560 if (r < 0)
561 return r;
1ee306e1
LP
562 }
563
564 if (!isempty(description)) {
c3350683
LP
565 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
566 if (r < 0)
567 return r;
1ee306e1
LP
568 }
569
c3350683
LP
570 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
571 if (r < 0)
572 return r;
554604b3
LP
573
574 if (more_properties) {
c3350683 575 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
576 if (r < 0)
577 return r;
578 }
579
c3350683
LP
580 r = sd_bus_message_close_container(m);
581 if (r < 0)
582 return r;
1ee306e1 583
86b8d289
LP
584 r = sd_bus_message_append(m, "a(sa(sv))", 0);
585 if (r < 0)
586 return r;
587
c49b30a2 588 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
589 if (r < 0)
590 return r;
1ee306e1
LP
591
592 if (job) {
593 const char *j;
594 char *copy;
595
c3350683
LP
596 r = sd_bus_message_read(reply, "o", &j);
597 if (r < 0)
598 return r;
1ee306e1
LP
599
600 copy = strdup(j);
601 if (!copy)
602 return -ENOMEM;
603
604 *job = copy;
605 }
606
c3350683 607 return 1;
1ee306e1
LP
608}
609
c3350683
LP
610int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
611 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
612 int r;
613
614 assert(manager);
615 assert(unit);
616
c3350683 617 r = sd_bus_call_method(
1ee306e1
LP
618 manager->bus,
619 "org.freedesktop.systemd1",
620 "/org/freedesktop/systemd1",
621 "org.freedesktop.systemd1.Manager",
622 "StopUnit",
1ee306e1 623 error,
c3350683
LP
624 &reply,
625 "ss", unit, "fail");
1ee306e1 626 if (r < 0) {
c3350683
LP
627 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
628 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
629
630 if (job)
631 *job = NULL;
632
c3350683 633 sd_bus_error_free(error);
6797c324
LP
634 return 0;
635 }
636
1ee306e1
LP
637 return r;
638 }
639
640 if (job) {
641 const char *j;
642 char *copy;
643
c3350683
LP
644 r = sd_bus_message_read(reply, "o", &j);
645 if (r < 0)
646 return r;
1ee306e1
LP
647
648 copy = strdup(j);
649 if (!copy)
650 return -ENOMEM;
651
652 *job = copy;
653 }
654
6797c324 655 return 1;
1ee306e1
LP
656}
657
de58a50e 658int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
659 assert(manager);
660 assert(unit);
661
a658cafa 662 return sd_bus_call_method(
1ee306e1
LP
663 manager->bus,
664 "org.freedesktop.systemd1",
665 "/org/freedesktop/systemd1",
666 "org.freedesktop.systemd1.Manager",
667 "KillUnit",
1ee306e1 668 error,
a658cafa 669 NULL,
de58a50e 670 "ssi", unit, "all", signo);
1ee306e1
LP
671}
672
673int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
674 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
675 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 676 _cleanup_free_ char *path = NULL;
1ee306e1 677 const char *state;
1ee306e1
LP
678 int r;
679
680 assert(manager);
681 assert(unit);
682
1ee306e1
LP
683 path = unit_dbus_path_from_name(unit);
684 if (!path)
685 return -ENOMEM;
686
c3350683 687 r = sd_bus_get_property(
1ee306e1
LP
688 manager->bus,
689 "org.freedesktop.systemd1",
690 path,
c3350683
LP
691 "org.freedesktop.systemd1.Unit",
692 "ActiveState",
1ee306e1 693 &error,
c3350683
LP
694 &reply,
695 "s");
1ee306e1 696 if (r < 0) {
c3350683
LP
697 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
698 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 699 return true;
6797c324 700
c3350683
LP
701 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
702 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 703 return false;
6797c324 704
1ee306e1
LP
705 return r;
706 }
707
c3350683
LP
708 r = sd_bus_message_read(reply, "s", &state);
709 if (r < 0)
1ee306e1 710 return -EINVAL;
1ee306e1
LP
711
712 return !streq(state, "inactive") && !streq(state, "failed");
713}
bd16acf3 714
c3350683
LP
715int manager_job_is_active(Manager *manager, const char *path) {
716 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
717 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
718 int r;
bd16acf3 719
c3350683
LP
720 assert(manager);
721 assert(path);
bd16acf3 722
c3350683
LP
723 r = sd_bus_get_property(
724 manager->bus,
725 "org.freedesktop.systemd1",
726 path,
727 "org.freedesktop.systemd1.Job",
728 "State",
729 &error,
730 &reply,
731 "s");
732 if (r < 0) {
733 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
734 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
735 return true;
bd16acf3 736
c3350683
LP
737 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
738 return false;
bd16acf3 739
bd16acf3 740 return r;
c3350683 741 }
bd16acf3 742
c3350683
LP
743 /* We don't actually care about the state really. The fact
744 * that we could read the job state is enough for us */
bd16acf3 745
c3350683 746 return true;
bd16acf3 747}
ab49725f
KS
748
749int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
750 _cleanup_free_ char *unit = NULL;
751 Machine *mm;
752 int r;
753
754 assert(m);
755 assert(pid >= 1);
756 assert(machine);
757
758 r = cg_pid_get_unit(pid, &unit);
759 if (r < 0)
760 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
761 else
762 mm = hashmap_get(m->machine_units, unit);
763
764 if (!mm)
765 return 0;
766
767 *machine = mm;
768 return 1;
769}
770
771int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
772 Machine *machine;
773
774 assert(m);
775 assert(name);
776
777 machine = hashmap_get(m->machines, name);
778 if (!machine) {
779 machine = machine_new(m, name);
780 if (!machine)
781 return -ENOMEM;
782 }
783
784 if (_machine)
785 *_machine = machine;
786
787 return 0;
788}