chiark / gitweb /
fdb9d5fac872df0eb3c43bbd8c1c8f243b1ddcd7
[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_quota_limit("/var/lib/machines", limit);
803         if (r == -ENOTTY)
804                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
805         else if (r < 0)
806                 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
807
808         return sd_bus_reply_method_return(message, NULL);
809 }
810
811 static int method_set_image_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
812         _cleanup_(image_unrefp) Image *i = NULL;
813         const char *name;
814         int r;
815
816         assert(bus);
817         r = sd_bus_message_read(message, "s", &name);
818         if (r < 0)
819                 return r;
820
821         if (!image_name_is_valid(name))
822                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
823
824         r = image_find(name, &i);
825         if (r < 0)
826                 return r;
827         if (r == 0)
828                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
829
830         i->userdata = userdata;
831         return bus_image_method_set_limit(bus, message, i, error);
832 }
833
834 const sd_bus_vtable manager_vtable[] = {
835         SD_BUS_VTABLE_START(0),
836         SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
837         SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
838         SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
839         SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
840         SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
841         SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
842         SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
843         SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
844         SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
845         SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
846         SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
847         SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
848         SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
849         SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
850         SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
851         SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
852         SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
853         SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
854         SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
855         SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
856         SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
857         SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
858         SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
859         SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
860         SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
861         SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
862         SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
863         SD_BUS_SIGNAL("MachineNew", "so", 0),
864         SD_BUS_SIGNAL("MachineRemoved", "so", 0),
865         SD_BUS_VTABLE_END
866 };
867
868 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
869         const char *path, *result, *unit;
870         Manager *m = userdata;
871         Machine *machine;
872         uint32_t id;
873         int r;
874
875         assert(bus);
876         assert(message);
877         assert(m);
878
879         r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
880         if (r < 0) {
881                 bus_log_parse_error(r);
882                 return r;
883         }
884
885         machine = hashmap_get(m->machine_units, unit);
886         if (!machine)
887                 return 0;
888
889         if (streq_ptr(path, machine->scope_job)) {
890                 free(machine->scope_job);
891                 machine->scope_job = NULL;
892
893                 if (machine->started) {
894                         if (streq(result, "done"))
895                                 machine_send_create_reply(machine, NULL);
896                         else {
897                                 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
898
899                                 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
900
901                                 machine_send_create_reply(machine, &e);
902                         }
903                 } else
904                         machine_save(machine);
905         }
906
907         machine_add_to_gc_queue(machine);
908         return 0;
909 }
910
911 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
912         _cleanup_free_ char *unit = NULL;
913         Manager *m = userdata;
914         Machine *machine;
915         const char *path;
916         int r;
917
918         assert(bus);
919         assert(message);
920         assert(m);
921
922         path = sd_bus_message_get_path(message);
923         if (!path)
924                 return 0;
925
926         r = unit_name_from_dbus_path(path, &unit);
927         if (r == -EINVAL) /* not for a unit */
928                 return 0;
929         if (r < 0)
930                 return r;
931
932         machine = hashmap_get(m->machine_units, unit);
933         if (machine)
934                 machine_add_to_gc_queue(machine);
935
936         return 0;
937 }
938
939 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
940         const char *path, *unit;
941         Manager *m = userdata;
942         Machine *machine;
943         int r;
944
945         assert(bus);
946         assert(message);
947         assert(m);
948
949         r = sd_bus_message_read(message, "so", &unit, &path);
950         if (r < 0) {
951                 bus_log_parse_error(r);
952                 return r;
953         }
954
955         machine = hashmap_get(m->machine_units, unit);
956         if (machine)
957                 machine_add_to_gc_queue(machine);
958
959         return 0;
960 }
961
962 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
963         Manager *m = userdata;
964         Machine *machine;
965         Iterator i;
966         int b, r;
967
968         assert(bus);
969
970         r = sd_bus_message_read(message, "b", &b);
971         if (r < 0) {
972                 bus_log_parse_error(r);
973                 return r;
974         }
975         if (b)
976                 return 0;
977
978         /* systemd finished reloading, let's recheck all our machines */
979         log_debug("System manager has been reloaded, rechecking machines...");
980
981         HASHMAP_FOREACH(machine, m->machines, i)
982                 machine_add_to_gc_queue(machine);
983
984         return 0;
985 }
986
987 int manager_start_scope(
988                 Manager *manager,
989                 const char *scope,
990                 pid_t pid,
991                 const char *slice,
992                 const char *description,
993                 sd_bus_message *more_properties,
994                 sd_bus_error *error,
995                 char **job) {
996
997         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
998         int r;
999
1000         assert(manager);
1001         assert(scope);
1002         assert(pid > 1);
1003
1004         r = sd_bus_message_new_method_call(
1005                         manager->bus,
1006                         &m,
1007                         "org.freedesktop.systemd1",
1008                         "/org/freedesktop/systemd1",
1009                         "org.freedesktop.systemd1.Manager",
1010                         "StartTransientUnit");
1011         if (r < 0)
1012                 return r;
1013
1014         r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
1015         if (r < 0)
1016                 return r;
1017
1018         r = sd_bus_message_open_container(m, 'a', "(sv)");
1019         if (r < 0)
1020                 return r;
1021
1022         if (!isempty(slice)) {
1023                 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1024                 if (r < 0)
1025                         return r;
1026         }
1027
1028         if (!isempty(description)) {
1029                 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1030                 if (r < 0)
1031                         return r;
1032         }
1033
1034         r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1035         if (r < 0)
1036                 return r;
1037
1038         r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1039         if (r < 0)
1040                 return r;
1041
1042         if (more_properties) {
1043                 r = sd_bus_message_copy(m, more_properties, true);
1044                 if (r < 0)
1045                         return r;
1046         }
1047
1048         r = sd_bus_message_close_container(m);
1049         if (r < 0)
1050                 return r;
1051
1052         r = sd_bus_message_append(m, "a(sa(sv))", 0);
1053         if (r < 0)
1054                 return r;
1055
1056         r = sd_bus_call(manager->bus, m, 0, error, &reply);
1057         if (r < 0)
1058                 return r;
1059
1060         if (job) {
1061                 const char *j;
1062                 char *copy;
1063
1064                 r = sd_bus_message_read(reply, "o", &j);
1065                 if (r < 0)
1066                         return r;
1067
1068                 copy = strdup(j);
1069                 if (!copy)
1070                         return -ENOMEM;
1071
1072                 *job = copy;
1073         }
1074
1075         return 1;
1076 }
1077
1078 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
1079         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1080         int r;
1081
1082         assert(manager);
1083         assert(unit);
1084
1085         r = sd_bus_call_method(
1086                         manager->bus,
1087                         "org.freedesktop.systemd1",
1088                         "/org/freedesktop/systemd1",
1089                         "org.freedesktop.systemd1.Manager",
1090                         "StopUnit",
1091                         error,
1092                         &reply,
1093                         "ss", unit, "fail");
1094         if (r < 0) {
1095                 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1096                     sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
1097
1098                         if (job)
1099                                 *job = NULL;
1100
1101                         sd_bus_error_free(error);
1102                         return 0;
1103                 }
1104
1105                 return r;
1106         }
1107
1108         if (job) {
1109                 const char *j;
1110                 char *copy;
1111
1112                 r = sd_bus_message_read(reply, "o", &j);
1113                 if (r < 0)
1114                         return r;
1115
1116                 copy = strdup(j);
1117                 if (!copy)
1118                         return -ENOMEM;
1119
1120                 *job = copy;
1121         }
1122
1123         return 1;
1124 }
1125
1126 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1127         assert(manager);
1128         assert(unit);
1129
1130         return sd_bus_call_method(
1131                         manager->bus,
1132                         "org.freedesktop.systemd1",
1133                         "/org/freedesktop/systemd1",
1134                         "org.freedesktop.systemd1.Manager",
1135                         "KillUnit",
1136                         error,
1137                         NULL,
1138                         "ssi", unit, "all", signo);
1139 }
1140
1141 int manager_unit_is_active(Manager *manager, const char *unit) {
1142         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1143         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1144         _cleanup_free_ char *path = NULL;
1145         const char *state;
1146         int r;
1147
1148         assert(manager);
1149         assert(unit);
1150
1151         path = unit_dbus_path_from_name(unit);
1152         if (!path)
1153                 return -ENOMEM;
1154
1155         r = sd_bus_get_property(
1156                         manager->bus,
1157                         "org.freedesktop.systemd1",
1158                         path,
1159                         "org.freedesktop.systemd1.Unit",
1160                         "ActiveState",
1161                         &error,
1162                         &reply,
1163                         "s");
1164         if (r < 0) {
1165                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1166                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1167                         return true;
1168
1169                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1170                     sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1171                         return false;
1172
1173                 return r;
1174         }
1175
1176         r = sd_bus_message_read(reply, "s", &state);
1177         if (r < 0)
1178                 return -EINVAL;
1179
1180         return !streq(state, "inactive") && !streq(state, "failed");
1181 }
1182
1183 int manager_job_is_active(Manager *manager, const char *path) {
1184         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1185         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1186         int r;
1187
1188         assert(manager);
1189         assert(path);
1190
1191         r = sd_bus_get_property(
1192                         manager->bus,
1193                         "org.freedesktop.systemd1",
1194                         path,
1195                         "org.freedesktop.systemd1.Job",
1196                         "State",
1197                         &error,
1198                         &reply,
1199                         "s");
1200         if (r < 0) {
1201                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1202                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1203                         return true;
1204
1205                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1206                         return false;
1207
1208                 return r;
1209         }
1210
1211         /* We don't actually care about the state really. The fact
1212          * that we could read the job state is enough for us */
1213
1214         return true;
1215 }
1216
1217 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1218         _cleanup_free_ char *unit = NULL;
1219         Machine *mm;
1220         int r;
1221
1222         assert(m);
1223         assert(pid >= 1);
1224         assert(machine);
1225
1226         r = cg_pid_get_unit(pid, &unit);
1227         if (r < 0)
1228                 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1229         else
1230                 mm = hashmap_get(m->machine_units, unit);
1231
1232         if (!mm)
1233                 return 0;
1234
1235         *machine = mm;
1236         return 1;
1237 }
1238
1239 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1240         Machine *machine;
1241
1242         assert(m);
1243         assert(name);
1244
1245         machine = hashmap_get(m->machines, name);
1246         if (!machine) {
1247                 machine = machine_new(m, name);
1248                 if (!machine)
1249                         return -ENOMEM;
1250         }
1251
1252         if (_machine)
1253                 *_machine = machine;
1254
1255         return 0;
1256 }