chiark / gitweb /
94dd128ec1d60c8520a472e4b13e5048595908e0
[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', "(ssbttto)");
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, "(ssbttto)",
504                                           image->name,
505                                           image_type_to_string(image->type),
506                                           image->read_only,
507                                           image->crtime,
508                                           image->mtime,
509                                           image->size,
510                                           p);
511                 if (r < 0)
512                         return r;
513         }
514
515         r = sd_bus_message_close_container(reply);
516         if (r < 0)
517                 return r;
518
519         return sd_bus_send(bus, reply, NULL);
520 }
521
522 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
523         Manager *m = userdata;
524         Machine *machine;
525         const char *name;
526         int r;
527
528         assert(bus);
529         assert(message);
530         assert(m);
531
532         r = sd_bus_message_read(message, "s", &name);
533         if (r < 0)
534                 return sd_bus_error_set_errno(error, r);
535
536         machine = hashmap_get(m->machines, name);
537         if (!machine)
538                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
539
540         return bus_machine_method_open_pty(bus, message, machine, error);
541 }
542
543 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
544         Manager *m = userdata;
545         Machine *machine;
546         const char *name;
547         int r;
548
549         assert(bus);
550         assert(message);
551         assert(m);
552
553         r = sd_bus_message_read(message, "s", &name);
554         if (r < 0)
555                 return r;
556
557         machine = hashmap_get(m->machines, name);
558         if (!machine)
559                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
560
561         return bus_machine_method_open_login(bus, message, machine, error);
562 }
563
564 static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
565         _cleanup_(image_unrefp) Image* i = NULL;
566         const char *name;
567         int r;
568
569         assert(bus);
570         assert(message);
571
572         r = sd_bus_message_read(message, "s", &name);
573         if (r < 0)
574                 return r;
575
576         if (!image_name_is_valid(name))
577                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
578
579         r = image_find(name, &i);
580         if (r < 0)
581                 return r;
582         if (r == 0)
583                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
584
585         return bus_image_method_remove(bus, message, i, error);
586 }
587
588 static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
589         _cleanup_(image_unrefp) Image* i = NULL;
590         const char *old_name;
591         int r;
592
593         assert(bus);
594         assert(message);
595
596         r = sd_bus_message_read(message, "s", &old_name);
597         if (r < 0)
598                 return r;
599
600         if (!image_name_is_valid(old_name))
601                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
602
603         r = image_find(old_name, &i);
604         if (r < 0)
605                 return r;
606         if (r == 0)
607                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
608
609         return bus_image_method_rename(bus, message, i, error);
610 }
611
612 static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
613         _cleanup_(image_unrefp) Image *i = NULL;
614         const char *old_name;
615         int r;
616
617         assert(bus);
618         r = sd_bus_message_read(message, "s", &old_name);
619         if (r < 0)
620                 return r;
621
622         if (!image_name_is_valid(old_name))
623                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
624
625         r = image_find(old_name, &i);
626         if (r < 0)
627                 return r;
628         if (r == 0)
629                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
630
631         return bus_image_method_clone(bus, message, i, error);
632 }
633
634 static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
635         _cleanup_(image_unrefp) Image *i = NULL;
636         const char *name;
637         int r;
638
639         assert(bus);
640         r = sd_bus_message_read(message, "s", &name);
641         if (r < 0)
642                 return r;
643
644         if (!image_name_is_valid(name))
645                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
646
647         r = image_find(name, &i);
648         if (r < 0)
649                 return r;
650         if (r == 0)
651                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
652
653         return bus_image_method_mark_read_only(bus, message, i, error);
654 }
655
656 const sd_bus_vtable manager_vtable[] = {
657         SD_BUS_VTABLE_START(0),
658         SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
659         SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
660         SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
661         SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
662         SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
663         SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
664         SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
665         SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
666         SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
667         SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
668         SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
669         SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
670         SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
671         SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
672         SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
673         SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
674         SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
675         SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
676         SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
677         SD_BUS_SIGNAL("MachineNew", "so", 0),
678         SD_BUS_SIGNAL("MachineRemoved", "so", 0),
679         SD_BUS_VTABLE_END
680 };
681
682 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
683         const char *path, *result, *unit;
684         Manager *m = userdata;
685         Machine *machine;
686         uint32_t id;
687         int r;
688
689         assert(bus);
690         assert(message);
691         assert(m);
692
693         r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
694         if (r < 0) {
695                 bus_log_parse_error(r);
696                 return r;
697         }
698
699         machine = hashmap_get(m->machine_units, unit);
700         if (!machine)
701                 return 0;
702
703         if (streq_ptr(path, machine->scope_job)) {
704                 free(machine->scope_job);
705                 machine->scope_job = NULL;
706
707                 if (machine->started) {
708                         if (streq(result, "done"))
709                                 machine_send_create_reply(machine, NULL);
710                         else {
711                                 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
712
713                                 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
714
715                                 machine_send_create_reply(machine, &e);
716                         }
717                 } else
718                         machine_save(machine);
719         }
720
721         machine_add_to_gc_queue(machine);
722         return 0;
723 }
724
725 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
726         _cleanup_free_ char *unit = NULL;
727         Manager *m = userdata;
728         Machine *machine;
729         const char *path;
730         int r;
731
732         assert(bus);
733         assert(message);
734         assert(m);
735
736         path = sd_bus_message_get_path(message);
737         if (!path)
738                 return 0;
739
740         r = unit_name_from_dbus_path(path, &unit);
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 }