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