]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined-dbus.c
logind,machined: various smaller cleanups
[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 0;
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 machine->scope_job = mfree(machine->scope_job);
1128
1129 if (machine->started) {
1130 if (streq(result, "done"))
1131 machine_send_create_reply(machine, NULL);
1132 else {
1133 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
1134
1135 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
1136
1137 machine_send_create_reply(machine, &e);
1138 }
1139 } else
1140 machine_save(machine);
1141 }
1142
1143 machine_add_to_gc_queue(machine);
1144 return 0;
1145 }
1146
1147 int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1148 _cleanup_free_ char *unit = NULL;
1149 const char *path, *interface;
1150 Manager *m = userdata;
1151 Machine *machine;
1152 int r;
1153
1154 assert(message);
1155 assert(m);
1156
1157 path = sd_bus_message_get_path(message);
1158 if (!path)
1159 return 0;
1160
1161 r = unit_name_from_dbus_path(path, &unit);
1162 if (r == -EINVAL) /* not for a unit */
1163 return 0;
1164 if (r < 0){
1165 log_oom();
1166 return 0;
1167 }
1168
1169 machine = hashmap_get(m->machine_units, unit);
1170 if (!machine)
1171 return 0;
1172
1173 r = sd_bus_message_read(message, "s", &interface);
1174 if (r < 0) {
1175 bus_log_parse_error(r);
1176 return 0;
1177 }
1178
1179 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
1180 struct properties {
1181 char *active_state;
1182 char *sub_state;
1183 } properties = {};
1184
1185 const struct bus_properties_map map[] = {
1186 { "ActiveState", "s", NULL, offsetof(struct properties, active_state) },
1187 { "SubState", "s", NULL, offsetof(struct properties, sub_state) },
1188 {}
1189 };
1190
1191 r = bus_message_map_properties_changed(message, map, &properties);
1192 if (r < 0)
1193 bus_log_parse_error(r);
1194 else if (streq_ptr(properties.active_state, "inactive") ||
1195 streq_ptr(properties.active_state, "failed") ||
1196 streq_ptr(properties.sub_state, "auto-restart"))
1197 machine_release_unit(machine);
1198
1199 free(properties.active_state);
1200 free(properties.sub_state);
1201 }
1202
1203 machine_add_to_gc_queue(machine);
1204 return 0;
1205 }
1206
1207 int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1208 const char *path, *unit;
1209 Manager *m = userdata;
1210 Machine *machine;
1211 int r;
1212
1213 assert(message);
1214 assert(m);
1215
1216 r = sd_bus_message_read(message, "so", &unit, &path);
1217 if (r < 0) {
1218 bus_log_parse_error(r);
1219 return 0;
1220 }
1221
1222 machine = hashmap_get(m->machine_units, unit);
1223 if (!machine)
1224 return 0;
1225
1226 machine_release_unit(machine);
1227 machine_add_to_gc_queue(machine);
1228
1229 return 0;
1230 }
1231
1232 int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1233 Manager *m = userdata;
1234 Machine *machine;
1235 Iterator i;
1236 int b, r;
1237
1238 assert(message);
1239 assert(m);
1240
1241 r = sd_bus_message_read(message, "b", &b);
1242 if (r < 0) {
1243 bus_log_parse_error(r);
1244 return 0;
1245 }
1246 if (b)
1247 return 0;
1248
1249 /* systemd finished reloading, let's recheck all our machines */
1250 log_debug("System manager has been reloaded, rechecking machines...");
1251
1252 HASHMAP_FOREACH(machine, m->machines, i)
1253 machine_add_to_gc_queue(machine);
1254
1255 return 0;
1256 }
1257
1258 int manager_start_scope(
1259 Manager *manager,
1260 const char *scope,
1261 pid_t pid,
1262 const char *slice,
1263 const char *description,
1264 sd_bus_message *more_properties,
1265 sd_bus_error *error,
1266 char **job) {
1267
1268 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1269 int r;
1270
1271 assert(manager);
1272 assert(scope);
1273 assert(pid > 1);
1274
1275 r = sd_bus_message_new_method_call(
1276 manager->bus,
1277 &m,
1278 "org.freedesktop.systemd1",
1279 "/org/freedesktop/systemd1",
1280 "org.freedesktop.systemd1.Manager",
1281 "StartTransientUnit");
1282 if (r < 0)
1283 return r;
1284
1285 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
1286 if (r < 0)
1287 return r;
1288
1289 r = sd_bus_message_open_container(m, 'a', "(sv)");
1290 if (r < 0)
1291 return r;
1292
1293 if (!isempty(slice)) {
1294 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1295 if (r < 0)
1296 return r;
1297 }
1298
1299 if (!isempty(description)) {
1300 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1301 if (r < 0)
1302 return r;
1303 }
1304
1305 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1306 if (r < 0)
1307 return r;
1308
1309 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1310 if (r < 0)
1311 return r;
1312
1313 if (more_properties) {
1314 r = sd_bus_message_copy(m, more_properties, true);
1315 if (r < 0)
1316 return r;
1317 }
1318
1319 r = sd_bus_message_close_container(m);
1320 if (r < 0)
1321 return r;
1322
1323 r = sd_bus_message_append(m, "a(sa(sv))", 0);
1324 if (r < 0)
1325 return r;
1326
1327 r = sd_bus_call(manager->bus, m, 0, error, &reply);
1328 if (r < 0)
1329 return r;
1330
1331 if (job) {
1332 const char *j;
1333 char *copy;
1334
1335 r = sd_bus_message_read(reply, "o", &j);
1336 if (r < 0)
1337 return r;
1338
1339 copy = strdup(j);
1340 if (!copy)
1341 return -ENOMEM;
1342
1343 *job = copy;
1344 }
1345
1346 return 1;
1347 }
1348
1349 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
1350 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1351 int r;
1352
1353 assert(manager);
1354 assert(unit);
1355
1356 r = sd_bus_call_method(
1357 manager->bus,
1358 "org.freedesktop.systemd1",
1359 "/org/freedesktop/systemd1",
1360 "org.freedesktop.systemd1.Manager",
1361 "StopUnit",
1362 error,
1363 &reply,
1364 "ss", unit, "fail");
1365 if (r < 0) {
1366 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1367 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
1368
1369 if (job)
1370 *job = NULL;
1371
1372 sd_bus_error_free(error);
1373 return 0;
1374 }
1375
1376 return r;
1377 }
1378
1379 if (job) {
1380 const char *j;
1381 char *copy;
1382
1383 r = sd_bus_message_read(reply, "o", &j);
1384 if (r < 0)
1385 return r;
1386
1387 copy = strdup(j);
1388 if (!copy)
1389 return -ENOMEM;
1390
1391 *job = copy;
1392 }
1393
1394 return 1;
1395 }
1396
1397 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1398 assert(manager);
1399 assert(unit);
1400
1401 return sd_bus_call_method(
1402 manager->bus,
1403 "org.freedesktop.systemd1",
1404 "/org/freedesktop/systemd1",
1405 "org.freedesktop.systemd1.Manager",
1406 "KillUnit",
1407 error,
1408 NULL,
1409 "ssi", unit, "all", signo);
1410 }
1411
1412 int manager_unit_is_active(Manager *manager, const char *unit) {
1413 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1414 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1415 _cleanup_free_ char *path = NULL;
1416 const char *state;
1417 int r;
1418
1419 assert(manager);
1420 assert(unit);
1421
1422 path = unit_dbus_path_from_name(unit);
1423 if (!path)
1424 return -ENOMEM;
1425
1426 r = sd_bus_get_property(
1427 manager->bus,
1428 "org.freedesktop.systemd1",
1429 path,
1430 "org.freedesktop.systemd1.Unit",
1431 "ActiveState",
1432 &error,
1433 &reply,
1434 "s");
1435 if (r < 0) {
1436 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1437 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1438 return true;
1439
1440 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1441 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1442 return false;
1443
1444 return r;
1445 }
1446
1447 r = sd_bus_message_read(reply, "s", &state);
1448 if (r < 0)
1449 return -EINVAL;
1450
1451 return !STR_IN_SET(state, "inactive", "failed");
1452 }
1453
1454 int manager_job_is_active(Manager *manager, const char *path) {
1455 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1456 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1457 int r;
1458
1459 assert(manager);
1460 assert(path);
1461
1462 r = sd_bus_get_property(
1463 manager->bus,
1464 "org.freedesktop.systemd1",
1465 path,
1466 "org.freedesktop.systemd1.Job",
1467 "State",
1468 &error,
1469 &reply,
1470 "s");
1471 if (r < 0) {
1472 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1473 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1474 return true;
1475
1476 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1477 return false;
1478
1479 return r;
1480 }
1481
1482 /* We don't actually care about the state really. The fact
1483 * that we could read the job state is enough for us */
1484
1485 return true;
1486 }
1487
1488 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1489 _cleanup_free_ char *unit = NULL;
1490 Machine *mm;
1491 int r;
1492
1493 assert(m);
1494 assert(pid >= 1);
1495 assert(machine);
1496
1497 r = cg_pid_get_unit(pid, &unit);
1498 if (r < 0)
1499 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1500 else
1501 mm = hashmap_get(m->machine_units, unit);
1502
1503 if (!mm)
1504 return 0;
1505
1506 *machine = mm;
1507 return 1;
1508 }
1509
1510 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1511 Machine *machine;
1512
1513 assert(m);
1514 assert(name);
1515
1516 machine = hashmap_get(m->machines, name);
1517 if (!machine) {
1518 machine = machine_new(m, name);
1519 if (!machine)
1520 return -ENOMEM;
1521 }
1522
1523 if (_machine)
1524 *_machine = machine;
1525
1526 return 0;
1527 }