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