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