]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined-dbus.c
0b57a62fd4e96793f864f161c915b901480c4ad4
[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 "path-util.h"
28 #include "unit-name.h"
29 #include "bus-util.h"
30 #include "bus-common-errors.h"
31 #include "cgroup-util.h"
32 #include "btrfs-util.h"
33 #include "machine-image.h"
34 #include "image-dbus.h"
35 #include "machined.h"
36 #include "machine-dbus.h"
37
38 static int property_get_pool_path(
39 sd_bus *bus,
40 const char *path,
41 const char *interface,
42 const char *property,
43 sd_bus_message *reply,
44 void *userdata,
45 sd_bus_error *error) {
46
47 assert(bus);
48 assert(reply);
49
50 return sd_bus_message_append(reply, "s", "/var/lib/machines");
51 }
52
53 static int property_get_pool_usage(
54 sd_bus *bus,
55 const char *path,
56 const char *interface,
57 const char *property,
58 sd_bus_message *reply,
59 void *userdata,
60 sd_bus_error *error) {
61
62 _cleanup_close_ int fd = -1;
63 uint64_t usage = (uint64_t) -1;
64 struct stat st;
65
66 assert(bus);
67 assert(reply);
68
69 /* We try to read the quota info from /var/lib/machines, as
70 * well as the usage of the loopback file
71 * /var/lib/machines.raw, and pick the larger value. */
72
73 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
74 if (fd >= 0) {
75 BtrfsQuotaInfo q;
76
77 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
78 usage = q.referred;
79 }
80
81 if (stat("/var/lib/machines.raw", &st) >= 0) {
82 if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
83 usage = st.st_blocks * 512ULL;
84 }
85
86 return sd_bus_message_append(reply, "t", usage);
87 }
88
89 static int property_get_pool_limit(
90 sd_bus *bus,
91 const char *path,
92 const char *interface,
93 const char *property,
94 sd_bus_message *reply,
95 void *userdata,
96 sd_bus_error *error) {
97
98 _cleanup_close_ int fd = -1;
99 uint64_t size = (uint64_t) -1;
100 struct stat st;
101
102 assert(bus);
103 assert(reply);
104
105 /* We try to read the quota limit from /var/lib/machines, as
106 * well as the size of the loopback file
107 * /var/lib/machines.raw, and pick the smaller value. */
108
109 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
110 if (fd >= 0) {
111 BtrfsQuotaInfo q;
112
113 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
114 size = q.referred_max;
115 }
116
117 if (stat("/var/lib/machines.raw", &st) >= 0) {
118 if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
119 size = st.st_size;
120 }
121
122 return sd_bus_message_append(reply, "t", size);
123 }
124
125 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
126 _cleanup_free_ char *p = NULL;
127 Manager *m = userdata;
128 Machine *machine;
129 const char *name;
130 int r;
131
132 assert(bus);
133 assert(message);
134 assert(m);
135
136 r = sd_bus_message_read(message, "s", &name);
137 if (r < 0)
138 return r;
139
140 machine = hashmap_get(m->machines, name);
141 if (!machine)
142 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
143
144 p = machine_bus_path(machine);
145 if (!p)
146 return -ENOMEM;
147
148 return sd_bus_reply_method_return(message, "o", p);
149 }
150
151 static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
152 _cleanup_free_ char *p = NULL;
153 Manager *m = userdata;
154 const char *name;
155 int r;
156
157 assert(bus);
158 assert(message);
159 assert(m);
160
161 r = sd_bus_message_read(message, "s", &name);
162 if (r < 0)
163 return r;
164
165 r = image_find(name, NULL);
166 if (r == 0)
167 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
168 if (r < 0)
169 return r;
170
171 p = image_bus_path(name);
172 if (!p)
173 return -ENOMEM;
174
175 return sd_bus_reply_method_return(message, "o", p);
176 }
177
178 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
179 _cleanup_free_ char *p = NULL;
180 Manager *m = userdata;
181 Machine *machine = NULL;
182 pid_t pid;
183 int r;
184
185 assert(bus);
186 assert(message);
187 assert(m);
188
189 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
190
191 r = sd_bus_message_read(message, "u", &pid);
192 if (r < 0)
193 return r;
194
195 if (pid == 0) {
196 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
197
198 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
199 if (r < 0)
200 return r;
201
202 r = sd_bus_creds_get_pid(creds, &pid);
203 if (r < 0)
204 return r;
205 }
206
207 r = manager_get_machine_by_pid(m, pid, &machine);
208 if (r < 0)
209 return r;
210 if (!machine)
211 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
212
213 p = machine_bus_path(machine);
214 if (!p)
215 return -ENOMEM;
216
217 return sd_bus_reply_method_return(message, "o", p);
218 }
219
220 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
221 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
222 Manager *m = userdata;
223 Machine *machine;
224 Iterator i;
225 int r;
226
227 assert(bus);
228 assert(message);
229 assert(m);
230
231 r = sd_bus_message_new_method_return(message, &reply);
232 if (r < 0)
233 return sd_bus_error_set_errno(error, r);
234
235 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
236 if (r < 0)
237 return sd_bus_error_set_errno(error, r);
238
239 HASHMAP_FOREACH(machine, m->machines, i) {
240 _cleanup_free_ char *p = NULL;
241
242 p = machine_bus_path(machine);
243 if (!p)
244 return -ENOMEM;
245
246 r = sd_bus_message_append(reply, "(ssso)",
247 machine->name,
248 strempty(machine_class_to_string(machine->class)),
249 machine->service,
250 p);
251 if (r < 0)
252 return sd_bus_error_set_errno(error, r);
253 }
254
255 r = sd_bus_message_close_container(reply);
256 if (r < 0)
257 return sd_bus_error_set_errno(error, r);
258
259 return sd_bus_send(bus, reply, NULL);
260 }
261
262 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
263 const char *name, *service, *class, *root_directory;
264 const int32_t *netif = NULL;
265 MachineClass c;
266 uint32_t leader;
267 sd_id128_t id;
268 const void *v;
269 Machine *m;
270 size_t n, n_netif = 0;
271 int r;
272
273 assert(manager);
274 assert(message);
275 assert(_m);
276
277 r = sd_bus_message_read(message, "s", &name);
278 if (r < 0)
279 return r;
280 if (!machine_name_is_valid(name))
281 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
282
283 r = sd_bus_message_read_array(message, 'y', &v, &n);
284 if (r < 0)
285 return r;
286 if (n == 0)
287 id = SD_ID128_NULL;
288 else if (n == 16)
289 memcpy(&id, v, n);
290 else
291 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
292
293 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
294 if (r < 0)
295 return r;
296
297 if (read_network) {
298 size_t i;
299
300 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
301 if (r < 0)
302 return r;
303
304 n_netif /= sizeof(int32_t);
305
306 for (i = 0; i < n_netif; i++) {
307 if (netif[i] <= 0)
308 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
309 }
310 }
311
312 if (isempty(class))
313 c = _MACHINE_CLASS_INVALID;
314 else {
315 c = machine_class_from_string(class);
316 if (c < 0)
317 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
318 }
319
320 if (leader == 1)
321 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
322
323 if (!isempty(root_directory) && !path_is_absolute(root_directory))
324 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
325
326 if (leader == 0) {
327 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
328
329 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
330 if (r < 0)
331 return r;
332
333 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
334
335 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
336 if (r < 0)
337 return r;
338 }
339
340 if (hashmap_get(manager->machines, name))
341 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
342
343 r = manager_add_machine(manager, name, &m);
344 if (r < 0)
345 return r;
346
347 m->leader = leader;
348 m->class = c;
349 m->id = id;
350
351 if (!isempty(service)) {
352 m->service = strdup(service);
353 if (!m->service) {
354 r = -ENOMEM;
355 goto fail;
356 }
357 }
358
359 if (!isempty(root_directory)) {
360 m->root_directory = strdup(root_directory);
361 if (!m->root_directory) {
362 r = -ENOMEM;
363 goto fail;
364 }
365 }
366
367 if (n_netif > 0) {
368 assert_cc(sizeof(int32_t) == sizeof(int));
369 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
370 if (!m->netif) {
371 r = -ENOMEM;
372 goto fail;
373 }
374
375 m->n_netif = n_netif;
376 }
377
378 *_m = m;
379
380 return 1;
381
382 fail:
383 machine_add_to_gc_queue(m);
384 return r;
385 }
386
387 static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
388 Manager *manager = userdata;
389 Machine *m = NULL;
390 int r;
391
392 r = method_create_or_register_machine(manager, message, read_network, &m, error);
393 if (r < 0)
394 return r;
395
396 r = sd_bus_message_enter_container(message, 'a', "(sv)");
397 if (r < 0)
398 goto fail;
399
400 r = machine_start(m, message, error);
401 if (r < 0)
402 goto fail;
403
404 m->create_message = sd_bus_message_ref(message);
405 return 1;
406
407 fail:
408 machine_add_to_gc_queue(m);
409 return r;
410 }
411
412 static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
413 return method_create_machine_internal(bus, message, true, userdata, error);
414 }
415
416 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
417 return method_create_machine_internal(bus, message, false, userdata, error);
418 }
419
420 static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
421 Manager *manager = userdata;
422 _cleanup_free_ char *p = NULL;
423 Machine *m = NULL;
424 int r;
425
426 r = method_create_or_register_machine(manager, message, read_network, &m, error);
427 if (r < 0)
428 return r;
429
430 r = cg_pid_get_unit(m->leader, &m->unit);
431 if (r < 0) {
432 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
433 goto fail;
434 }
435
436 r = machine_start(m, NULL, error);
437 if (r < 0)
438 goto fail;
439
440 p = machine_bus_path(m);
441 if (!p) {
442 r = -ENOMEM;
443 goto fail;
444 }
445
446 return sd_bus_reply_method_return(message, "o", p);
447
448 fail:
449 machine_add_to_gc_queue(m);
450 return r;
451 }
452
453 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
454 return method_register_machine_internal(bus, message, true, userdata, error);
455 }
456
457 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
458 return method_register_machine_internal(bus, message, false, userdata, error);
459 }
460
461 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
462 Manager *m = userdata;
463 Machine *machine;
464 const char *name;
465 int r;
466
467 assert(bus);
468 assert(message);
469 assert(m);
470
471 r = sd_bus_message_read(message, "s", &name);
472 if (r < 0)
473 return sd_bus_error_set_errno(error, r);
474
475 machine = hashmap_get(m->machines, name);
476 if (!machine)
477 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
478
479 return bus_machine_method_terminate(bus, message, machine, error);
480 }
481
482 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
483 Manager *m = userdata;
484 Machine *machine;
485 const char *name;
486 int r;
487
488 assert(bus);
489 assert(message);
490 assert(m);
491
492 r = sd_bus_message_read(message, "s", &name);
493 if (r < 0)
494 return sd_bus_error_set_errno(error, r);
495
496 machine = hashmap_get(m->machines, name);
497 if (!machine)
498 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
499
500 return bus_machine_method_kill(bus, message, machine, error);
501 }
502
503 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
504 Manager *m = userdata;
505 Machine *machine;
506 const char *name;
507 int r;
508
509 assert(bus);
510 assert(message);
511 assert(m);
512
513 r = sd_bus_message_read(message, "s", &name);
514 if (r < 0)
515 return sd_bus_error_set_errno(error, r);
516
517 machine = hashmap_get(m->machines, name);
518 if (!machine)
519 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
520
521 return bus_machine_method_get_addresses(bus, message, machine, error);
522 }
523
524 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
525 Manager *m = userdata;
526 Machine *machine;
527 const char *name;
528 int r;
529
530 assert(bus);
531 assert(message);
532 assert(m);
533
534 r = sd_bus_message_read(message, "s", &name);
535 if (r < 0)
536 return sd_bus_error_set_errno(error, r);
537
538 machine = hashmap_get(m->machines, name);
539 if (!machine)
540 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
541
542 return bus_machine_method_get_os_release(bus, message, machine, error);
543 }
544
545 static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
546 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
547 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
548 Manager *m = userdata;
549 Image *image;
550 Iterator i;
551 int r;
552
553 assert(bus);
554 assert(message);
555 assert(m);
556
557 images = hashmap_new(&string_hash_ops);
558 if (!images)
559 return -ENOMEM;
560
561 r = image_discover(images);
562 if (r < 0)
563 return r;
564
565 r = sd_bus_message_new_method_return(message, &reply);
566 if (r < 0)
567 return r;
568
569 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
570 if (r < 0)
571 return r;
572
573 HASHMAP_FOREACH(image, images, i) {
574 _cleanup_free_ char *p = NULL;
575
576 p = image_bus_path(image->name);
577 if (!p)
578 return -ENOMEM;
579
580 r = sd_bus_message_append(reply, "(ssbttto)",
581 image->name,
582 image_type_to_string(image->type),
583 image->read_only,
584 image->crtime,
585 image->mtime,
586 image->usage,
587 p);
588 if (r < 0)
589 return r;
590 }
591
592 r = sd_bus_message_close_container(reply);
593 if (r < 0)
594 return r;
595
596 return sd_bus_send(bus, reply, NULL);
597 }
598
599 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
600 Manager *m = userdata;
601 Machine *machine;
602 const char *name;
603 int r;
604
605 assert(bus);
606 assert(message);
607 assert(m);
608
609 r = sd_bus_message_read(message, "s", &name);
610 if (r < 0)
611 return sd_bus_error_set_errno(error, r);
612
613 machine = hashmap_get(m->machines, name);
614 if (!machine)
615 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
616
617 return bus_machine_method_open_pty(bus, message, machine, error);
618 }
619
620 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
621 Manager *m = userdata;
622 Machine *machine;
623 const char *name;
624 int r;
625
626 assert(bus);
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(bus, message, machine, error);
639 }
640
641 static int method_bind_mount_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
642 Manager *m = userdata;
643 Machine *machine;
644 const char *name;
645 int r;
646
647 assert(bus);
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_bind_mount(bus, message, machine, error);
660 }
661
662 static int method_copy_machine(sd_bus *bus, 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(bus);
669 assert(message);
670 assert(m);
671
672 r = sd_bus_message_read(message, "s", &name);
673 if (r < 0)
674 return r;
675
676 machine = hashmap_get(m->machines, name);
677 if (!machine)
678 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
679
680 return bus_machine_method_copy(bus, message, machine, error);
681 }
682
683 static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
684 _cleanup_(image_unrefp) Image* i = NULL;
685 const char *name;
686 int r;
687
688 assert(bus);
689 assert(message);
690
691 r = sd_bus_message_read(message, "s", &name);
692 if (r < 0)
693 return r;
694
695 if (!image_name_is_valid(name))
696 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
697
698 r = image_find(name, &i);
699 if (r < 0)
700 return r;
701 if (r == 0)
702 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
703
704 i->userdata = userdata;
705 return bus_image_method_remove(bus, message, i, error);
706 }
707
708 static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
709 _cleanup_(image_unrefp) Image* i = NULL;
710 const char *old_name;
711 int r;
712
713 assert(bus);
714 assert(message);
715
716 r = sd_bus_message_read(message, "s", &old_name);
717 if (r < 0)
718 return r;
719
720 if (!image_name_is_valid(old_name))
721 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
722
723 r = image_find(old_name, &i);
724 if (r < 0)
725 return r;
726 if (r == 0)
727 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
728
729 i->userdata = userdata;
730 return bus_image_method_rename(bus, message, i, error);
731 }
732
733 static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
734 _cleanup_(image_unrefp) Image *i = NULL;
735 const char *old_name;
736 int r;
737
738 assert(bus);
739 r = sd_bus_message_read(message, "s", &old_name);
740 if (r < 0)
741 return r;
742
743 if (!image_name_is_valid(old_name))
744 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
745
746 r = image_find(old_name, &i);
747 if (r < 0)
748 return r;
749 if (r == 0)
750 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
751
752 i->userdata = userdata;
753 return bus_image_method_clone(bus, message, i, error);
754 }
755
756 static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
757 _cleanup_(image_unrefp) Image *i = NULL;
758 const char *name;
759 int r;
760
761 assert(bus);
762 r = sd_bus_message_read(message, "s", &name);
763 if (r < 0)
764 return r;
765
766 if (!image_name_is_valid(name))
767 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
768
769 r = image_find(name, &i);
770 if (r < 0)
771 return r;
772 if (r == 0)
773 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
774
775 i->userdata = userdata;
776 return bus_image_method_mark_read_only(bus, message, i, error);
777 }
778
779 static int method_set_pool_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
780 Manager *m = userdata;
781 uint64_t limit;
782 int r;
783
784 assert(bus);
785 r = sd_bus_message_read(message, "t", &limit);
786 if (r < 0)
787 return r;
788
789 r = bus_verify_polkit_async(
790 message,
791 CAP_SYS_ADMIN,
792 "org.freedesktop.machine1.manage-machines",
793 false,
794 UID_INVALID,
795 &m->polkit_registry,
796 error);
797 if (r < 0)
798 return r;
799 if (r == 0)
800 return 1; /* Will call us back */
801
802 r = btrfs_resize_loopback("/var/lib/machines", limit);
803 if (r < 0 && r != -ENODEV)
804 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
805
806 r = btrfs_quota_limit("/var/lib/machines", limit);
807 if (r == -ENOTTY)
808 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
809 else if (r < 0)
810 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
811
812 return sd_bus_reply_method_return(message, NULL);
813 }
814
815 static int method_set_image_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
816 _cleanup_(image_unrefp) Image *i = NULL;
817 const char *name;
818 int r;
819
820 assert(bus);
821 r = sd_bus_message_read(message, "s", &name);
822 if (r < 0)
823 return r;
824
825 if (!image_name_is_valid(name))
826 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
827
828 r = image_find(name, &i);
829 if (r < 0)
830 return r;
831 if (r == 0)
832 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
833
834 i->userdata = userdata;
835 return bus_image_method_set_limit(bus, message, i, error);
836 }
837
838 const sd_bus_vtable manager_vtable[] = {
839 SD_BUS_VTABLE_START(0),
840 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
841 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
842 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
843 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
844 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
845 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
846 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
847 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
848 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
849 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
850 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
851 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
852 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
853 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
854 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
855 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
856 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
857 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
858 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
859 SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
860 SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
861 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
862 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
863 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
864 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
865 SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
866 SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
867 SD_BUS_SIGNAL("MachineNew", "so", 0),
868 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
869 SD_BUS_VTABLE_END
870 };
871
872 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
873 const char *path, *result, *unit;
874 Manager *m = userdata;
875 Machine *machine;
876 uint32_t id;
877 int r;
878
879 assert(bus);
880 assert(message);
881 assert(m);
882
883 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
884 if (r < 0) {
885 bus_log_parse_error(r);
886 return r;
887 }
888
889 machine = hashmap_get(m->machine_units, unit);
890 if (!machine)
891 return 0;
892
893 if (streq_ptr(path, machine->scope_job)) {
894 free(machine->scope_job);
895 machine->scope_job = NULL;
896
897 if (machine->started) {
898 if (streq(result, "done"))
899 machine_send_create_reply(machine, NULL);
900 else {
901 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
902
903 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
904
905 machine_send_create_reply(machine, &e);
906 }
907 } else
908 machine_save(machine);
909 }
910
911 machine_add_to_gc_queue(machine);
912 return 0;
913 }
914
915 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
916 _cleanup_free_ char *unit = NULL;
917 Manager *m = userdata;
918 Machine *machine;
919 const char *path;
920 int r;
921
922 assert(bus);
923 assert(message);
924 assert(m);
925
926 path = sd_bus_message_get_path(message);
927 if (!path)
928 return 0;
929
930 r = unit_name_from_dbus_path(path, &unit);
931 if (r == -EINVAL) /* not for a unit */
932 return 0;
933 if (r < 0)
934 return r;
935
936 machine = hashmap_get(m->machine_units, unit);
937 if (machine)
938 machine_add_to_gc_queue(machine);
939
940 return 0;
941 }
942
943 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
944 const char *path, *unit;
945 Manager *m = userdata;
946 Machine *machine;
947 int r;
948
949 assert(bus);
950 assert(message);
951 assert(m);
952
953 r = sd_bus_message_read(message, "so", &unit, &path);
954 if (r < 0) {
955 bus_log_parse_error(r);
956 return r;
957 }
958
959 machine = hashmap_get(m->machine_units, unit);
960 if (machine)
961 machine_add_to_gc_queue(machine);
962
963 return 0;
964 }
965
966 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
967 Manager *m = userdata;
968 Machine *machine;
969 Iterator i;
970 int b, r;
971
972 assert(bus);
973
974 r = sd_bus_message_read(message, "b", &b);
975 if (r < 0) {
976 bus_log_parse_error(r);
977 return r;
978 }
979 if (b)
980 return 0;
981
982 /* systemd finished reloading, let's recheck all our machines */
983 log_debug("System manager has been reloaded, rechecking machines...");
984
985 HASHMAP_FOREACH(machine, m->machines, i)
986 machine_add_to_gc_queue(machine);
987
988 return 0;
989 }
990
991 int manager_start_scope(
992 Manager *manager,
993 const char *scope,
994 pid_t pid,
995 const char *slice,
996 const char *description,
997 sd_bus_message *more_properties,
998 sd_bus_error *error,
999 char **job) {
1000
1001 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1002 int r;
1003
1004 assert(manager);
1005 assert(scope);
1006 assert(pid > 1);
1007
1008 r = sd_bus_message_new_method_call(
1009 manager->bus,
1010 &m,
1011 "org.freedesktop.systemd1",
1012 "/org/freedesktop/systemd1",
1013 "org.freedesktop.systemd1.Manager",
1014 "StartTransientUnit");
1015 if (r < 0)
1016 return r;
1017
1018 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
1019 if (r < 0)
1020 return r;
1021
1022 r = sd_bus_message_open_container(m, 'a', "(sv)");
1023 if (r < 0)
1024 return r;
1025
1026 if (!isempty(slice)) {
1027 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1028 if (r < 0)
1029 return r;
1030 }
1031
1032 if (!isempty(description)) {
1033 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1034 if (r < 0)
1035 return r;
1036 }
1037
1038 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1039 if (r < 0)
1040 return r;
1041
1042 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1043 if (r < 0)
1044 return r;
1045
1046 if (more_properties) {
1047 r = sd_bus_message_copy(m, more_properties, true);
1048 if (r < 0)
1049 return r;
1050 }
1051
1052 r = sd_bus_message_close_container(m);
1053 if (r < 0)
1054 return r;
1055
1056 r = sd_bus_message_append(m, "a(sa(sv))", 0);
1057 if (r < 0)
1058 return r;
1059
1060 r = sd_bus_call(manager->bus, m, 0, error, &reply);
1061 if (r < 0)
1062 return r;
1063
1064 if (job) {
1065 const char *j;
1066 char *copy;
1067
1068 r = sd_bus_message_read(reply, "o", &j);
1069 if (r < 0)
1070 return r;
1071
1072 copy = strdup(j);
1073 if (!copy)
1074 return -ENOMEM;
1075
1076 *job = copy;
1077 }
1078
1079 return 1;
1080 }
1081
1082 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
1083 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1084 int r;
1085
1086 assert(manager);
1087 assert(unit);
1088
1089 r = sd_bus_call_method(
1090 manager->bus,
1091 "org.freedesktop.systemd1",
1092 "/org/freedesktop/systemd1",
1093 "org.freedesktop.systemd1.Manager",
1094 "StopUnit",
1095 error,
1096 &reply,
1097 "ss", unit, "fail");
1098 if (r < 0) {
1099 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1100 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
1101
1102 if (job)
1103 *job = NULL;
1104
1105 sd_bus_error_free(error);
1106 return 0;
1107 }
1108
1109 return r;
1110 }
1111
1112 if (job) {
1113 const char *j;
1114 char *copy;
1115
1116 r = sd_bus_message_read(reply, "o", &j);
1117 if (r < 0)
1118 return r;
1119
1120 copy = strdup(j);
1121 if (!copy)
1122 return -ENOMEM;
1123
1124 *job = copy;
1125 }
1126
1127 return 1;
1128 }
1129
1130 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1131 assert(manager);
1132 assert(unit);
1133
1134 return sd_bus_call_method(
1135 manager->bus,
1136 "org.freedesktop.systemd1",
1137 "/org/freedesktop/systemd1",
1138 "org.freedesktop.systemd1.Manager",
1139 "KillUnit",
1140 error,
1141 NULL,
1142 "ssi", unit, "all", signo);
1143 }
1144
1145 int manager_unit_is_active(Manager *manager, const char *unit) {
1146 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1147 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1148 _cleanup_free_ char *path = NULL;
1149 const char *state;
1150 int r;
1151
1152 assert(manager);
1153 assert(unit);
1154
1155 path = unit_dbus_path_from_name(unit);
1156 if (!path)
1157 return -ENOMEM;
1158
1159 r = sd_bus_get_property(
1160 manager->bus,
1161 "org.freedesktop.systemd1",
1162 path,
1163 "org.freedesktop.systemd1.Unit",
1164 "ActiveState",
1165 &error,
1166 &reply,
1167 "s");
1168 if (r < 0) {
1169 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1170 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1171 return true;
1172
1173 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1174 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1175 return false;
1176
1177 return r;
1178 }
1179
1180 r = sd_bus_message_read(reply, "s", &state);
1181 if (r < 0)
1182 return -EINVAL;
1183
1184 return !streq(state, "inactive") && !streq(state, "failed");
1185 }
1186
1187 int manager_job_is_active(Manager *manager, const char *path) {
1188 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1189 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1190 int r;
1191
1192 assert(manager);
1193 assert(path);
1194
1195 r = sd_bus_get_property(
1196 manager->bus,
1197 "org.freedesktop.systemd1",
1198 path,
1199 "org.freedesktop.systemd1.Job",
1200 "State",
1201 &error,
1202 &reply,
1203 "s");
1204 if (r < 0) {
1205 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1206 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1207 return true;
1208
1209 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1210 return false;
1211
1212 return r;
1213 }
1214
1215 /* We don't actually care about the state really. The fact
1216 * that we could read the job state is enough for us */
1217
1218 return true;
1219 }
1220
1221 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1222 _cleanup_free_ char *unit = NULL;
1223 Machine *mm;
1224 int r;
1225
1226 assert(m);
1227 assert(pid >= 1);
1228 assert(machine);
1229
1230 r = cg_pid_get_unit(pid, &unit);
1231 if (r < 0)
1232 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1233 else
1234 mm = hashmap_get(m->machine_units, unit);
1235
1236 if (!mm)
1237 return 0;
1238
1239 *machine = mm;
1240 return 1;
1241 }
1242
1243 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1244 Machine *machine;
1245
1246 assert(m);
1247 assert(name);
1248
1249 machine = hashmap_get(m->machines, name);
1250 if (!machine) {
1251 machine = machine_new(m, name);
1252 if (!machine)
1253 return -ENOMEM;
1254 }
1255
1256 if (_machine)
1257 *_machine = machine;
1258
1259 return 0;
1260 }