chiark / gitweb /
0b57a62fd4e96793f864f161c915b901480c4ad4
[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 "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 }