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