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