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