chiark / gitweb /
18b772d42d651a6335769b6bf8167e6a13e39c63
[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         m->registered = true;
358
359         r = machine_start(m, NULL, error);
360         if (r < 0)
361                 goto fail;
362
363         p = machine_bus_path(m);
364         if (!p) {
365                 r = -ENOMEM;
366                 goto fail;
367         }
368
369         return sd_bus_reply_method_return(message, "o", p);
370
371 fail:
372         machine_add_to_gc_queue(m);
373         return r;
374 }
375
376 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
377         return method_register_machine_internal(bus, message, true, userdata, error);
378 }
379
380 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
381         return method_register_machine_internal(bus, message, false, userdata, error);
382 }
383
384 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
385         Manager *m = userdata;
386         Machine *machine;
387         const char *name;
388         int r;
389
390         assert(bus);
391         assert(message);
392         assert(m);
393
394         r = sd_bus_message_read(message, "s", &name);
395         if (r < 0)
396                 return sd_bus_error_set_errno(error, r);
397
398         machine = hashmap_get(m->machines, name);
399         if (!machine)
400                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
401
402         return bus_machine_method_terminate(bus, message, machine, error);
403 }
404
405 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
406         Manager *m = userdata;
407         Machine *machine;
408         const char *name;
409         int r;
410
411         assert(bus);
412         assert(message);
413         assert(m);
414
415         r = sd_bus_message_read(message, "s", &name);
416         if (r < 0)
417                 return sd_bus_error_set_errno(error, r);
418
419         machine = hashmap_get(m->machines, name);
420         if (!machine)
421                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
422
423         return bus_machine_method_kill(bus, message, machine, error);
424 }
425
426 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
427         Manager *m = userdata;
428         Machine *machine;
429         const char *name;
430         int r;
431
432         assert(bus);
433         assert(message);
434         assert(m);
435
436         r = sd_bus_message_read(message, "s", &name);
437         if (r < 0)
438                 return sd_bus_error_set_errno(error, r);
439
440         machine = hashmap_get(m->machines, name);
441         if (!machine)
442                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
443
444         return bus_machine_method_get_addresses(bus, message, machine, error);
445 }
446
447 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
448         Manager *m = userdata;
449         Machine *machine;
450         const char *name;
451         int r;
452
453         assert(bus);
454         assert(message);
455         assert(m);
456
457         r = sd_bus_message_read(message, "s", &name);
458         if (r < 0)
459                 return sd_bus_error_set_errno(error, r);
460
461         machine = hashmap_get(m->machines, name);
462         if (!machine)
463                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
464
465         return bus_machine_method_get_os_release(bus, message, machine, error);
466 }
467
468 static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
469         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
470         _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
471         Manager *m = userdata;
472         Image *image;
473         Iterator i;
474         int r;
475
476         assert(bus);
477         assert(message);
478         assert(m);
479
480         images = hashmap_new(&string_hash_ops);
481         if (!images)
482                 return -ENOMEM;
483
484         r = image_discover(images);
485         if (r < 0)
486                 return r;
487
488         r = sd_bus_message_new_method_return(message, &reply);
489         if (r < 0)
490                 return r;
491
492         r = sd_bus_message_open_container(reply, 'a', "(ssbtto)");
493         if (r < 0)
494                 return r;
495
496         HASHMAP_FOREACH(image, images, i) {
497                 _cleanup_free_ char *p = NULL;
498
499                 p = image_bus_path(image->name);
500                 if (!p)
501                         return -ENOMEM;
502
503                 r = sd_bus_message_append(reply, "(ssbtto)",
504                                           image->name,
505                                           image_type_to_string(image->type),
506                                           image->read_only,
507                                           image->crtime,
508                                           image->mtime,
509                                           p);
510                 if (r < 0)
511                         return r;
512         }
513
514         r = sd_bus_message_close_container(reply);
515         if (r < 0)
516                 return r;
517
518         return sd_bus_send(bus, reply, NULL);
519 }
520
521 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
522         Manager *m = userdata;
523         Machine *machine;
524         const char *name;
525         int r;
526
527         assert(bus);
528         assert(message);
529         assert(m);
530
531         r = sd_bus_message_read(message, "s", &name);
532         if (r < 0)
533                 return sd_bus_error_set_errno(error, r);
534
535         machine = hashmap_get(m->machines, name);
536         if (!machine)
537                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
538
539         return bus_machine_method_open_pty(bus, message, machine, error);
540 }
541
542 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
543         Manager *m = userdata;
544         Machine *machine;
545         const char *name;
546         int r;
547
548         assert(bus);
549         assert(message);
550         assert(m);
551
552         r = sd_bus_message_read(message, "s", &name);
553         if (r < 0)
554                 return r;
555
556         machine = hashmap_get(m->machines, name);
557         if (!machine)
558                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
559
560         return bus_machine_method_open_login(bus, message, machine, error);
561 }
562
563 static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
564         _cleanup_(image_unrefp) Image* i = NULL;
565         const char *name;
566         int r;
567
568         assert(bus);
569         assert(message);
570
571         r = sd_bus_message_read(message, "s", &name);
572         if (r < 0)
573                 return r;
574
575         if (!image_name_is_valid(name))
576                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
577
578         r = image_find(name, &i);
579         if (r < 0)
580                 return r;
581         if (r == 0)
582                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
583
584         r = image_remove(i);
585         if (r < 0)
586                 return r;
587
588         return sd_bus_reply_method_return(message, NULL);
589 }
590
591 static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
592         _cleanup_(image_unrefp) Image* i = NULL;
593         const char *old_name, *new_name;
594         int r;
595
596         assert(bus);
597         assert(message);
598
599         r = sd_bus_message_read(message, "ss", &old_name, &new_name);
600         if (r < 0)
601                 return r;
602
603         if (!image_name_is_valid(old_name))
604                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
605         if (!image_name_is_valid(new_name))
606                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
607
608         r = image_find(old_name, &i);
609         if (r < 0)
610                 return r;
611         if (r == 0)
612                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
613
614         r = image_rename(i, new_name);
615         if (r < 0)
616                 return r;
617
618         return sd_bus_reply_method_return(message, NULL);
619 }
620
621 static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
622         _cleanup_(image_unrefp) Image *i = NULL;
623         const char *old_name, *new_name;
624         int read_only, r;
625
626         assert(bus);
627         r = sd_bus_message_read(message, "ssb", &old_name, &new_name, &read_only);
628         if (r < 0)
629                 return r;
630
631         if (!image_name_is_valid(old_name))
632                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
633         if (!image_name_is_valid(new_name))
634                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
635
636         r = image_find(old_name, &i);
637         if (r < 0)
638                 return r;
639         if (r == 0)
640                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
641
642         r = image_clone(i, new_name, read_only);
643         if (r < 0)
644                 return r;
645
646         return sd_bus_reply_method_return(message, NULL);
647 }
648
649 static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
650         _cleanup_(image_unrefp) Image *i = NULL;
651         const char *name;
652         int read_only, r;
653
654         assert(bus);
655         r = sd_bus_message_read(message, "sb", &name, &read_only);
656         if (r < 0)
657                 return r;
658
659         if (!image_name_is_valid(name))
660                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
661
662         r = image_find(name, &i);
663         if (r < 0)
664                 return r;
665         if (r == 0)
666                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
667
668         r = image_read_only(i, read_only);
669         if (r < 0)
670                 return r;
671
672         return sd_bus_reply_method_return(message, NULL);
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(ssbtto)", 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_SIGNAL("MachineNew", "so", 0),
697         SD_BUS_SIGNAL("MachineRemoved", "so", 0),
698         SD_BUS_VTABLE_END
699 };
700
701 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
702         const char *path, *result, *unit;
703         Manager *m = userdata;
704         Machine *machine;
705         uint32_t id;
706         int r;
707
708         assert(bus);
709         assert(message);
710         assert(m);
711
712         r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
713         if (r < 0) {
714                 bus_log_parse_error(r);
715                 return r;
716         }
717
718         machine = hashmap_get(m->machine_units, unit);
719         if (!machine)
720                 return 0;
721
722         if (streq_ptr(path, machine->scope_job)) {
723                 free(machine->scope_job);
724                 machine->scope_job = NULL;
725
726                 if (machine->started) {
727                         if (streq(result, "done"))
728                                 machine_send_create_reply(machine, NULL);
729                         else {
730                                 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
731
732                                 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
733
734                                 machine_send_create_reply(machine, &e);
735                         }
736                 } else
737                         machine_save(machine);
738         }
739
740         machine_add_to_gc_queue(machine);
741         return 0;
742 }
743
744 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
745         _cleanup_free_ char *unit = NULL;
746         Manager *m = userdata;
747         Machine *machine;
748         const char *path;
749         int r;
750
751         assert(bus);
752         assert(message);
753         assert(m);
754
755         path = sd_bus_message_get_path(message);
756         if (!path)
757                 return 0;
758
759         r = unit_name_from_dbus_path(path, &unit);
760         if (r < 0)
761                 return r;
762
763         machine = hashmap_get(m->machine_units, unit);
764         if (machine)
765                 machine_add_to_gc_queue(machine);
766
767         return 0;
768 }
769
770 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
771         const char *path, *unit;
772         Manager *m = userdata;
773         Machine *machine;
774         int r;
775
776         assert(bus);
777         assert(message);
778         assert(m);
779
780         r = sd_bus_message_read(message, "so", &unit, &path);
781         if (r < 0) {
782                 bus_log_parse_error(r);
783                 return r;
784         }
785
786         machine = hashmap_get(m->machine_units, unit);
787         if (machine)
788                 machine_add_to_gc_queue(machine);
789
790         return 0;
791 }
792
793 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
794         Manager *m = userdata;
795         Machine *machine;
796         Iterator i;
797         int b, r;
798
799         assert(bus);
800
801         r = sd_bus_message_read(message, "b", &b);
802         if (r < 0) {
803                 bus_log_parse_error(r);
804                 return r;
805         }
806         if (b)
807                 return 0;
808
809         /* systemd finished reloading, let's recheck all our machines */
810         log_debug("System manager has been reloaded, rechecking machines...");
811
812         HASHMAP_FOREACH(machine, m->machines, i)
813                 machine_add_to_gc_queue(machine);
814
815         return 0;
816 }
817
818 int manager_start_scope(
819                 Manager *manager,
820                 const char *scope,
821                 pid_t pid,
822                 const char *slice,
823                 const char *description,
824                 sd_bus_message *more_properties,
825                 sd_bus_error *error,
826                 char **job) {
827
828         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
829         int r;
830
831         assert(manager);
832         assert(scope);
833         assert(pid > 1);
834
835         r = sd_bus_message_new_method_call(
836                         manager->bus,
837                         &m,
838                         "org.freedesktop.systemd1",
839                         "/org/freedesktop/systemd1",
840                         "org.freedesktop.systemd1.Manager",
841                         "StartTransientUnit");
842         if (r < 0)
843                 return r;
844
845         r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
846         if (r < 0)
847                 return r;
848
849         r = sd_bus_message_open_container(m, 'a', "(sv)");
850         if (r < 0)
851                 return r;
852
853         if (!isempty(slice)) {
854                 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
855                 if (r < 0)
856                         return r;
857         }
858
859         if (!isempty(description)) {
860                 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
861                 if (r < 0)
862                         return r;
863         }
864
865         r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
866         if (r < 0)
867                 return r;
868
869         r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
870         if (r < 0)
871                 return r;
872
873         if (more_properties) {
874                 r = sd_bus_message_copy(m, more_properties, true);
875                 if (r < 0)
876                         return r;
877         }
878
879         r = sd_bus_message_close_container(m);
880         if (r < 0)
881                 return r;
882
883         r = sd_bus_message_append(m, "a(sa(sv))", 0);
884         if (r < 0)
885                 return r;
886
887         r = sd_bus_call(manager->bus, m, 0, error, &reply);
888         if (r < 0)
889                 return r;
890
891         if (job) {
892                 const char *j;
893                 char *copy;
894
895                 r = sd_bus_message_read(reply, "o", &j);
896                 if (r < 0)
897                         return r;
898
899                 copy = strdup(j);
900                 if (!copy)
901                         return -ENOMEM;
902
903                 *job = copy;
904         }
905
906         return 1;
907 }
908
909 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
910         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
911         int r;
912
913         assert(manager);
914         assert(unit);
915
916         r = sd_bus_call_method(
917                         manager->bus,
918                         "org.freedesktop.systemd1",
919                         "/org/freedesktop/systemd1",
920                         "org.freedesktop.systemd1.Manager",
921                         "StopUnit",
922                         error,
923                         &reply,
924                         "ss", unit, "fail");
925         if (r < 0) {
926                 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
927                     sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
928
929                         if (job)
930                                 *job = NULL;
931
932                         sd_bus_error_free(error);
933                         return 0;
934                 }
935
936                 return r;
937         }
938
939         if (job) {
940                 const char *j;
941                 char *copy;
942
943                 r = sd_bus_message_read(reply, "o", &j);
944                 if (r < 0)
945                         return r;
946
947                 copy = strdup(j);
948                 if (!copy)
949                         return -ENOMEM;
950
951                 *job = copy;
952         }
953
954         return 1;
955 }
956
957 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
958         assert(manager);
959         assert(unit);
960
961         return sd_bus_call_method(
962                         manager->bus,
963                         "org.freedesktop.systemd1",
964                         "/org/freedesktop/systemd1",
965                         "org.freedesktop.systemd1.Manager",
966                         "KillUnit",
967                         error,
968                         NULL,
969                         "ssi", unit, "all", signo);
970 }
971
972 int manager_unit_is_active(Manager *manager, const char *unit) {
973         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
974         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
975         _cleanup_free_ char *path = NULL;
976         const char *state;
977         int r;
978
979         assert(manager);
980         assert(unit);
981
982         path = unit_dbus_path_from_name(unit);
983         if (!path)
984                 return -ENOMEM;
985
986         r = sd_bus_get_property(
987                         manager->bus,
988                         "org.freedesktop.systemd1",
989                         path,
990                         "org.freedesktop.systemd1.Unit",
991                         "ActiveState",
992                         &error,
993                         &reply,
994                         "s");
995         if (r < 0) {
996                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
997                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
998                         return true;
999
1000                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1001                     sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1002                         return false;
1003
1004                 return r;
1005         }
1006
1007         r = sd_bus_message_read(reply, "s", &state);
1008         if (r < 0)
1009                 return -EINVAL;
1010
1011         return !streq(state, "inactive") && !streq(state, "failed");
1012 }
1013
1014 int manager_job_is_active(Manager *manager, const char *path) {
1015         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1016         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1017         int r;
1018
1019         assert(manager);
1020         assert(path);
1021
1022         r = sd_bus_get_property(
1023                         manager->bus,
1024                         "org.freedesktop.systemd1",
1025                         path,
1026                         "org.freedesktop.systemd1.Job",
1027                         "State",
1028                         &error,
1029                         &reply,
1030                         "s");
1031         if (r < 0) {
1032                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1033                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1034                         return true;
1035
1036                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1037                         return false;
1038
1039                 return r;
1040         }
1041
1042         /* We don't actually care about the state really. The fact
1043          * that we could read the job state is enough for us */
1044
1045         return true;
1046 }
1047
1048 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1049         _cleanup_free_ char *unit = NULL;
1050         Machine *mm;
1051         int r;
1052
1053         assert(m);
1054         assert(pid >= 1);
1055         assert(machine);
1056
1057         r = cg_pid_get_unit(pid, &unit);
1058         if (r < 0)
1059                 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1060         else
1061                 mm = hashmap_get(m->machine_units, unit);
1062
1063         if (!mm)
1064                 return 0;
1065
1066         *machine = mm;
1067         return 1;
1068 }
1069
1070 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1071         Machine *machine;
1072
1073         assert(m);
1074         assert(name);
1075
1076         machine = hashmap_get(m->machines, name);
1077         if (!machine) {
1078                 machine = machine_new(m, name);
1079                 if (!machine)
1080                         return -ENOMEM;
1081         }
1082
1083         if (_machine)
1084                 *_machine = machine;
1085
1086         return 0;
1087 }