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