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