chiark / gitweb /
155146b938c0e42ae2f4ad2908b84bea274c55b7
[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_copy_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
584         Manager *m = userdata;
585         Machine *machine;
586         const char *name;
587         int r;
588
589         assert(bus);
590         assert(message);
591         assert(m);
592
593         r = sd_bus_message_read(message, "s", &name);
594         if (r < 0)
595                 return r;
596
597         machine = hashmap_get(m->machines, name);
598         if (!machine)
599                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
600
601         return bus_machine_method_copy(bus, message, machine, error);
602 }
603
604 static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
605         _cleanup_(image_unrefp) Image* i = NULL;
606         const char *name;
607         int r;
608
609         assert(bus);
610         assert(message);
611
612         r = sd_bus_message_read(message, "s", &name);
613         if (r < 0)
614                 return r;
615
616         if (!image_name_is_valid(name))
617                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
618
619         r = image_find(name, &i);
620         if (r < 0)
621                 return r;
622         if (r == 0)
623                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
624
625         return bus_image_method_remove(bus, message, i, error);
626 }
627
628 static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
629         _cleanup_(image_unrefp) Image* i = NULL;
630         const char *old_name;
631         int r;
632
633         assert(bus);
634         assert(message);
635
636         r = sd_bus_message_read(message, "s", &old_name);
637         if (r < 0)
638                 return r;
639
640         if (!image_name_is_valid(old_name))
641                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
642
643         r = image_find(old_name, &i);
644         if (r < 0)
645                 return r;
646         if (r == 0)
647                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
648
649         return bus_image_method_rename(bus, message, i, error);
650 }
651
652 static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
653         _cleanup_(image_unrefp) Image *i = NULL;
654         const char *old_name;
655         int r;
656
657         assert(bus);
658         r = sd_bus_message_read(message, "s", &old_name);
659         if (r < 0)
660                 return r;
661
662         if (!image_name_is_valid(old_name))
663                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
664
665         r = image_find(old_name, &i);
666         if (r < 0)
667                 return r;
668         if (r == 0)
669                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
670
671         return bus_image_method_clone(bus, message, i, error);
672 }
673
674 static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
675         _cleanup_(image_unrefp) Image *i = NULL;
676         const char *name;
677         int r;
678
679         assert(bus);
680         r = sd_bus_message_read(message, "s", &name);
681         if (r < 0)
682                 return r;
683
684         if (!image_name_is_valid(name))
685                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
686
687         r = image_find(name, &i);
688         if (r < 0)
689                 return r;
690         if (r == 0)
691                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
692
693         return bus_image_method_mark_read_only(bus, message, i, error);
694 }
695
696 const sd_bus_vtable manager_vtable[] = {
697         SD_BUS_VTABLE_START(0),
698         SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
699         SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
700         SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
701         SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
702         SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
703         SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
704         SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
705         SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
706         SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
707         SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
708         SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
709         SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
710         SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
711         SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
712         SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
713         SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, 0),
714         SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, 0),
715         SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, 0),
716         SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
717         SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
718         SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
719         SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
720         SD_BUS_SIGNAL("MachineNew", "so", 0),
721         SD_BUS_SIGNAL("MachineRemoved", "so", 0),
722         SD_BUS_VTABLE_END
723 };
724
725 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
726         const char *path, *result, *unit;
727         Manager *m = userdata;
728         Machine *machine;
729         uint32_t id;
730         int r;
731
732         assert(bus);
733         assert(message);
734         assert(m);
735
736         r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
737         if (r < 0) {
738                 bus_log_parse_error(r);
739                 return r;
740         }
741
742         machine = hashmap_get(m->machine_units, unit);
743         if (!machine)
744                 return 0;
745
746         if (streq_ptr(path, machine->scope_job)) {
747                 free(machine->scope_job);
748                 machine->scope_job = NULL;
749
750                 if (machine->started) {
751                         if (streq(result, "done"))
752                                 machine_send_create_reply(machine, NULL);
753                         else {
754                                 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
755
756                                 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
757
758                                 machine_send_create_reply(machine, &e);
759                         }
760                 } else
761                         machine_save(machine);
762         }
763
764         machine_add_to_gc_queue(machine);
765         return 0;
766 }
767
768 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
769         _cleanup_free_ char *unit = NULL;
770         Manager *m = userdata;
771         Machine *machine;
772         const char *path;
773         int r;
774
775         assert(bus);
776         assert(message);
777         assert(m);
778
779         path = sd_bus_message_get_path(message);
780         if (!path)
781                 return 0;
782
783         r = unit_name_from_dbus_path(path, &unit);
784         if (r == -EINVAL) /* not for a unit */
785                 return 0;
786         if (r < 0)
787                 return r;
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_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
797         const char *path, *unit;
798         Manager *m = userdata;
799         Machine *machine;
800         int r;
801
802         assert(bus);
803         assert(message);
804         assert(m);
805
806         r = sd_bus_message_read(message, "so", &unit, &path);
807         if (r < 0) {
808                 bus_log_parse_error(r);
809                 return r;
810         }
811
812         machine = hashmap_get(m->machine_units, unit);
813         if (machine)
814                 machine_add_to_gc_queue(machine);
815
816         return 0;
817 }
818
819 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
820         Manager *m = userdata;
821         Machine *machine;
822         Iterator i;
823         int b, r;
824
825         assert(bus);
826
827         r = sd_bus_message_read(message, "b", &b);
828         if (r < 0) {
829                 bus_log_parse_error(r);
830                 return r;
831         }
832         if (b)
833                 return 0;
834
835         /* systemd finished reloading, let's recheck all our machines */
836         log_debug("System manager has been reloaded, rechecking machines...");
837
838         HASHMAP_FOREACH(machine, m->machines, i)
839                 machine_add_to_gc_queue(machine);
840
841         return 0;
842 }
843
844 int manager_start_scope(
845                 Manager *manager,
846                 const char *scope,
847                 pid_t pid,
848                 const char *slice,
849                 const char *description,
850                 sd_bus_message *more_properties,
851                 sd_bus_error *error,
852                 char **job) {
853
854         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
855         int r;
856
857         assert(manager);
858         assert(scope);
859         assert(pid > 1);
860
861         r = sd_bus_message_new_method_call(
862                         manager->bus,
863                         &m,
864                         "org.freedesktop.systemd1",
865                         "/org/freedesktop/systemd1",
866                         "org.freedesktop.systemd1.Manager",
867                         "StartTransientUnit");
868         if (r < 0)
869                 return r;
870
871         r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
872         if (r < 0)
873                 return r;
874
875         r = sd_bus_message_open_container(m, 'a', "(sv)");
876         if (r < 0)
877                 return r;
878
879         if (!isempty(slice)) {
880                 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
881                 if (r < 0)
882                         return r;
883         }
884
885         if (!isempty(description)) {
886                 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
887                 if (r < 0)
888                         return r;
889         }
890
891         r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
892         if (r < 0)
893                 return r;
894
895         r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
896         if (r < 0)
897                 return r;
898
899         if (more_properties) {
900                 r = sd_bus_message_copy(m, more_properties, true);
901                 if (r < 0)
902                         return r;
903         }
904
905         r = sd_bus_message_close_container(m);
906         if (r < 0)
907                 return r;
908
909         r = sd_bus_message_append(m, "a(sa(sv))", 0);
910         if (r < 0)
911                 return r;
912
913         r = sd_bus_call(manager->bus, m, 0, error, &reply);
914         if (r < 0)
915                 return r;
916
917         if (job) {
918                 const char *j;
919                 char *copy;
920
921                 r = sd_bus_message_read(reply, "o", &j);
922                 if (r < 0)
923                         return r;
924
925                 copy = strdup(j);
926                 if (!copy)
927                         return -ENOMEM;
928
929                 *job = copy;
930         }
931
932         return 1;
933 }
934
935 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
936         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
937         int r;
938
939         assert(manager);
940         assert(unit);
941
942         r = sd_bus_call_method(
943                         manager->bus,
944                         "org.freedesktop.systemd1",
945                         "/org/freedesktop/systemd1",
946                         "org.freedesktop.systemd1.Manager",
947                         "StopUnit",
948                         error,
949                         &reply,
950                         "ss", unit, "fail");
951         if (r < 0) {
952                 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
953                     sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
954
955                         if (job)
956                                 *job = NULL;
957
958                         sd_bus_error_free(error);
959                         return 0;
960                 }
961
962                 return r;
963         }
964
965         if (job) {
966                 const char *j;
967                 char *copy;
968
969                 r = sd_bus_message_read(reply, "o", &j);
970                 if (r < 0)
971                         return r;
972
973                 copy = strdup(j);
974                 if (!copy)
975                         return -ENOMEM;
976
977                 *job = copy;
978         }
979
980         return 1;
981 }
982
983 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
984         assert(manager);
985         assert(unit);
986
987         return sd_bus_call_method(
988                         manager->bus,
989                         "org.freedesktop.systemd1",
990                         "/org/freedesktop/systemd1",
991                         "org.freedesktop.systemd1.Manager",
992                         "KillUnit",
993                         error,
994                         NULL,
995                         "ssi", unit, "all", signo);
996 }
997
998 int manager_unit_is_active(Manager *manager, const char *unit) {
999         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1000         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1001         _cleanup_free_ char *path = NULL;
1002         const char *state;
1003         int r;
1004
1005         assert(manager);
1006         assert(unit);
1007
1008         path = unit_dbus_path_from_name(unit);
1009         if (!path)
1010                 return -ENOMEM;
1011
1012         r = sd_bus_get_property(
1013                         manager->bus,
1014                         "org.freedesktop.systemd1",
1015                         path,
1016                         "org.freedesktop.systemd1.Unit",
1017                         "ActiveState",
1018                         &error,
1019                         &reply,
1020                         "s");
1021         if (r < 0) {
1022                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1023                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1024                         return true;
1025
1026                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1027                     sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1028                         return false;
1029
1030                 return r;
1031         }
1032
1033         r = sd_bus_message_read(reply, "s", &state);
1034         if (r < 0)
1035                 return -EINVAL;
1036
1037         return !streq(state, "inactive") && !streq(state, "failed");
1038 }
1039
1040 int manager_job_is_active(Manager *manager, const char *path) {
1041         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1042         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1043         int r;
1044
1045         assert(manager);
1046         assert(path);
1047
1048         r = sd_bus_get_property(
1049                         manager->bus,
1050                         "org.freedesktop.systemd1",
1051                         path,
1052                         "org.freedesktop.systemd1.Job",
1053                         "State",
1054                         &error,
1055                         &reply,
1056                         "s");
1057         if (r < 0) {
1058                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1059                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1060                         return true;
1061
1062                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1063                         return false;
1064
1065                 return r;
1066         }
1067
1068         /* We don't actually care about the state really. The fact
1069          * that we could read the job state is enough for us */
1070
1071         return true;
1072 }
1073
1074 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1075         _cleanup_free_ char *unit = NULL;
1076         Machine *mm;
1077         int r;
1078
1079         assert(m);
1080         assert(pid >= 1);
1081         assert(machine);
1082
1083         r = cg_pid_get_unit(pid, &unit);
1084         if (r < 0)
1085                 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1086         else
1087                 mm = hashmap_get(m->machine_units, unit);
1088
1089         if (!mm)
1090                 return 0;
1091
1092         *machine = mm;
1093         return 1;
1094 }
1095
1096 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1097         Machine *machine;
1098
1099         assert(m);
1100         assert(name);
1101
1102         machine = hashmap_get(m->machines, name);
1103         if (!machine) {
1104                 machine = machine_new(m, name);
1105                 if (!machine)
1106                         return -ENOMEM;
1107         }
1108
1109         if (_machine)
1110                 *_machine = machine;
1111
1112         return 0;
1113 }