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