]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined-dbus.c
Merge pull request #375 from msekletar/test-install-crashers
[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_bind_mount_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
641 Manager *m = userdata;
642 Machine *machine;
643 const char *name;
644 int r;
645
646 assert(message);
647 assert(m);
648
649 r = sd_bus_message_read(message, "s", &name);
650 if (r < 0)
651 return r;
652
653 machine = hashmap_get(m->machines, name);
654 if (!machine)
655 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
656
657 return bus_machine_method_bind_mount(message, machine, error);
658 }
659
660 static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
661 Manager *m = userdata;
662 Machine *machine;
663 const char *name;
664 int r;
665
666 assert(message);
667 assert(m);
668
669 r = sd_bus_message_read(message, "s", &name);
670 if (r < 0)
671 return r;
672
673 machine = hashmap_get(m->machines, name);
674 if (!machine)
675 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
676
677 return bus_machine_method_copy(message, machine, error);
678 }
679
680 static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
681 _cleanup_(image_unrefp) Image* i = NULL;
682 const char *name;
683 int r;
684
685 assert(message);
686
687 r = sd_bus_message_read(message, "s", &name);
688 if (r < 0)
689 return r;
690
691 if (!image_name_is_valid(name))
692 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
693
694 r = image_find(name, &i);
695 if (r < 0)
696 return r;
697 if (r == 0)
698 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
699
700 i->userdata = userdata;
701 return bus_image_method_remove(message, i, error);
702 }
703
704 static int method_rename_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
705 _cleanup_(image_unrefp) Image* i = NULL;
706 const char *old_name;
707 int r;
708
709 assert(message);
710
711 r = sd_bus_message_read(message, "s", &old_name);
712 if (r < 0)
713 return r;
714
715 if (!image_name_is_valid(old_name))
716 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
717
718 r = image_find(old_name, &i);
719 if (r < 0)
720 return r;
721 if (r == 0)
722 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
723
724 i->userdata = userdata;
725 return bus_image_method_rename(message, i, error);
726 }
727
728 static int method_clone_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
729 _cleanup_(image_unrefp) Image *i = NULL;
730 const char *old_name;
731 int r;
732
733 assert(message);
734
735 r = sd_bus_message_read(message, "s", &old_name);
736 if (r < 0)
737 return r;
738
739 if (!image_name_is_valid(old_name))
740 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
741
742 r = image_find(old_name, &i);
743 if (r < 0)
744 return r;
745 if (r == 0)
746 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
747
748 i->userdata = userdata;
749 return bus_image_method_clone(message, i, error);
750 }
751
752 static int method_mark_image_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
753 _cleanup_(image_unrefp) Image *i = NULL;
754 const char *name;
755 int r;
756
757 assert(message);
758
759 r = sd_bus_message_read(message, "s", &name);
760 if (r < 0)
761 return r;
762
763 if (!image_name_is_valid(name))
764 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
765
766 r = image_find(name, &i);
767 if (r < 0)
768 return r;
769 if (r == 0)
770 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
771
772 i->userdata = userdata;
773 return bus_image_method_mark_read_only(message, i, error);
774 }
775
776 static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
777 Manager *m = userdata;
778 uint64_t limit;
779 int r;
780
781 assert(message);
782
783 r = sd_bus_message_read(message, "t", &limit);
784 if (r < 0)
785 return r;
786
787 r = bus_verify_polkit_async(
788 message,
789 CAP_SYS_ADMIN,
790 "org.freedesktop.machine1.manage-machines",
791 false,
792 UID_INVALID,
793 &m->polkit_registry,
794 error);
795 if (r < 0)
796 return r;
797 if (r == 0)
798 return 1; /* Will call us back */
799
800 /* Set up the machine directory if necessary */
801 r = setup_machine_directory(limit, error);
802 if (r < 0)
803 return r;
804
805 r = btrfs_resize_loopback("/var/lib/machines", limit, false);
806 if (r == -ENOTTY)
807 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
808 if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
809 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
810
811 r = btrfs_quota_limit("/var/lib/machines", limit);
812 if (r == -ENOTTY)
813 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
814 if (r < 0)
815 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
816
817 return sd_bus_reply_method_return(message, NULL);
818 }
819
820 static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
821 _cleanup_(image_unrefp) Image *i = NULL;
822 const char *name;
823 int r;
824
825 assert(message);
826
827 r = sd_bus_message_read(message, "s", &name);
828 if (r < 0)
829 return r;
830
831 if (!image_name_is_valid(name))
832 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
833
834 r = image_find(name, &i);
835 if (r < 0)
836 return r;
837 if (r == 0)
838 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
839
840 i->userdata = userdata;
841 return bus_image_method_set_limit(message, i, error);
842 }
843
844 static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
845 _cleanup_fclose_ FILE *f = NULL;
846 Manager *m = userdata;
847 const char *name, *p;
848 Machine *machine;
849 uint32_t uid;
850 int r;
851
852 r = sd_bus_message_read(message, "su", &name, &uid);
853 if (r < 0)
854 return r;
855
856 if (UID_IS_INVALID(uid))
857 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
858
859 machine = hashmap_get(m->machines, name);
860 if (!machine)
861 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
862
863 p = procfs_file_alloca(machine->leader, "uid_map");
864 f = fopen(p, "re");
865 if (!f)
866 return -errno;
867
868 for (;;) {
869 uid_t uid_base, uid_shift, uid_range, converted;
870 int k;
871
872 errno = 0;
873 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
874 if (k < 0 && feof(f))
875 break;
876 if (k != 3) {
877 if (ferror(f) && errno != 0)
878 return -errno;
879
880 return -EIO;
881 }
882
883 if (uid < uid_base || uid >= uid_base + uid_range)
884 continue;
885
886 converted = uid - uid_base + uid_shift;
887 if (UID_IS_INVALID(converted))
888 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
889
890 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
891 }
892
893 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
894 }
895
896 static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
897 Manager *m = userdata;
898 Machine *machine;
899 uid_t uid;
900 Iterator i;
901 int r;
902
903 r = sd_bus_message_read(message, "u", &uid);
904 if (r < 0)
905 return r;
906 if (UID_IS_INVALID(uid))
907 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
908 if (uid < 0x10000)
909 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
910
911 HASHMAP_FOREACH(machine, m->machines, i) {
912 _cleanup_fclose_ FILE *f = NULL;
913 char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
914
915 xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
916 f = fopen(p, "re");
917 if (!f) {
918 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
919 continue;
920 }
921
922 for (;;) {
923 _cleanup_free_ char *o = NULL;
924 uid_t uid_base, uid_shift, uid_range, converted;
925 int k;
926
927 errno = 0;
928 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
929 if (k < 0 && feof(f))
930 break;
931 if (k != 3) {
932 if (ferror(f) && errno != 0)
933 return -errno;
934
935 return -EIO;
936 }
937
938 if (uid < uid_shift || uid >= uid_shift + uid_range)
939 continue;
940
941 converted = (uid - uid_shift + uid_base);
942 if (UID_IS_INVALID(converted))
943 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
944
945 o = machine_bus_path(machine);
946 if (!o)
947 return -ENOMEM;
948
949 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
950 }
951 }
952
953 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
954 }
955
956 static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
957 _cleanup_fclose_ FILE *f = NULL;
958 Manager *m = groupdata;
959 const char *name, *p;
960 Machine *machine;
961 uint32_t gid;
962 int r;
963
964 r = sd_bus_message_read(message, "su", &name, &gid);
965 if (r < 0)
966 return r;
967
968 if (GID_IS_INVALID(gid))
969 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
970
971 machine = hashmap_get(m->machines, name);
972 if (!machine)
973 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
974
975 p = procfs_file_alloca(machine->leader, "gid_map");
976 f = fopen(p, "re");
977 if (!f)
978 return -errno;
979
980 for (;;) {
981 gid_t gid_base, gid_shift, gid_range, converted;
982 int k;
983
984 errno = 0;
985 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
986 if (k < 0 && feof(f))
987 break;
988 if (k != 3) {
989 if (ferror(f) && errno != 0)
990 return -errno;
991
992 return -EIO;
993 }
994
995 if (gid < gid_base || gid >= gid_base + gid_range)
996 continue;
997
998 converted = gid - gid_base + gid_shift;
999 if (GID_IS_INVALID(converted))
1000 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1001
1002 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
1003 }
1004
1005 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
1006 }
1007
1008 static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
1009 Manager *m = groupdata;
1010 Machine *machine;
1011 gid_t gid;
1012 Iterator i;
1013 int r;
1014
1015 r = sd_bus_message_read(message, "u", &gid);
1016 if (r < 0)
1017 return r;
1018 if (GID_IS_INVALID(gid))
1019 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1020 if (gid < 0x10000)
1021 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
1022
1023 HASHMAP_FOREACH(machine, m->machines, i) {
1024 _cleanup_fclose_ FILE *f = NULL;
1025 char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
1026
1027 xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
1028 f = fopen(p, "re");
1029 if (!f) {
1030 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
1031 continue;
1032 }
1033
1034 for (;;) {
1035 _cleanup_free_ char *o = NULL;
1036 gid_t gid_base, gid_shift, gid_range, converted;
1037 int k;
1038
1039 errno = 0;
1040 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1041 if (k < 0 && feof(f))
1042 break;
1043 if (k != 3) {
1044 if (ferror(f) && errno != 0)
1045 return -errno;
1046
1047 return -EIO;
1048 }
1049
1050 if (gid < gid_shift || gid >= gid_shift + gid_range)
1051 continue;
1052
1053 converted = (gid - gid_shift + gid_base);
1054 if (GID_IS_INVALID(converted))
1055 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1056
1057 o = machine_bus_path(machine);
1058 if (!o)
1059 return -ENOMEM;
1060
1061 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
1062 }
1063 }
1064
1065 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
1066 }
1067
1068 const sd_bus_vtable manager_vtable[] = {
1069 SD_BUS_VTABLE_START(0),
1070 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
1071 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
1072 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
1073 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1074 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
1075 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
1076 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
1077 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
1078 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
1079 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
1080 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
1081 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
1082 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1083 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1084 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
1085 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
1086 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
1087 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
1088 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1089 SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1090 SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1091 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
1092 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
1093 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
1094 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
1095 SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
1096 SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
1097 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1098 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1099 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
1100 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
1101 SD_BUS_SIGNAL("MachineNew", "so", 0),
1102 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1103 SD_BUS_VTABLE_END
1104 };
1105
1106 int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1107 const char *path, *result, *unit;
1108 Manager *m = userdata;
1109 Machine *machine;
1110 uint32_t id;
1111 int r;
1112
1113 assert(message);
1114 assert(m);
1115
1116 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
1117 if (r < 0) {
1118 bus_log_parse_error(r);
1119 return r;
1120 }
1121
1122 machine = hashmap_get(m->machine_units, unit);
1123 if (!machine)
1124 return 0;
1125
1126 if (streq_ptr(path, machine->scope_job)) {
1127 free(machine->scope_job);
1128 machine->scope_job = NULL;
1129
1130 if (machine->started) {
1131 if (streq(result, "done"))
1132 machine_send_create_reply(machine, NULL);
1133 else {
1134 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
1135
1136 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
1137
1138 machine_send_create_reply(machine, &e);
1139 }
1140 } else
1141 machine_save(machine);
1142 }
1143
1144 machine_add_to_gc_queue(machine);
1145 return 0;
1146 }
1147
1148 int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1149 _cleanup_free_ char *unit = NULL;
1150 const char *path, *interface;
1151 Manager *m = userdata;
1152 Machine *machine;
1153 int r;
1154
1155 assert(message);
1156 assert(m);
1157
1158 path = sd_bus_message_get_path(message);
1159 if (!path)
1160 return 0;
1161
1162 r = unit_name_from_dbus_path(path, &unit);
1163 if (r == -EINVAL) /* not for a unit */
1164 return 0;
1165 if (r < 0){
1166 log_oom();
1167 return 0;
1168 }
1169
1170 machine = hashmap_get(m->machine_units, unit);
1171 if (!machine)
1172 return 0;
1173
1174 r = sd_bus_message_read(message, "s", &interface);
1175 if (r < 0) {
1176 bus_log_parse_error(r);
1177 return 0;
1178 }
1179
1180 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
1181 struct properties {
1182 char *active_state;
1183 char *sub_state;
1184 } properties = {};
1185
1186 const struct bus_properties_map map[] = {
1187 { "ActiveState", "s", NULL, offsetof(struct properties, active_state) },
1188 { "SubState", "s", NULL, offsetof(struct properties, sub_state) },
1189 {}
1190 };
1191
1192 r = bus_message_map_properties_changed(message, map, &properties);
1193 if (r < 0)
1194 bus_log_parse_error(r);
1195 else if (streq_ptr(properties.active_state, "inactive") ||
1196 streq_ptr(properties.active_state, "failed") ||
1197 streq_ptr(properties.sub_state, "auto-restart"))
1198 machine_release_unit(machine);
1199
1200 free(properties.active_state);
1201 free(properties.sub_state);
1202 }
1203
1204 machine_add_to_gc_queue(machine);
1205 return 0;
1206 }
1207
1208 int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1209 const char *path, *unit;
1210 Manager *m = userdata;
1211 Machine *machine;
1212 int r;
1213
1214 assert(message);
1215 assert(m);
1216
1217 r = sd_bus_message_read(message, "so", &unit, &path);
1218 if (r < 0) {
1219 bus_log_parse_error(r);
1220 return 0;
1221 }
1222
1223 machine = hashmap_get(m->machine_units, unit);
1224 if (!machine)
1225 return 0;
1226
1227 machine_release_unit(machine);
1228 machine_add_to_gc_queue(machine);
1229
1230 return 0;
1231 }
1232
1233 int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1234 Manager *m = userdata;
1235 Machine *machine;
1236 Iterator i;
1237 int b, r;
1238
1239 assert(message);
1240 assert(m);
1241
1242 r = sd_bus_message_read(message, "b", &b);
1243 if (r < 0) {
1244 bus_log_parse_error(r);
1245 return r;
1246 }
1247 if (b)
1248 return 0;
1249
1250 /* systemd finished reloading, let's recheck all our machines */
1251 log_debug("System manager has been reloaded, rechecking machines...");
1252
1253 HASHMAP_FOREACH(machine, m->machines, i)
1254 machine_add_to_gc_queue(machine);
1255
1256 return 0;
1257 }
1258
1259 int manager_start_scope(
1260 Manager *manager,
1261 const char *scope,
1262 pid_t pid,
1263 const char *slice,
1264 const char *description,
1265 sd_bus_message *more_properties,
1266 sd_bus_error *error,
1267 char **job) {
1268
1269 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1270 int r;
1271
1272 assert(manager);
1273 assert(scope);
1274 assert(pid > 1);
1275
1276 r = sd_bus_message_new_method_call(
1277 manager->bus,
1278 &m,
1279 "org.freedesktop.systemd1",
1280 "/org/freedesktop/systemd1",
1281 "org.freedesktop.systemd1.Manager",
1282 "StartTransientUnit");
1283 if (r < 0)
1284 return r;
1285
1286 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
1287 if (r < 0)
1288 return r;
1289
1290 r = sd_bus_message_open_container(m, 'a', "(sv)");
1291 if (r < 0)
1292 return r;
1293
1294 if (!isempty(slice)) {
1295 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1296 if (r < 0)
1297 return r;
1298 }
1299
1300 if (!isempty(description)) {
1301 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1302 if (r < 0)
1303 return r;
1304 }
1305
1306 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1307 if (r < 0)
1308 return r;
1309
1310 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1311 if (r < 0)
1312 return r;
1313
1314 if (more_properties) {
1315 r = sd_bus_message_copy(m, more_properties, true);
1316 if (r < 0)
1317 return r;
1318 }
1319
1320 r = sd_bus_message_close_container(m);
1321 if (r < 0)
1322 return r;
1323
1324 r = sd_bus_message_append(m, "a(sa(sv))", 0);
1325 if (r < 0)
1326 return r;
1327
1328 r = sd_bus_call(manager->bus, m, 0, error, &reply);
1329 if (r < 0)
1330 return r;
1331
1332 if (job) {
1333 const char *j;
1334 char *copy;
1335
1336 r = sd_bus_message_read(reply, "o", &j);
1337 if (r < 0)
1338 return r;
1339
1340 copy = strdup(j);
1341 if (!copy)
1342 return -ENOMEM;
1343
1344 *job = copy;
1345 }
1346
1347 return 1;
1348 }
1349
1350 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
1351 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1352 int r;
1353
1354 assert(manager);
1355 assert(unit);
1356
1357 r = sd_bus_call_method(
1358 manager->bus,
1359 "org.freedesktop.systemd1",
1360 "/org/freedesktop/systemd1",
1361 "org.freedesktop.systemd1.Manager",
1362 "StopUnit",
1363 error,
1364 &reply,
1365 "ss", unit, "fail");
1366 if (r < 0) {
1367 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1368 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
1369
1370 if (job)
1371 *job = NULL;
1372
1373 sd_bus_error_free(error);
1374 return 0;
1375 }
1376
1377 return r;
1378 }
1379
1380 if (job) {
1381 const char *j;
1382 char *copy;
1383
1384 r = sd_bus_message_read(reply, "o", &j);
1385 if (r < 0)
1386 return r;
1387
1388 copy = strdup(j);
1389 if (!copy)
1390 return -ENOMEM;
1391
1392 *job = copy;
1393 }
1394
1395 return 1;
1396 }
1397
1398 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1399 assert(manager);
1400 assert(unit);
1401
1402 return sd_bus_call_method(
1403 manager->bus,
1404 "org.freedesktop.systemd1",
1405 "/org/freedesktop/systemd1",
1406 "org.freedesktop.systemd1.Manager",
1407 "KillUnit",
1408 error,
1409 NULL,
1410 "ssi", unit, "all", signo);
1411 }
1412
1413 int manager_unit_is_active(Manager *manager, const char *unit) {
1414 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1415 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1416 _cleanup_free_ char *path = NULL;
1417 const char *state;
1418 int r;
1419
1420 assert(manager);
1421 assert(unit);
1422
1423 path = unit_dbus_path_from_name(unit);
1424 if (!path)
1425 return -ENOMEM;
1426
1427 r = sd_bus_get_property(
1428 manager->bus,
1429 "org.freedesktop.systemd1",
1430 path,
1431 "org.freedesktop.systemd1.Unit",
1432 "ActiveState",
1433 &error,
1434 &reply,
1435 "s");
1436 if (r < 0) {
1437 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1438 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1439 return true;
1440
1441 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1442 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1443 return false;
1444
1445 return r;
1446 }
1447
1448 r = sd_bus_message_read(reply, "s", &state);
1449 if (r < 0)
1450 return -EINVAL;
1451
1452 return !STR_IN_SET(state, "inactive", "failed");
1453 }
1454
1455 int manager_job_is_active(Manager *manager, const char *path) {
1456 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1457 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1458 int r;
1459
1460 assert(manager);
1461 assert(path);
1462
1463 r = sd_bus_get_property(
1464 manager->bus,
1465 "org.freedesktop.systemd1",
1466 path,
1467 "org.freedesktop.systemd1.Job",
1468 "State",
1469 &error,
1470 &reply,
1471 "s");
1472 if (r < 0) {
1473 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1474 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1475 return true;
1476
1477 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1478 return false;
1479
1480 return r;
1481 }
1482
1483 /* We don't actually care about the state really. The fact
1484 * that we could read the job state is enough for us */
1485
1486 return true;
1487 }
1488
1489 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1490 _cleanup_free_ char *unit = NULL;
1491 Machine *mm;
1492 int r;
1493
1494 assert(m);
1495 assert(pid >= 1);
1496 assert(machine);
1497
1498 r = cg_pid_get_unit(pid, &unit);
1499 if (r < 0)
1500 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1501 else
1502 mm = hashmap_get(m->machine_units, unit);
1503
1504 if (!mm)
1505 return 0;
1506
1507 *machine = mm;
1508 return 1;
1509 }
1510
1511 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1512 Machine *machine;
1513
1514 assert(m);
1515 assert(name);
1516
1517 machine = hashmap_get(m->machines, name);
1518 if (!machine) {
1519 machine = machine_new(m, name);
1520 if (!machine)
1521 return -ENOMEM;
1522 }
1523
1524 if (_machine)
1525 *_machine = machine;
1526
1527 return 0;
1528 }