]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined-dbus.c
machined: always look for leader PID first
[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
26 #include "sd-id128.h"
27 #include "strv.h"
28 #include "path-util.h"
29 #include "unit-name.h"
30 #include "bus-util.h"
31 #include "bus-common-errors.h"
32 #include "cgroup-util.h"
33 #include "btrfs-util.h"
34 #include "formats-util.h"
35 #include "process-util.h"
36 #include "machine-image.h"
37 #include "machine-pool.h"
38 #include "image-dbus.h"
39 #include "machined.h"
40 #include "machine-dbus.h"
41
42 static int property_get_pool_path(
43 sd_bus *bus,
44 const char *path,
45 const char *interface,
46 const char *property,
47 sd_bus_message *reply,
48 void *userdata,
49 sd_bus_error *error) {
50
51 assert(bus);
52 assert(reply);
53
54 return sd_bus_message_append(reply, "s", "/var/lib/machines");
55 }
56
57 static int property_get_pool_usage(
58 sd_bus *bus,
59 const char *path,
60 const char *interface,
61 const char *property,
62 sd_bus_message *reply,
63 void *userdata,
64 sd_bus_error *error) {
65
66 _cleanup_close_ int fd = -1;
67 uint64_t usage = (uint64_t) -1;
68 struct stat st;
69
70 assert(bus);
71 assert(reply);
72
73 /* We try to read the quota info from /var/lib/machines, as
74 * well as the usage of the loopback file
75 * /var/lib/machines.raw, and pick the larger value. */
76
77 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
78 if (fd >= 0) {
79 BtrfsQuotaInfo q;
80
81 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
82 usage = q.referenced;
83 }
84
85 if (stat("/var/lib/machines.raw", &st) >= 0) {
86 if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
87 usage = st.st_blocks * 512ULL;
88 }
89
90 return sd_bus_message_append(reply, "t", usage);
91 }
92
93 static int property_get_pool_limit(
94 sd_bus *bus,
95 const char *path,
96 const char *interface,
97 const char *property,
98 sd_bus_message *reply,
99 void *userdata,
100 sd_bus_error *error) {
101
102 _cleanup_close_ int fd = -1;
103 uint64_t size = (uint64_t) -1;
104 struct stat st;
105
106 assert(bus);
107 assert(reply);
108
109 /* We try to read the quota limit from /var/lib/machines, as
110 * well as the size of the loopback file
111 * /var/lib/machines.raw, and pick the smaller value. */
112
113 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
114 if (fd >= 0) {
115 BtrfsQuotaInfo q;
116
117 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
118 size = q.referenced_max;
119 }
120
121 if (stat("/var/lib/machines.raw", &st) >= 0) {
122 if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
123 size = st.st_size;
124 }
125
126 return sd_bus_message_append(reply, "t", size);
127 }
128
129 static int method_get_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
130 _cleanup_free_ char *p = NULL;
131 Manager *m = userdata;
132 Machine *machine;
133 const char *name;
134 int r;
135
136 assert(message);
137 assert(m);
138
139 r = sd_bus_message_read(message, "s", &name);
140 if (r < 0)
141 return r;
142
143 machine = hashmap_get(m->machines, name);
144 if (!machine)
145 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
146
147 p = machine_bus_path(machine);
148 if (!p)
149 return -ENOMEM;
150
151 return sd_bus_reply_method_return(message, "o", p);
152 }
153
154 static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
155 _cleanup_free_ char *p = NULL;
156 Manager *m = userdata;
157 const char *name;
158 int r;
159
160 assert(message);
161 assert(m);
162
163 r = sd_bus_message_read(message, "s", &name);
164 if (r < 0)
165 return r;
166
167 r = image_find(name, NULL);
168 if (r == 0)
169 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
170 if (r < 0)
171 return r;
172
173 p = image_bus_path(name);
174 if (!p)
175 return -ENOMEM;
176
177 return sd_bus_reply_method_return(message, "o", p);
178 }
179
180 static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
181 _cleanup_free_ char *p = NULL;
182 Manager *m = userdata;
183 Machine *machine = NULL;
184 pid_t pid;
185 int r;
186
187 assert(message);
188 assert(m);
189
190 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
191
192 r = sd_bus_message_read(message, "u", &pid);
193 if (r < 0)
194 return r;
195
196 if (pid == 0) {
197 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
198
199 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
200 if (r < 0)
201 return r;
202
203 r = sd_bus_creds_get_pid(creds, &pid);
204 if (r < 0)
205 return r;
206 }
207
208 r = manager_get_machine_by_pid(m, pid, &machine);
209 if (r < 0)
210 return r;
211 if (!machine)
212 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
213
214 p = machine_bus_path(machine);
215 if (!p)
216 return -ENOMEM;
217
218 return sd_bus_reply_method_return(message, "o", p);
219 }
220
221 static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_error *error) {
222 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
223 Manager *m = userdata;
224 Machine *machine;
225 Iterator i;
226 int r;
227
228 assert(message);
229 assert(m);
230
231 r = sd_bus_message_new_method_return(message, &reply);
232 if (r < 0)
233 return sd_bus_error_set_errno(error, r);
234
235 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
236 if (r < 0)
237 return sd_bus_error_set_errno(error, r);
238
239 HASHMAP_FOREACH(machine, m->machines, i) {
240 _cleanup_free_ char *p = NULL;
241
242 p = machine_bus_path(machine);
243 if (!p)
244 return -ENOMEM;
245
246 r = sd_bus_message_append(reply, "(ssso)",
247 machine->name,
248 strempty(machine_class_to_string(machine->class)),
249 machine->service,
250 p);
251 if (r < 0)
252 return sd_bus_error_set_errno(error, r);
253 }
254
255 r = sd_bus_message_close_container(reply);
256 if (r < 0)
257 return sd_bus_error_set_errno(error, r);
258
259 return sd_bus_send(NULL, reply, NULL);
260 }
261
262 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
263 const char *name, *service, *class, *root_directory;
264 const int32_t *netif = NULL;
265 MachineClass c;
266 uint32_t leader;
267 sd_id128_t id;
268 const void *v;
269 Machine *m;
270 size_t n, n_netif = 0;
271 int r;
272
273 assert(manager);
274 assert(message);
275 assert(_m);
276
277 r = sd_bus_message_read(message, "s", &name);
278 if (r < 0)
279 return r;
280 if (!machine_name_is_valid(name))
281 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
282
283 r = sd_bus_message_read_array(message, 'y', &v, &n);
284 if (r < 0)
285 return r;
286 if (n == 0)
287 id = SD_ID128_NULL;
288 else if (n == 16)
289 memcpy(&id, v, n);
290 else
291 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
292
293 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
294 if (r < 0)
295 return r;
296
297 if (read_network) {
298 size_t i;
299
300 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
301 if (r < 0)
302 return r;
303
304 n_netif /= sizeof(int32_t);
305
306 for (i = 0; i < n_netif; i++) {
307 if (netif[i] <= 0)
308 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
309 }
310 }
311
312 if (isempty(class))
313 c = _MACHINE_CLASS_INVALID;
314 else {
315 c = machine_class_from_string(class);
316 if (c < 0)
317 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
318 }
319
320 if (leader == 1)
321 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
322
323 if (!isempty(root_directory) && !path_is_absolute(root_directory))
324 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
325
326 if (leader == 0) {
327 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
328
329 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
330 if (r < 0)
331 return r;
332
333 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
334
335 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
336 if (r < 0)
337 return r;
338 }
339
340 if (hashmap_get(manager->machines, name))
341 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
342
343 r = manager_add_machine(manager, name, &m);
344 if (r < 0)
345 return r;
346
347 m->leader = leader;
348 m->class = c;
349 m->id = id;
350
351 if (!isempty(service)) {
352 m->service = strdup(service);
353 if (!m->service) {
354 r = -ENOMEM;
355 goto fail;
356 }
357 }
358
359 if (!isempty(root_directory)) {
360 m->root_directory = strdup(root_directory);
361 if (!m->root_directory) {
362 r = -ENOMEM;
363 goto fail;
364 }
365 }
366
367 if (n_netif > 0) {
368 assert_cc(sizeof(int32_t) == sizeof(int));
369 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
370 if (!m->netif) {
371 r = -ENOMEM;
372 goto fail;
373 }
374
375 m->n_netif = n_netif;
376 }
377
378 *_m = m;
379
380 return 1;
381
382 fail:
383 machine_add_to_gc_queue(m);
384 return r;
385 }
386
387 static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
388 Manager *manager = userdata;
389 Machine *m = NULL;
390 int r;
391
392 assert(message);
393 assert(manager);
394
395 r = method_create_or_register_machine(manager, message, read_network, &m, error);
396 if (r < 0)
397 return r;
398
399 r = sd_bus_message_enter_container(message, 'a', "(sv)");
400 if (r < 0)
401 goto fail;
402
403 r = machine_start(m, message, error);
404 if (r < 0)
405 goto fail;
406
407 m->create_message = sd_bus_message_ref(message);
408 return 1;
409
410 fail:
411 machine_add_to_gc_queue(m);
412 return r;
413 }
414
415 static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
416 return method_create_machine_internal(message, true, userdata, error);
417 }
418
419 static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
420 return method_create_machine_internal(message, false, userdata, error);
421 }
422
423 static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
424 Manager *manager = userdata;
425 _cleanup_free_ char *p = NULL;
426 Machine *m = NULL;
427 int r;
428
429 assert(message);
430 assert(manager);
431
432 r = method_create_or_register_machine(manager, message, read_network, &m, error);
433 if (r < 0)
434 return r;
435
436 r = cg_pid_get_unit(m->leader, &m->unit);
437 if (r < 0) {
438 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
439 goto fail;
440 }
441
442 r = machine_start(m, NULL, error);
443 if (r < 0)
444 goto fail;
445
446 p = machine_bus_path(m);
447 if (!p) {
448 r = -ENOMEM;
449 goto fail;
450 }
451
452 return sd_bus_reply_method_return(message, "o", p);
453
454 fail:
455 machine_add_to_gc_queue(m);
456 return r;
457 }
458
459 static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
460 return method_register_machine_internal(message, true, userdata, error);
461 }
462
463 static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
464 return method_register_machine_internal(message, false, userdata, error);
465 }
466
467 static int method_terminate_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
468 Manager *m = userdata;
469 Machine *machine;
470 const char *name;
471 int r;
472
473 assert(message);
474 assert(m);
475
476 r = sd_bus_message_read(message, "s", &name);
477 if (r < 0)
478 return sd_bus_error_set_errno(error, r);
479
480 machine = hashmap_get(m->machines, name);
481 if (!machine)
482 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
483
484 return bus_machine_method_terminate(message, machine, error);
485 }
486
487 static int method_kill_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
488 Manager *m = userdata;
489 Machine *machine;
490 const char *name;
491 int r;
492
493 assert(message);
494 assert(m);
495
496 r = sd_bus_message_read(message, "s", &name);
497 if (r < 0)
498 return sd_bus_error_set_errno(error, r);
499
500 machine = hashmap_get(m->machines, name);
501 if (!machine)
502 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
503
504 return bus_machine_method_kill(message, machine, error);
505 }
506
507 static int method_get_machine_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
508 Manager *m = userdata;
509 Machine *machine;
510 const char *name;
511 int r;
512
513 assert(message);
514 assert(m);
515
516 r = sd_bus_message_read(message, "s", &name);
517 if (r < 0)
518 return sd_bus_error_set_errno(error, r);
519
520 machine = hashmap_get(m->machines, name);
521 if (!machine)
522 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
523
524 return bus_machine_method_get_addresses(message, machine, error);
525 }
526
527 static int method_get_machine_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
528 Manager *m = userdata;
529 Machine *machine;
530 const char *name;
531 int r;
532
533 assert(message);
534 assert(m);
535
536 r = sd_bus_message_read(message, "s", &name);
537 if (r < 0)
538 return sd_bus_error_set_errno(error, r);
539
540 machine = hashmap_get(m->machines, name);
541 if (!machine)
542 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
543
544 return bus_machine_method_get_os_release(message, machine, error);
545 }
546
547 static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
548 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
549 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
550 Manager *m = userdata;
551 Image *image;
552 Iterator i;
553 int r;
554
555 assert(message);
556 assert(m);
557
558 images = hashmap_new(&string_hash_ops);
559 if (!images)
560 return -ENOMEM;
561
562 r = image_discover(images);
563 if (r < 0)
564 return r;
565
566 r = sd_bus_message_new_method_return(message, &reply);
567 if (r < 0)
568 return r;
569
570 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
571 if (r < 0)
572 return r;
573
574 HASHMAP_FOREACH(image, images, i) {
575 _cleanup_free_ char *p = NULL;
576
577 p = image_bus_path(image->name);
578 if (!p)
579 return -ENOMEM;
580
581 r = sd_bus_message_append(reply, "(ssbttto)",
582 image->name,
583 image_type_to_string(image->type),
584 image->read_only,
585 image->crtime,
586 image->mtime,
587 image->usage,
588 p);
589 if (r < 0)
590 return r;
591 }
592
593 r = sd_bus_message_close_container(reply);
594 if (r < 0)
595 return r;
596
597 return sd_bus_send(NULL, reply, NULL);
598 }
599
600 static int method_open_machine_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
601 Manager *m = userdata;
602 Machine *machine;
603 const char *name;
604 int r;
605
606 assert(message);
607 assert(m);
608
609 r = sd_bus_message_read(message, "s", &name);
610 if (r < 0)
611 return sd_bus_error_set_errno(error, r);
612
613 machine = hashmap_get(m->machines, name);
614 if (!machine)
615 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
616
617 return bus_machine_method_open_pty(message, machine, error);
618 }
619
620 static int method_open_machine_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
621 Manager *m = userdata;
622 Machine *machine;
623 const char *name;
624 int r;
625
626 assert(message);
627 assert(m);
628
629 r = sd_bus_message_read(message, "s", &name);
630 if (r < 0)
631 return r;
632
633 machine = hashmap_get(m->machines, name);
634 if (!machine)
635 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
636
637 return bus_machine_method_open_login(message, machine, error);
638 }
639
640 static int method_open_machine_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
641 Manager *m = userdata;
642 Machine *machine;
643 const char *name;
644
645 int r;
646
647 assert(message);
648 assert(m);
649
650 r = sd_bus_message_read(message, "s", &name);
651 if (r < 0)
652 return r;
653
654 machine = hashmap_get(m->machines, name);
655 if (!machine)
656 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
657
658 return bus_machine_method_open_shell(message, machine, error);
659 }
660
661 static int method_bind_mount_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
662 Manager *m = userdata;
663 Machine *machine;
664 const char *name;
665 int r;
666
667 assert(message);
668 assert(m);
669
670 r = sd_bus_message_read(message, "s", &name);
671 if (r < 0)
672 return r;
673
674 machine = hashmap_get(m->machines, name);
675 if (!machine)
676 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
677
678 return bus_machine_method_bind_mount(message, machine, error);
679 }
680
681 static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
682 Manager *m = userdata;
683 Machine *machine;
684 const char *name;
685 int r;
686
687 assert(message);
688 assert(m);
689
690 r = sd_bus_message_read(message, "s", &name);
691 if (r < 0)
692 return r;
693
694 machine = hashmap_get(m->machines, name);
695 if (!machine)
696 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
697
698 return bus_machine_method_copy(message, machine, error);
699 }
700
701 static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
702 _cleanup_(image_unrefp) Image* i = NULL;
703 const char *name;
704 int r;
705
706 assert(message);
707
708 r = sd_bus_message_read(message, "s", &name);
709 if (r < 0)
710 return r;
711
712 if (!image_name_is_valid(name))
713 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
714
715 r = image_find(name, &i);
716 if (r < 0)
717 return r;
718 if (r == 0)
719 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
720
721 i->userdata = userdata;
722 return bus_image_method_remove(message, i, error);
723 }
724
725 static int method_rename_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
726 _cleanup_(image_unrefp) Image* i = NULL;
727 const char *old_name;
728 int r;
729
730 assert(message);
731
732 r = sd_bus_message_read(message, "s", &old_name);
733 if (r < 0)
734 return r;
735
736 if (!image_name_is_valid(old_name))
737 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
738
739 r = image_find(old_name, &i);
740 if (r < 0)
741 return r;
742 if (r == 0)
743 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
744
745 i->userdata = userdata;
746 return bus_image_method_rename(message, i, error);
747 }
748
749 static int method_clone_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
750 _cleanup_(image_unrefp) Image *i = NULL;
751 const char *old_name;
752 int r;
753
754 assert(message);
755
756 r = sd_bus_message_read(message, "s", &old_name);
757 if (r < 0)
758 return r;
759
760 if (!image_name_is_valid(old_name))
761 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
762
763 r = image_find(old_name, &i);
764 if (r < 0)
765 return r;
766 if (r == 0)
767 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
768
769 i->userdata = userdata;
770 return bus_image_method_clone(message, i, error);
771 }
772
773 static int method_mark_image_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
774 _cleanup_(image_unrefp) Image *i = NULL;
775 const char *name;
776 int r;
777
778 assert(message);
779
780 r = sd_bus_message_read(message, "s", &name);
781 if (r < 0)
782 return r;
783
784 if (!image_name_is_valid(name))
785 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
786
787 r = image_find(name, &i);
788 if (r < 0)
789 return r;
790 if (r == 0)
791 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
792
793 i->userdata = userdata;
794 return bus_image_method_mark_read_only(message, i, error);
795 }
796
797 static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
798 Manager *m = userdata;
799 uint64_t limit;
800 int r;
801
802 assert(message);
803
804 r = sd_bus_message_read(message, "t", &limit);
805 if (r < 0)
806 return r;
807
808 r = bus_verify_polkit_async(
809 message,
810 CAP_SYS_ADMIN,
811 "org.freedesktop.machine1.manage-machines",
812 false,
813 UID_INVALID,
814 &m->polkit_registry,
815 error);
816 if (r < 0)
817 return r;
818 if (r == 0)
819 return 1; /* Will call us back */
820
821 /* Set up the machine directory if necessary */
822 r = setup_machine_directory(limit, error);
823 if (r < 0)
824 return r;
825
826 r = btrfs_resize_loopback("/var/lib/machines", limit, false);
827 if (r == -ENOTTY)
828 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
829 if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
830 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
831
832 r = btrfs_quota_limit("/var/lib/machines", limit);
833 if (r == -ENOTTY)
834 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
835 if (r < 0)
836 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
837
838 return sd_bus_reply_method_return(message, NULL);
839 }
840
841 static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
842 _cleanup_(image_unrefp) Image *i = NULL;
843 const char *name;
844 int r;
845
846 assert(message);
847
848 r = sd_bus_message_read(message, "s", &name);
849 if (r < 0)
850 return r;
851
852 if (!image_name_is_valid(name))
853 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
854
855 r = image_find(name, &i);
856 if (r < 0)
857 return r;
858 if (r == 0)
859 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
860
861 i->userdata = userdata;
862 return bus_image_method_set_limit(message, i, error);
863 }
864
865 static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
866 _cleanup_fclose_ FILE *f = NULL;
867 Manager *m = userdata;
868 const char *name, *p;
869 Machine *machine;
870 uint32_t uid;
871 int r;
872
873 r = sd_bus_message_read(message, "su", &name, &uid);
874 if (r < 0)
875 return r;
876
877 if (UID_IS_INVALID(uid))
878 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
879
880 machine = hashmap_get(m->machines, name);
881 if (!machine)
882 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
883
884 p = procfs_file_alloca(machine->leader, "uid_map");
885 f = fopen(p, "re");
886 if (!f)
887 return -errno;
888
889 for (;;) {
890 uid_t uid_base, uid_shift, uid_range, converted;
891 int k;
892
893 errno = 0;
894 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
895 if (k < 0 && feof(f))
896 break;
897 if (k != 3) {
898 if (ferror(f) && errno != 0)
899 return -errno;
900
901 return -EIO;
902 }
903
904 if (uid < uid_base || uid >= uid_base + uid_range)
905 continue;
906
907 converted = uid - uid_base + uid_shift;
908 if (UID_IS_INVALID(converted))
909 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
910
911 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
912 }
913
914 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
915 }
916
917 static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
918 Manager *m = userdata;
919 Machine *machine;
920 uid_t uid;
921 Iterator i;
922 int r;
923
924 r = sd_bus_message_read(message, "u", &uid);
925 if (r < 0)
926 return r;
927 if (UID_IS_INVALID(uid))
928 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
929 if (uid < 0x10000)
930 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
931
932 HASHMAP_FOREACH(machine, m->machines, i) {
933 _cleanup_fclose_ FILE *f = NULL;
934 char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
935
936 xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
937 f = fopen(p, "re");
938 if (!f) {
939 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
940 continue;
941 }
942
943 for (;;) {
944 _cleanup_free_ char *o = NULL;
945 uid_t uid_base, uid_shift, uid_range, converted;
946 int k;
947
948 errno = 0;
949 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
950 if (k < 0 && feof(f))
951 break;
952 if (k != 3) {
953 if (ferror(f) && errno != 0)
954 return -errno;
955
956 return -EIO;
957 }
958
959 if (uid < uid_shift || uid >= uid_shift + uid_range)
960 continue;
961
962 converted = (uid - uid_shift + uid_base);
963 if (UID_IS_INVALID(converted))
964 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
965
966 o = machine_bus_path(machine);
967 if (!o)
968 return -ENOMEM;
969
970 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
971 }
972 }
973
974 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
975 }
976
977 static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
978 _cleanup_fclose_ FILE *f = NULL;
979 Manager *m = groupdata;
980 const char *name, *p;
981 Machine *machine;
982 uint32_t gid;
983 int r;
984
985 r = sd_bus_message_read(message, "su", &name, &gid);
986 if (r < 0)
987 return r;
988
989 if (GID_IS_INVALID(gid))
990 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
991
992 machine = hashmap_get(m->machines, name);
993 if (!machine)
994 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
995
996 p = procfs_file_alloca(machine->leader, "gid_map");
997 f = fopen(p, "re");
998 if (!f)
999 return -errno;
1000
1001 for (;;) {
1002 gid_t gid_base, gid_shift, gid_range, converted;
1003 int k;
1004
1005 errno = 0;
1006 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1007 if (k < 0 && feof(f))
1008 break;
1009 if (k != 3) {
1010 if (ferror(f) && errno != 0)
1011 return -errno;
1012
1013 return -EIO;
1014 }
1015
1016 if (gid < gid_base || gid >= gid_base + gid_range)
1017 continue;
1018
1019 converted = gid - gid_base + gid_shift;
1020 if (GID_IS_INVALID(converted))
1021 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1022
1023 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
1024 }
1025
1026 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
1027 }
1028
1029 static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
1030 Manager *m = groupdata;
1031 Machine *machine;
1032 gid_t gid;
1033 Iterator i;
1034 int r;
1035
1036 r = sd_bus_message_read(message, "u", &gid);
1037 if (r < 0)
1038 return r;
1039 if (GID_IS_INVALID(gid))
1040 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1041 if (gid < 0x10000)
1042 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
1043
1044 HASHMAP_FOREACH(machine, m->machines, i) {
1045 _cleanup_fclose_ FILE *f = NULL;
1046 char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
1047
1048 xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
1049 f = fopen(p, "re");
1050 if (!f) {
1051 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
1052 continue;
1053 }
1054
1055 for (;;) {
1056 _cleanup_free_ char *o = NULL;
1057 gid_t gid_base, gid_shift, gid_range, converted;
1058 int k;
1059
1060 errno = 0;
1061 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1062 if (k < 0 && feof(f))
1063 break;
1064 if (k != 3) {
1065 if (ferror(f) && errno != 0)
1066 return -errno;
1067
1068 return -EIO;
1069 }
1070
1071 if (gid < gid_shift || gid >= gid_shift + gid_range)
1072 continue;
1073
1074 converted = (gid - gid_shift + gid_base);
1075 if (GID_IS_INVALID(converted))
1076 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1077
1078 o = machine_bus_path(machine);
1079 if (!o)
1080 return -ENOMEM;
1081
1082 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
1083 }
1084 }
1085
1086 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
1087 }
1088
1089 const sd_bus_vtable manager_vtable[] = {
1090 SD_BUS_VTABLE_START(0),
1091 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
1092 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
1093 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
1094 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1095 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
1096 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
1097 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
1098 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
1099 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
1100 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
1101 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
1102 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
1103 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1104 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1105 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
1106 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
1107 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
1108 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
1109 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell, SD_BUS_VTABLE_UNPRIVILEGED),
1110 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1111 SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1112 SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1113 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
1114 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
1115 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
1116 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
1117 SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
1118 SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
1119 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1120 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1121 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
1122 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
1123 SD_BUS_SIGNAL("MachineNew", "so", 0),
1124 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1125 SD_BUS_VTABLE_END
1126 };
1127
1128 int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1129 const char *path, *result, *unit;
1130 Manager *m = userdata;
1131 Machine *machine;
1132 uint32_t id;
1133 int r;
1134
1135 assert(message);
1136 assert(m);
1137
1138 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
1139 if (r < 0) {
1140 bus_log_parse_error(r);
1141 return 0;
1142 }
1143
1144 machine = hashmap_get(m->machine_units, unit);
1145 if (!machine)
1146 return 0;
1147
1148 if (streq_ptr(path, machine->scope_job)) {
1149 machine->scope_job = mfree(machine->scope_job);
1150
1151 if (machine->started) {
1152 if (streq(result, "done"))
1153 machine_send_create_reply(machine, NULL);
1154 else {
1155 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
1156
1157 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
1158
1159 machine_send_create_reply(machine, &e);
1160 }
1161 }
1162
1163 machine_save(machine);
1164 }
1165
1166 machine_add_to_gc_queue(machine);
1167 return 0;
1168 }
1169
1170 int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1171 _cleanup_free_ char *unit = NULL;
1172 const char *path;
1173 Manager *m = userdata;
1174 Machine *machine;
1175 int r;
1176
1177 assert(message);
1178 assert(m);
1179
1180 path = sd_bus_message_get_path(message);
1181 if (!path)
1182 return 0;
1183
1184 r = unit_name_from_dbus_path(path, &unit);
1185 if (r == -EINVAL) /* not for a unit */
1186 return 0;
1187 if (r < 0){
1188 log_oom();
1189 return 0;
1190 }
1191
1192 machine = hashmap_get(m->machine_units, unit);
1193 if (!machine)
1194 return 0;
1195
1196 machine_add_to_gc_queue(machine);
1197 return 0;
1198 }
1199
1200 int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1201 const char *path, *unit;
1202 Manager *m = userdata;
1203 Machine *machine;
1204 int r;
1205
1206 assert(message);
1207 assert(m);
1208
1209 r = sd_bus_message_read(message, "so", &unit, &path);
1210 if (r < 0) {
1211 bus_log_parse_error(r);
1212 return 0;
1213 }
1214
1215 machine = hashmap_get(m->machine_units, unit);
1216 if (!machine)
1217 return 0;
1218
1219 machine_add_to_gc_queue(machine);
1220 return 0;
1221 }
1222
1223 int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1224 Manager *m = userdata;
1225 Machine *machine;
1226 Iterator i;
1227 int b, r;
1228
1229 assert(message);
1230 assert(m);
1231
1232 r = sd_bus_message_read(message, "b", &b);
1233 if (r < 0) {
1234 bus_log_parse_error(r);
1235 return 0;
1236 }
1237 if (b)
1238 return 0;
1239
1240 /* systemd finished reloading, let's recheck all our machines */
1241 log_debug("System manager has been reloaded, rechecking machines...");
1242
1243 HASHMAP_FOREACH(machine, m->machines, i)
1244 machine_add_to_gc_queue(machine);
1245
1246 return 0;
1247 }
1248
1249 int manager_start_scope(
1250 Manager *manager,
1251 const char *scope,
1252 pid_t pid,
1253 const char *slice,
1254 const char *description,
1255 sd_bus_message *more_properties,
1256 sd_bus_error *error,
1257 char **job) {
1258
1259 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1260 int r;
1261
1262 assert(manager);
1263 assert(scope);
1264 assert(pid > 1);
1265
1266 r = sd_bus_message_new_method_call(
1267 manager->bus,
1268 &m,
1269 "org.freedesktop.systemd1",
1270 "/org/freedesktop/systemd1",
1271 "org.freedesktop.systemd1.Manager",
1272 "StartTransientUnit");
1273 if (r < 0)
1274 return r;
1275
1276 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
1277 if (r < 0)
1278 return r;
1279
1280 r = sd_bus_message_open_container(m, 'a', "(sv)");
1281 if (r < 0)
1282 return r;
1283
1284 if (!isempty(slice)) {
1285 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1286 if (r < 0)
1287 return r;
1288 }
1289
1290 if (!isempty(description)) {
1291 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1292 if (r < 0)
1293 return r;
1294 }
1295
1296 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1297 if (r < 0)
1298 return r;
1299
1300 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1301 if (r < 0)
1302 return r;
1303
1304 if (more_properties) {
1305 r = sd_bus_message_copy(m, more_properties, true);
1306 if (r < 0)
1307 return r;
1308 }
1309
1310 r = sd_bus_message_close_container(m);
1311 if (r < 0)
1312 return r;
1313
1314 r = sd_bus_message_append(m, "a(sa(sv))", 0);
1315 if (r < 0)
1316 return r;
1317
1318 r = sd_bus_call(manager->bus, m, 0, error, &reply);
1319 if (r < 0)
1320 return r;
1321
1322 if (job) {
1323 const char *j;
1324 char *copy;
1325
1326 r = sd_bus_message_read(reply, "o", &j);
1327 if (r < 0)
1328 return r;
1329
1330 copy = strdup(j);
1331 if (!copy)
1332 return -ENOMEM;
1333
1334 *job = copy;
1335 }
1336
1337 return 1;
1338 }
1339
1340 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
1341 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1342 int r;
1343
1344 assert(manager);
1345 assert(unit);
1346
1347 r = sd_bus_call_method(
1348 manager->bus,
1349 "org.freedesktop.systemd1",
1350 "/org/freedesktop/systemd1",
1351 "org.freedesktop.systemd1.Manager",
1352 "StopUnit",
1353 error,
1354 &reply,
1355 "ss", unit, "fail");
1356 if (r < 0) {
1357 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1358 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
1359
1360 if (job)
1361 *job = NULL;
1362
1363 sd_bus_error_free(error);
1364 return 0;
1365 }
1366
1367 return r;
1368 }
1369
1370 if (job) {
1371 const char *j;
1372 char *copy;
1373
1374 r = sd_bus_message_read(reply, "o", &j);
1375 if (r < 0)
1376 return r;
1377
1378 copy = strdup(j);
1379 if (!copy)
1380 return -ENOMEM;
1381
1382 *job = copy;
1383 }
1384
1385 return 1;
1386 }
1387
1388 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1389 assert(manager);
1390 assert(unit);
1391
1392 return sd_bus_call_method(
1393 manager->bus,
1394 "org.freedesktop.systemd1",
1395 "/org/freedesktop/systemd1",
1396 "org.freedesktop.systemd1.Manager",
1397 "KillUnit",
1398 error,
1399 NULL,
1400 "ssi", unit, "all", signo);
1401 }
1402
1403 int manager_unit_is_active(Manager *manager, const char *unit) {
1404 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1405 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1406 _cleanup_free_ char *path = NULL;
1407 const char *state;
1408 int r;
1409
1410 assert(manager);
1411 assert(unit);
1412
1413 path = unit_dbus_path_from_name(unit);
1414 if (!path)
1415 return -ENOMEM;
1416
1417 r = sd_bus_get_property(
1418 manager->bus,
1419 "org.freedesktop.systemd1",
1420 path,
1421 "org.freedesktop.systemd1.Unit",
1422 "ActiveState",
1423 &error,
1424 &reply,
1425 "s");
1426 if (r < 0) {
1427 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1428 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1429 return true;
1430
1431 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1432 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1433 return false;
1434
1435 return r;
1436 }
1437
1438 r = sd_bus_message_read(reply, "s", &state);
1439 if (r < 0)
1440 return -EINVAL;
1441
1442 return !STR_IN_SET(state, "inactive", "failed");
1443 }
1444
1445 int manager_job_is_active(Manager *manager, const char *path) {
1446 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1447 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1448 int r;
1449
1450 assert(manager);
1451 assert(path);
1452
1453 r = sd_bus_get_property(
1454 manager->bus,
1455 "org.freedesktop.systemd1",
1456 path,
1457 "org.freedesktop.systemd1.Job",
1458 "State",
1459 &error,
1460 &reply,
1461 "s");
1462 if (r < 0) {
1463 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1464 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1465 return true;
1466
1467 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1468 return false;
1469
1470 return r;
1471 }
1472
1473 /* We don't actually care about the state really. The fact
1474 * that we could read the job state is enough for us */
1475
1476 return true;
1477 }
1478
1479 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1480 Machine *mm;
1481 int r;
1482
1483 assert(m);
1484 assert(pid >= 1);
1485 assert(machine);
1486
1487 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1488 if (!mm) {
1489 _cleanup_free_ char *unit = NULL;
1490
1491 r = cg_pid_get_unit(pid, &unit);
1492 if (r >= 0)
1493 mm = hashmap_get(m->machine_units, unit);
1494 }
1495 if (!mm)
1496 return 0;
1497
1498 *machine = mm;
1499 return 1;
1500 }
1501
1502 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1503 Machine *machine;
1504
1505 assert(m);
1506 assert(name);
1507
1508 machine = hashmap_get(m->machines, name);
1509 if (!machine) {
1510 machine = machine_new(m, name);
1511 if (!machine)
1512 return -ENOMEM;
1513 }
1514
1515 if (_machine)
1516 *_machine = machine;
1517
1518 return 0;
1519 }