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