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