chiark / gitweb /
9296377c6f4ad40e1d9df2f8771afb7018c6c641
[elogind.git] / src / machine / machined-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <pwd.h>
26
27 #include "sd-id128.h"
28 #include "sd-messages.h"
29 #include "strv.h"
30 #include "mkdir.h"
31 #include "path-util.h"
32 #include "special.h"
33 #include "fileio-label.h"
34 #include "label.h"
35 #include "utf8.h"
36 #include "unit-name.h"
37 #include "bus-util.h"
38 #include "bus-common-errors.h"
39 #include "time-util.h"
40 #include "cgroup-util.h"
41 #include "machine-image.h"
42 #include "image-dbus.h"
43 #include "machined.h"
44 #include "machine-dbus.h"
45
46 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
47         _cleanup_free_ char *p = NULL;
48         Manager *m = userdata;
49         Machine *machine;
50         const char *name;
51         int r;
52
53         assert(bus);
54         assert(message);
55         assert(m);
56
57         r = sd_bus_message_read(message, "s", &name);
58         if (r < 0)
59                 return r;
60
61         machine = hashmap_get(m->machines, name);
62         if (!machine)
63                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
64
65         p = machine_bus_path(machine);
66         if (!p)
67                 return -ENOMEM;
68
69         return sd_bus_reply_method_return(message, "o", p);
70 }
71
72 static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
73         _cleanup_free_ char *p = NULL;
74         Manager *m = userdata;
75         const char *name;
76         int r;
77
78         assert(bus);
79         assert(message);
80         assert(m);
81
82         r = sd_bus_message_read(message, "s", &name);
83         if (r < 0)
84                 return r;
85
86         r = image_find(name, NULL);
87         if (r == 0)
88                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
89         if (r < 0)
90                 return r;
91
92         p = image_bus_path(name);
93         if (!p)
94                 return -ENOMEM;
95
96         return sd_bus_reply_method_return(message, "o", p);
97 }
98
99 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
100         _cleanup_free_ char *p = NULL;
101         Manager *m = userdata;
102         Machine *machine = NULL;
103         pid_t pid;
104         int r;
105
106         assert(bus);
107         assert(message);
108         assert(m);
109
110         assert_cc(sizeof(pid_t) == sizeof(uint32_t));
111
112         r = sd_bus_message_read(message, "u", &pid);
113         if (r < 0)
114                 return r;
115
116         if (pid == 0) {
117                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
118
119                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
120                 if (r < 0)
121                         return r;
122
123                 r = sd_bus_creds_get_pid(creds, &pid);
124                 if (r < 0)
125                         return r;
126         }
127
128         r = manager_get_machine_by_pid(m, pid, &machine);
129         if (r < 0)
130                 return r;
131         if (!machine)
132                 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
133
134         p = machine_bus_path(machine);
135         if (!p)
136                 return -ENOMEM;
137
138         return sd_bus_reply_method_return(message, "o", p);
139 }
140
141 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
142         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
143         Manager *m = userdata;
144         Machine *machine;
145         Iterator i;
146         int r;
147
148         assert(bus);
149         assert(message);
150         assert(m);
151
152         r = sd_bus_message_new_method_return(message, &reply);
153         if (r < 0)
154                 return sd_bus_error_set_errno(error, r);
155
156         r = sd_bus_message_open_container(reply, 'a', "(ssso)");
157         if (r < 0)
158                 return sd_bus_error_set_errno(error, r);
159
160         HASHMAP_FOREACH(machine, m->machines, i) {
161                 _cleanup_free_ char *p = NULL;
162
163                 p = machine_bus_path(machine);
164                 if (!p)
165                         return -ENOMEM;
166
167                 r = sd_bus_message_append(reply, "(ssso)",
168                                           machine->name,
169                                           strempty(machine_class_to_string(machine->class)),
170                                           machine->service,
171                                           p);
172                 if (r < 0)
173                         return sd_bus_error_set_errno(error, r);
174         }
175
176         r = sd_bus_message_close_container(reply);
177         if (r < 0)
178                 return sd_bus_error_set_errno(error, r);
179
180         return sd_bus_send(bus, reply, NULL);
181 }
182
183 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
184         const char *name, *service, *class, *root_directory;
185         const int32_t *netif = NULL;
186         MachineClass c;
187         uint32_t leader;
188         sd_id128_t id;
189         const void *v;
190         Machine *m;
191         size_t n, n_netif = 0;
192         int r;
193
194         assert(manager);
195         assert(message);
196         assert(_m);
197
198         r = sd_bus_message_read(message, "s", &name);
199         if (r < 0)
200                 return r;
201         if (!machine_name_is_valid(name))
202                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
203
204         r = sd_bus_message_read_array(message, 'y', &v, &n);
205         if (r < 0)
206                 return r;
207         if (n == 0)
208                 id = SD_ID128_NULL;
209         else if (n == 16)
210                 memcpy(&id, v, n);
211         else
212                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
213
214         r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
215         if (r < 0)
216                 return r;
217
218         if (read_network) {
219                 size_t i;
220
221                 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
222                 if (r < 0)
223                         return r;
224
225                 n_netif /= sizeof(int32_t);
226
227                 for (i = 0; i < n_netif; i++) {
228                         if (netif[i] <= 0)
229                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
230                 }
231         }
232
233         if (isempty(class))
234                 c = _MACHINE_CLASS_INVALID;
235         else {
236                 c = machine_class_from_string(class);
237                 if (c < 0)
238                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
239         }
240
241         if (leader == 1)
242                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
243
244         if (!isempty(root_directory) && !path_is_absolute(root_directory))
245                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
246
247         if (leader == 0) {
248                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
249
250                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
251                 if (r < 0)
252                         return r;
253
254                 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
255
256                 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
257                 if (r < 0)
258                         return r;
259         }
260
261         if (hashmap_get(manager->machines, name))
262                 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
263
264         r = manager_add_machine(manager, name, &m);
265         if (r < 0)
266                 return r;
267
268         m->leader = leader;
269         m->class = c;
270         m->id = id;
271
272         if (!isempty(service)) {
273                 m->service = strdup(service);
274                 if (!m->service) {
275                         r = -ENOMEM;
276                         goto fail;
277                 }
278         }
279
280         if (!isempty(root_directory)) {
281                 m->root_directory = strdup(root_directory);
282                 if (!m->root_directory) {
283                         r = -ENOMEM;
284                         goto fail;
285                 }
286         }
287
288         if (n_netif > 0) {
289                 assert_cc(sizeof(int32_t) == sizeof(int));
290                 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
291                 if (!m->netif) {
292                         r = -ENOMEM;
293                         goto fail;
294                 }
295
296                 m->n_netif = n_netif;
297         }
298
299         *_m = m;
300
301         return 1;
302
303 fail:
304         machine_add_to_gc_queue(m);
305         return r;
306 }
307
308 static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
309         Manager *manager = userdata;
310         Machine *m = NULL;
311         int r;
312
313         r = method_create_or_register_machine(manager, message, read_network, &m, error);
314         if (r < 0)
315                 return r;
316
317         r = sd_bus_message_enter_container(message, 'a', "(sv)");
318         if (r < 0)
319                 goto fail;
320
321         r = machine_start(m, message, error);
322         if (r < 0)
323                 goto fail;
324
325         m->create_message = sd_bus_message_ref(message);
326         return 1;
327
328 fail:
329         machine_add_to_gc_queue(m);
330         return r;
331 }
332
333 static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
334         return method_create_machine_internal(bus, message, true, userdata, error);
335 }
336
337 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
338         return method_create_machine_internal(bus, message, false, userdata, error);
339 }
340
341 static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
342         Manager *manager = userdata;
343         _cleanup_free_ char *p = NULL;
344         Machine *m = NULL;
345         int r;
346
347         r = method_create_or_register_machine(manager, message, read_network, &m, error);
348         if (r < 0)
349                 return r;
350
351         r = cg_pid_get_unit(m->leader, &m->unit);
352         if (r < 0) {
353                 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
354                 goto fail;
355         }
356
357         m->registered = true;
358
359         r = machine_start(m, NULL, error);
360         if (r < 0)
361                 goto fail;
362
363         p = machine_bus_path(m);
364         if (!p) {
365                 r = -ENOMEM;
366                 goto fail;
367         }
368
369         return sd_bus_reply_method_return(message, "o", p);
370
371 fail:
372         machine_add_to_gc_queue(m);
373         return r;
374 }
375
376 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
377         return method_register_machine_internal(bus, message, true, userdata, error);
378 }
379
380 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
381         return method_register_machine_internal(bus, message, false, userdata, error);
382 }
383
384 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
385         Manager *m = userdata;
386         Machine *machine;
387         const char *name;
388         int r;
389
390         assert(bus);
391         assert(message);
392         assert(m);
393
394         r = sd_bus_message_read(message, "s", &name);
395         if (r < 0)
396                 return sd_bus_error_set_errno(error, r);
397
398         machine = hashmap_get(m->machines, name);
399         if (!machine)
400                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
401
402         return bus_machine_method_terminate(bus, message, machine, error);
403 }
404
405 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
406         Manager *m = userdata;
407         Machine *machine;
408         const char *name;
409         int r;
410
411         assert(bus);
412         assert(message);
413         assert(m);
414
415         r = sd_bus_message_read(message, "s", &name);
416         if (r < 0)
417                 return sd_bus_error_set_errno(error, r);
418
419         machine = hashmap_get(m->machines, name);
420         if (!machine)
421                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
422
423         return bus_machine_method_kill(bus, message, machine, error);
424 }
425
426 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
427         Manager *m = userdata;
428         Machine *machine;
429         const char *name;
430         int r;
431
432         assert(bus);
433         assert(message);
434         assert(m);
435
436         r = sd_bus_message_read(message, "s", &name);
437         if (r < 0)
438                 return sd_bus_error_set_errno(error, r);
439
440         machine = hashmap_get(m->machines, name);
441         if (!machine)
442                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
443
444         return bus_machine_method_get_addresses(bus, message, machine, error);
445 }
446
447 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
448         Manager *m = userdata;
449         Machine *machine;
450         const char *name;
451         int r;
452
453         assert(bus);
454         assert(message);
455         assert(m);
456
457         r = sd_bus_message_read(message, "s", &name);
458         if (r < 0)
459                 return sd_bus_error_set_errno(error, r);
460
461         machine = hashmap_get(m->machines, name);
462         if (!machine)
463                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
464
465         return bus_machine_method_get_os_release(bus, message, machine, error);
466 }
467
468 static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
469         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
470         _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
471         Manager *m = userdata;
472         Image *image;
473         Iterator i;
474         int r;
475
476         assert(bus);
477         assert(message);
478         assert(m);
479
480         images = hashmap_new(&string_hash_ops);
481         if (!images)
482                 return -ENOMEM;
483
484         r = image_discover(images);
485         if (r < 0)
486                 return r;
487
488         r = sd_bus_message_new_method_return(message, &reply);
489         if (r < 0)
490                 return r;
491
492         r = sd_bus_message_open_container(reply, 'a', "(ssbtto)");
493         if (r < 0)
494                 return r;
495
496         HASHMAP_FOREACH(image, images, i) {
497                 _cleanup_free_ char *p = NULL;
498
499                 p = image_bus_path(image->name);
500                 if (!p)
501                         return -ENOMEM;
502
503                 r = sd_bus_message_append(reply, "(ssbtto)",
504                                           image->name,
505                                           image_type_to_string(image->type),
506                                           image->read_only,
507                                           image->crtime,
508                                           image->mtime,
509                                           p);
510                 if (r < 0)
511                         return r;
512         }
513
514         r = sd_bus_message_close_container(reply);
515         if (r < 0)
516                 return r;
517
518         return sd_bus_send(bus, reply, NULL);
519 }
520
521 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
522         Manager *m = userdata;
523         Machine *machine;
524         const char *name;
525         int r;
526
527         assert(bus);
528         assert(message);
529         assert(m);
530
531         r = sd_bus_message_read(message, "s", &name);
532         if (r < 0)
533                 return sd_bus_error_set_errno(error, r);
534
535         machine = hashmap_get(m->machines, name);
536         if (!machine)
537                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
538
539         return bus_machine_method_open_pty(bus, message, machine, error);
540 }
541
542 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
543         Manager *m = userdata;
544         Machine *machine;
545         const char *name;
546         int r;
547
548         assert(bus);
549         assert(message);
550         assert(m);
551
552         r = sd_bus_message_read(message, "s", &name);
553         if (r < 0)
554                 return r;
555
556         machine = hashmap_get(m->machines, name);
557         if (!machine)
558                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
559
560         return bus_machine_method_open_login(bus, message, machine, error);
561 }
562
563 static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
564         _cleanup_(image_unrefp) Image* i = NULL;
565         const char *name;
566         int r;
567
568         assert(bus);
569         assert(message);
570
571         r = sd_bus_message_read(message, "s", &name);
572         if (r < 0)
573                 return r;
574
575         if (!image_name_is_valid(name))
576                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
577
578         r = image_find(name, &i);
579         if (r < 0)
580                 return r;
581         if (r == 0)
582                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
583
584         r = image_remove(i);
585         if (r < 0)
586                 return r;
587
588         return sd_bus_reply_method_return(message, NULL);
589 }
590
591 const sd_bus_vtable manager_vtable[] = {
592         SD_BUS_VTABLE_START(0),
593         SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
594         SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
595         SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
596         SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
597         SD_BUS_METHOD("ListImages", NULL, "a(ssbtto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
598         SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
599         SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
600         SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
601         SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
602         SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
603         SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
604         SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
605         SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
606         SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
607         SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
608         SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
609         SD_BUS_SIGNAL("MachineNew", "so", 0),
610         SD_BUS_SIGNAL("MachineRemoved", "so", 0),
611         SD_BUS_VTABLE_END
612 };
613
614 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
615         const char *path, *result, *unit;
616         Manager *m = userdata;
617         Machine *machine;
618         uint32_t id;
619         int r;
620
621         assert(bus);
622         assert(message);
623         assert(m);
624
625         r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
626         if (r < 0) {
627                 bus_log_parse_error(r);
628                 return r;
629         }
630
631         machine = hashmap_get(m->machine_units, unit);
632         if (!machine)
633                 return 0;
634
635         if (streq_ptr(path, machine->scope_job)) {
636                 free(machine->scope_job);
637                 machine->scope_job = NULL;
638
639                 if (machine->started) {
640                         if (streq(result, "done"))
641                                 machine_send_create_reply(machine, NULL);
642                         else {
643                                 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
644
645                                 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
646
647                                 machine_send_create_reply(machine, &e);
648                         }
649                 } else
650                         machine_save(machine);
651         }
652
653         machine_add_to_gc_queue(machine);
654         return 0;
655 }
656
657 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
658         _cleanup_free_ char *unit = NULL;
659         Manager *m = userdata;
660         Machine *machine;
661         const char *path;
662         int r;
663
664         assert(bus);
665         assert(message);
666         assert(m);
667
668         path = sd_bus_message_get_path(message);
669         if (!path)
670                 return 0;
671
672         r = unit_name_from_dbus_path(path, &unit);
673         if (r < 0)
674                 return r;
675
676         machine = hashmap_get(m->machine_units, unit);
677         if (machine)
678                 machine_add_to_gc_queue(machine);
679
680         return 0;
681 }
682
683 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
684         const char *path, *unit;
685         Manager *m = userdata;
686         Machine *machine;
687         int r;
688
689         assert(bus);
690         assert(message);
691         assert(m);
692
693         r = sd_bus_message_read(message, "so", &unit, &path);
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                 machine_add_to_gc_queue(machine);
702
703         return 0;
704 }
705
706 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
707         Manager *m = userdata;
708         Machine *machine;
709         Iterator i;
710         int b, r;
711
712         assert(bus);
713
714         r = sd_bus_message_read(message, "b", &b);
715         if (r < 0) {
716                 bus_log_parse_error(r);
717                 return r;
718         }
719         if (b)
720                 return 0;
721
722         /* systemd finished reloading, let's recheck all our machines */
723         log_debug("System manager has been reloaded, rechecking machines...");
724
725         HASHMAP_FOREACH(machine, m->machines, i)
726                 machine_add_to_gc_queue(machine);
727
728         return 0;
729 }
730
731 int manager_start_scope(
732                 Manager *manager,
733                 const char *scope,
734                 pid_t pid,
735                 const char *slice,
736                 const char *description,
737                 sd_bus_message *more_properties,
738                 sd_bus_error *error,
739                 char **job) {
740
741         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
742         int r;
743
744         assert(manager);
745         assert(scope);
746         assert(pid > 1);
747
748         r = sd_bus_message_new_method_call(
749                         manager->bus,
750                         &m,
751                         "org.freedesktop.systemd1",
752                         "/org/freedesktop/systemd1",
753                         "org.freedesktop.systemd1.Manager",
754                         "StartTransientUnit");
755         if (r < 0)
756                 return r;
757
758         r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
759         if (r < 0)
760                 return r;
761
762         r = sd_bus_message_open_container(m, 'a', "(sv)");
763         if (r < 0)
764                 return r;
765
766         if (!isempty(slice)) {
767                 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
768                 if (r < 0)
769                         return r;
770         }
771
772         if (!isempty(description)) {
773                 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
774                 if (r < 0)
775                         return r;
776         }
777
778         r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
779         if (r < 0)
780                 return r;
781
782         r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
783         if (r < 0)
784                 return r;
785
786         if (more_properties) {
787                 r = sd_bus_message_copy(m, more_properties, true);
788                 if (r < 0)
789                         return r;
790         }
791
792         r = sd_bus_message_close_container(m);
793         if (r < 0)
794                 return r;
795
796         r = sd_bus_message_append(m, "a(sa(sv))", 0);
797         if (r < 0)
798                 return r;
799
800         r = sd_bus_call(manager->bus, m, 0, error, &reply);
801         if (r < 0)
802                 return r;
803
804         if (job) {
805                 const char *j;
806                 char *copy;
807
808                 r = sd_bus_message_read(reply, "o", &j);
809                 if (r < 0)
810                         return r;
811
812                 copy = strdup(j);
813                 if (!copy)
814                         return -ENOMEM;
815
816                 *job = copy;
817         }
818
819         return 1;
820 }
821
822 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
823         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
824         int r;
825
826         assert(manager);
827         assert(unit);
828
829         r = sd_bus_call_method(
830                         manager->bus,
831                         "org.freedesktop.systemd1",
832                         "/org/freedesktop/systemd1",
833                         "org.freedesktop.systemd1.Manager",
834                         "StopUnit",
835                         error,
836                         &reply,
837                         "ss", unit, "fail");
838         if (r < 0) {
839                 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
840                     sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
841
842                         if (job)
843                                 *job = NULL;
844
845                         sd_bus_error_free(error);
846                         return 0;
847                 }
848
849                 return r;
850         }
851
852         if (job) {
853                 const char *j;
854                 char *copy;
855
856                 r = sd_bus_message_read(reply, "o", &j);
857                 if (r < 0)
858                         return r;
859
860                 copy = strdup(j);
861                 if (!copy)
862                         return -ENOMEM;
863
864                 *job = copy;
865         }
866
867         return 1;
868 }
869
870 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
871         assert(manager);
872         assert(unit);
873
874         return sd_bus_call_method(
875                         manager->bus,
876                         "org.freedesktop.systemd1",
877                         "/org/freedesktop/systemd1",
878                         "org.freedesktop.systemd1.Manager",
879                         "KillUnit",
880                         error,
881                         NULL,
882                         "ssi", unit, "all", signo);
883 }
884
885 int manager_unit_is_active(Manager *manager, const char *unit) {
886         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
887         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
888         _cleanup_free_ char *path = NULL;
889         const char *state;
890         int r;
891
892         assert(manager);
893         assert(unit);
894
895         path = unit_dbus_path_from_name(unit);
896         if (!path)
897                 return -ENOMEM;
898
899         r = sd_bus_get_property(
900                         manager->bus,
901                         "org.freedesktop.systemd1",
902                         path,
903                         "org.freedesktop.systemd1.Unit",
904                         "ActiveState",
905                         &error,
906                         &reply,
907                         "s");
908         if (r < 0) {
909                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
910                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
911                         return true;
912
913                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
914                     sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
915                         return false;
916
917                 return r;
918         }
919
920         r = sd_bus_message_read(reply, "s", &state);
921         if (r < 0)
922                 return -EINVAL;
923
924         return !streq(state, "inactive") && !streq(state, "failed");
925 }
926
927 int manager_job_is_active(Manager *manager, const char *path) {
928         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
929         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
930         int r;
931
932         assert(manager);
933         assert(path);
934
935         r = sd_bus_get_property(
936                         manager->bus,
937                         "org.freedesktop.systemd1",
938                         path,
939                         "org.freedesktop.systemd1.Job",
940                         "State",
941                         &error,
942                         &reply,
943                         "s");
944         if (r < 0) {
945                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
946                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
947                         return true;
948
949                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
950                         return false;
951
952                 return r;
953         }
954
955         /* We don't actually care about the state really. The fact
956          * that we could read the job state is enough for us */
957
958         return true;
959 }
960
961 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
962         _cleanup_free_ char *unit = NULL;
963         Machine *mm;
964         int r;
965
966         assert(m);
967         assert(pid >= 1);
968         assert(machine);
969
970         r = cg_pid_get_unit(pid, &unit);
971         if (r < 0)
972                 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
973         else
974                 mm = hashmap_get(m->machine_units, unit);
975
976         if (!mm)
977                 return 0;
978
979         *machine = mm;
980         return 1;
981 }
982
983 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
984         Machine *machine;
985
986         assert(m);
987         assert(name);
988
989         machine = hashmap_get(m->machines, name);
990         if (!machine) {
991                 machine = machine_new(m, name);
992                 if (!machine)
993                         return -ENOMEM;
994         }
995
996         if (_machine)
997                 *_machine = machine;
998
999         return 0;
1000 }