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