chiark / gitweb /
b894e0b44448264402de15f8a8f0f417a36ebf6e
[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 == -EINVAL) /* not for a unit */
742                 return 0;
743         if (r < 0)
744                 return r;
745
746         machine = hashmap_get(m->machine_units, unit);
747         if (machine)
748                 machine_add_to_gc_queue(machine);
749
750         return 0;
751 }
752
753 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
754         const char *path, *unit;
755         Manager *m = userdata;
756         Machine *machine;
757         int r;
758
759         assert(bus);
760         assert(message);
761         assert(m);
762
763         r = sd_bus_message_read(message, "so", &unit, &path);
764         if (r < 0) {
765                 bus_log_parse_error(r);
766                 return r;
767         }
768
769         machine = hashmap_get(m->machine_units, unit);
770         if (machine)
771                 machine_add_to_gc_queue(machine);
772
773         return 0;
774 }
775
776 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
777         Manager *m = userdata;
778         Machine *machine;
779         Iterator i;
780         int b, r;
781
782         assert(bus);
783
784         r = sd_bus_message_read(message, "b", &b);
785         if (r < 0) {
786                 bus_log_parse_error(r);
787                 return r;
788         }
789         if (b)
790                 return 0;
791
792         /* systemd finished reloading, let's recheck all our machines */
793         log_debug("System manager has been reloaded, rechecking machines...");
794
795         HASHMAP_FOREACH(machine, m->machines, i)
796                 machine_add_to_gc_queue(machine);
797
798         return 0;
799 }
800
801 int manager_start_scope(
802                 Manager *manager,
803                 const char *scope,
804                 pid_t pid,
805                 const char *slice,
806                 const char *description,
807                 sd_bus_message *more_properties,
808                 sd_bus_error *error,
809                 char **job) {
810
811         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
812         int r;
813
814         assert(manager);
815         assert(scope);
816         assert(pid > 1);
817
818         r = sd_bus_message_new_method_call(
819                         manager->bus,
820                         &m,
821                         "org.freedesktop.systemd1",
822                         "/org/freedesktop/systemd1",
823                         "org.freedesktop.systemd1.Manager",
824                         "StartTransientUnit");
825         if (r < 0)
826                 return r;
827
828         r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
829         if (r < 0)
830                 return r;
831
832         r = sd_bus_message_open_container(m, 'a', "(sv)");
833         if (r < 0)
834                 return r;
835
836         if (!isempty(slice)) {
837                 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
838                 if (r < 0)
839                         return r;
840         }
841
842         if (!isempty(description)) {
843                 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
844                 if (r < 0)
845                         return r;
846         }
847
848         r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
849         if (r < 0)
850                 return r;
851
852         r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
853         if (r < 0)
854                 return r;
855
856         if (more_properties) {
857                 r = sd_bus_message_copy(m, more_properties, true);
858                 if (r < 0)
859                         return r;
860         }
861
862         r = sd_bus_message_close_container(m);
863         if (r < 0)
864                 return r;
865
866         r = sd_bus_message_append(m, "a(sa(sv))", 0);
867         if (r < 0)
868                 return r;
869
870         r = sd_bus_call(manager->bus, m, 0, error, &reply);
871         if (r < 0)
872                 return r;
873
874         if (job) {
875                 const char *j;
876                 char *copy;
877
878                 r = sd_bus_message_read(reply, "o", &j);
879                 if (r < 0)
880                         return r;
881
882                 copy = strdup(j);
883                 if (!copy)
884                         return -ENOMEM;
885
886                 *job = copy;
887         }
888
889         return 1;
890 }
891
892 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
893         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
894         int r;
895
896         assert(manager);
897         assert(unit);
898
899         r = sd_bus_call_method(
900                         manager->bus,
901                         "org.freedesktop.systemd1",
902                         "/org/freedesktop/systemd1",
903                         "org.freedesktop.systemd1.Manager",
904                         "StopUnit",
905                         error,
906                         &reply,
907                         "ss", unit, "fail");
908         if (r < 0) {
909                 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
910                     sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
911
912                         if (job)
913                                 *job = NULL;
914
915                         sd_bus_error_free(error);
916                         return 0;
917                 }
918
919                 return r;
920         }
921
922         if (job) {
923                 const char *j;
924                 char *copy;
925
926                 r = sd_bus_message_read(reply, "o", &j);
927                 if (r < 0)
928                         return r;
929
930                 copy = strdup(j);
931                 if (!copy)
932                         return -ENOMEM;
933
934                 *job = copy;
935         }
936
937         return 1;
938 }
939
940 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
941         assert(manager);
942         assert(unit);
943
944         return sd_bus_call_method(
945                         manager->bus,
946                         "org.freedesktop.systemd1",
947                         "/org/freedesktop/systemd1",
948                         "org.freedesktop.systemd1.Manager",
949                         "KillUnit",
950                         error,
951                         NULL,
952                         "ssi", unit, "all", signo);
953 }
954
955 int manager_unit_is_active(Manager *manager, const char *unit) {
956         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
957         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
958         _cleanup_free_ char *path = NULL;
959         const char *state;
960         int r;
961
962         assert(manager);
963         assert(unit);
964
965         path = unit_dbus_path_from_name(unit);
966         if (!path)
967                 return -ENOMEM;
968
969         r = sd_bus_get_property(
970                         manager->bus,
971                         "org.freedesktop.systemd1",
972                         path,
973                         "org.freedesktop.systemd1.Unit",
974                         "ActiveState",
975                         &error,
976                         &reply,
977                         "s");
978         if (r < 0) {
979                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
980                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
981                         return true;
982
983                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
984                     sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
985                         return false;
986
987                 return r;
988         }
989
990         r = sd_bus_message_read(reply, "s", &state);
991         if (r < 0)
992                 return -EINVAL;
993
994         return !streq(state, "inactive") && !streq(state, "failed");
995 }
996
997 int manager_job_is_active(Manager *manager, const char *path) {
998         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
999         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1000         int r;
1001
1002         assert(manager);
1003         assert(path);
1004
1005         r = sd_bus_get_property(
1006                         manager->bus,
1007                         "org.freedesktop.systemd1",
1008                         path,
1009                         "org.freedesktop.systemd1.Job",
1010                         "State",
1011                         &error,
1012                         &reply,
1013                         "s");
1014         if (r < 0) {
1015                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1016                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1017                         return true;
1018
1019                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1020                         return false;
1021
1022                 return r;
1023         }
1024
1025         /* We don't actually care about the state really. The fact
1026          * that we could read the job state is enough for us */
1027
1028         return true;
1029 }
1030
1031 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1032         _cleanup_free_ char *unit = NULL;
1033         Machine *mm;
1034         int r;
1035
1036         assert(m);
1037         assert(pid >= 1);
1038         assert(machine);
1039
1040         r = cg_pid_get_unit(pid, &unit);
1041         if (r < 0)
1042                 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1043         else
1044                 mm = hashmap_get(m->machine_units, unit);
1045
1046         if (!mm)
1047                 return 0;
1048
1049         *machine = mm;
1050         return 1;
1051 }
1052
1053 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1054         Machine *machine;
1055
1056         assert(m);
1057         assert(name);
1058
1059         machine = hashmap_get(m->machines, name);
1060         if (!machine) {
1061                 machine = machine_new(m, name);
1062                 if (!machine)
1063                         return -ENOMEM;
1064         }
1065
1066         if (_machine)
1067                 *_machine = machine;
1068
1069         return 0;
1070 }