]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined-dbus.c
machined: Move image discovery logic into src/shared, so that we can make use of...
[thirdparty/systemd.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 }