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