]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined-dbus.c
machined: don't look for images on each property get, but cache the image object...
[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', "(ssbttto)");
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, "(ssbttto)",
504 image->name,
505 image_type_to_string(image->type),
506 image->read_only,
507 image->crtime,
508 image->mtime,
509 image->size,
510 p);
511 if (r < 0)
512 return r;
513 }
514
515 r = sd_bus_message_close_container(reply);
516 if (r < 0)
517 return r;
518
519 return sd_bus_send(bus, reply, NULL);
520 }
521
522 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
523 Manager *m = userdata;
524 Machine *machine;
525 const char *name;
526 int r;
527
528 assert(bus);
529 assert(message);
530 assert(m);
531
532 r = sd_bus_message_read(message, "s", &name);
533 if (r < 0)
534 return sd_bus_error_set_errno(error, r);
535
536 machine = hashmap_get(m->machines, name);
537 if (!machine)
538 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
539
540 return bus_machine_method_open_pty(bus, message, machine, error);
541 }
542
543 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
544 Manager *m = userdata;
545 Machine *machine;
546 const char *name;
547 int r;
548
549 assert(bus);
550 assert(message);
551 assert(m);
552
553 r = sd_bus_message_read(message, "s", &name);
554 if (r < 0)
555 return r;
556
557 machine = hashmap_get(m->machines, name);
558 if (!machine)
559 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
560
561 return bus_machine_method_open_login(bus, message, machine, error);
562 }
563
564 static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
565 _cleanup_(image_unrefp) Image* i = NULL;
566 const char *name;
567 int r;
568
569 assert(bus);
570 assert(message);
571
572 r = sd_bus_message_read(message, "s", &name);
573 if (r < 0)
574 return r;
575
576 if (!image_name_is_valid(name))
577 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
578
579 r = image_find(name, &i);
580 if (r < 0)
581 return r;
582 if (r == 0)
583 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
584
585 return bus_image_method_remove(bus, message, i, error);
586 }
587
588 static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
589 _cleanup_(image_unrefp) Image* i = NULL;
590 const char *old_name;
591 int r;
592
593 assert(bus);
594 assert(message);
595
596 r = sd_bus_message_read(message, "s", &old_name);
597 if (r < 0)
598 return r;
599
600 if (!image_name_is_valid(old_name))
601 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
602
603 r = image_find(old_name, &i);
604 if (r < 0)
605 return r;
606 if (r == 0)
607 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
608
609 return bus_image_method_rename(bus, message, i, error);
610 }
611
612 static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
613 _cleanup_(image_unrefp) Image *i = NULL;
614 const char *old_name;
615 int r;
616
617 assert(bus);
618 r = sd_bus_message_read(message, "s", &old_name);
619 if (r < 0)
620 return r;
621
622 if (!image_name_is_valid(old_name))
623 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
624
625 r = image_find(old_name, &i);
626 if (r < 0)
627 return r;
628 if (r == 0)
629 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
630
631 return bus_image_method_clone(bus, message, i, error);
632 }
633
634 static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
635 _cleanup_(image_unrefp) Image *i = NULL;
636 const char *name;
637 int r;
638
639 assert(bus);
640 r = sd_bus_message_read(message, "s", &name);
641 if (r < 0)
642 return r;
643
644 if (!image_name_is_valid(name))
645 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
646
647 r = image_find(name, &i);
648 if (r < 0)
649 return r;
650 if (r == 0)
651 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
652
653 return bus_image_method_mark_read_only(bus, message, i, error);
654 }
655
656 const sd_bus_vtable manager_vtable[] = {
657 SD_BUS_VTABLE_START(0),
658 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
659 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
660 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
661 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
662 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
663 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
664 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
665 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
666 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
667 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
668 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
669 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
670 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
671 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
672 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
673 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
674 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
675 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
676 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
677 SD_BUS_SIGNAL("MachineNew", "so", 0),
678 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
679 SD_BUS_VTABLE_END
680 };
681
682 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
683 const char *path, *result, *unit;
684 Manager *m = userdata;
685 Machine *machine;
686 uint32_t id;
687 int r;
688
689 assert(bus);
690 assert(message);
691 assert(m);
692
693 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
694 if (r < 0) {
695 bus_log_parse_error(r);
696 return r;
697 }
698
699 machine = hashmap_get(m->machine_units, unit);
700 if (!machine)
701 return 0;
702
703 if (streq_ptr(path, machine->scope_job)) {
704 free(machine->scope_job);
705 machine->scope_job = NULL;
706
707 if (machine->started) {
708 if (streq(result, "done"))
709 machine_send_create_reply(machine, NULL);
710 else {
711 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
712
713 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
714
715 machine_send_create_reply(machine, &e);
716 }
717 } else
718 machine_save(machine);
719 }
720
721 machine_add_to_gc_queue(machine);
722 return 0;
723 }
724
725 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
726 _cleanup_free_ char *unit = NULL;
727 Manager *m = userdata;
728 Machine *machine;
729 const char *path;
730 int r;
731
732 assert(bus);
733 assert(message);
734 assert(m);
735
736 path = sd_bus_message_get_path(message);
737 if (!path)
738 return 0;
739
740 r = unit_name_from_dbus_path(path, &unit);
741 if (r < 0)
742 return r;
743
744 machine = hashmap_get(m->machine_units, unit);
745 if (machine)
746 machine_add_to_gc_queue(machine);
747
748 return 0;
749 }
750
751 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
752 const char *path, *unit;
753 Manager *m = userdata;
754 Machine *machine;
755 int r;
756
757 assert(bus);
758 assert(message);
759 assert(m);
760
761 r = sd_bus_message_read(message, "so", &unit, &path);
762 if (r < 0) {
763 bus_log_parse_error(r);
764 return r;
765 }
766
767 machine = hashmap_get(m->machine_units, unit);
768 if (machine)
769 machine_add_to_gc_queue(machine);
770
771 return 0;
772 }
773
774 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
775 Manager *m = userdata;
776 Machine *machine;
777 Iterator i;
778 int b, r;
779
780 assert(bus);
781
782 r = sd_bus_message_read(message, "b", &b);
783 if (r < 0) {
784 bus_log_parse_error(r);
785 return r;
786 }
787 if (b)
788 return 0;
789
790 /* systemd finished reloading, let's recheck all our machines */
791 log_debug("System manager has been reloaded, rechecking machines...");
792
793 HASHMAP_FOREACH(machine, m->machines, i)
794 machine_add_to_gc_queue(machine);
795
796 return 0;
797 }
798
799 int manager_start_scope(
800 Manager *manager,
801 const char *scope,
802 pid_t pid,
803 const char *slice,
804 const char *description,
805 sd_bus_message *more_properties,
806 sd_bus_error *error,
807 char **job) {
808
809 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
810 int r;
811
812 assert(manager);
813 assert(scope);
814 assert(pid > 1);
815
816 r = sd_bus_message_new_method_call(
817 manager->bus,
818 &m,
819 "org.freedesktop.systemd1",
820 "/org/freedesktop/systemd1",
821 "org.freedesktop.systemd1.Manager",
822 "StartTransientUnit");
823 if (r < 0)
824 return r;
825
826 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
827 if (r < 0)
828 return r;
829
830 r = sd_bus_message_open_container(m, 'a', "(sv)");
831 if (r < 0)
832 return r;
833
834 if (!isempty(slice)) {
835 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
836 if (r < 0)
837 return r;
838 }
839
840 if (!isempty(description)) {
841 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
842 if (r < 0)
843 return r;
844 }
845
846 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
847 if (r < 0)
848 return r;
849
850 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
851 if (r < 0)
852 return r;
853
854 if (more_properties) {
855 r = sd_bus_message_copy(m, more_properties, true);
856 if (r < 0)
857 return r;
858 }
859
860 r = sd_bus_message_close_container(m);
861 if (r < 0)
862 return r;
863
864 r = sd_bus_message_append(m, "a(sa(sv))", 0);
865 if (r < 0)
866 return r;
867
868 r = sd_bus_call(manager->bus, m, 0, error, &reply);
869 if (r < 0)
870 return r;
871
872 if (job) {
873 const char *j;
874 char *copy;
875
876 r = sd_bus_message_read(reply, "o", &j);
877 if (r < 0)
878 return r;
879
880 copy = strdup(j);
881 if (!copy)
882 return -ENOMEM;
883
884 *job = copy;
885 }
886
887 return 1;
888 }
889
890 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
891 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
892 int r;
893
894 assert(manager);
895 assert(unit);
896
897 r = sd_bus_call_method(
898 manager->bus,
899 "org.freedesktop.systemd1",
900 "/org/freedesktop/systemd1",
901 "org.freedesktop.systemd1.Manager",
902 "StopUnit",
903 error,
904 &reply,
905 "ss", unit, "fail");
906 if (r < 0) {
907 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
908 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
909
910 if (job)
911 *job = NULL;
912
913 sd_bus_error_free(error);
914 return 0;
915 }
916
917 return r;
918 }
919
920 if (job) {
921 const char *j;
922 char *copy;
923
924 r = sd_bus_message_read(reply, "o", &j);
925 if (r < 0)
926 return r;
927
928 copy = strdup(j);
929 if (!copy)
930 return -ENOMEM;
931
932 *job = copy;
933 }
934
935 return 1;
936 }
937
938 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
939 assert(manager);
940 assert(unit);
941
942 return sd_bus_call_method(
943 manager->bus,
944 "org.freedesktop.systemd1",
945 "/org/freedesktop/systemd1",
946 "org.freedesktop.systemd1.Manager",
947 "KillUnit",
948 error,
949 NULL,
950 "ssi", unit, "all", signo);
951 }
952
953 int manager_unit_is_active(Manager *manager, const char *unit) {
954 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
955 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
956 _cleanup_free_ char *path = NULL;
957 const char *state;
958 int r;
959
960 assert(manager);
961 assert(unit);
962
963 path = unit_dbus_path_from_name(unit);
964 if (!path)
965 return -ENOMEM;
966
967 r = sd_bus_get_property(
968 manager->bus,
969 "org.freedesktop.systemd1",
970 path,
971 "org.freedesktop.systemd1.Unit",
972 "ActiveState",
973 &error,
974 &reply,
975 "s");
976 if (r < 0) {
977 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
978 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
979 return true;
980
981 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
982 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
983 return false;
984
985 return r;
986 }
987
988 r = sd_bus_message_read(reply, "s", &state);
989 if (r < 0)
990 return -EINVAL;
991
992 return !streq(state, "inactive") && !streq(state, "failed");
993 }
994
995 int manager_job_is_active(Manager *manager, const char *path) {
996 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
997 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
998 int r;
999
1000 assert(manager);
1001 assert(path);
1002
1003 r = sd_bus_get_property(
1004 manager->bus,
1005 "org.freedesktop.systemd1",
1006 path,
1007 "org.freedesktop.systemd1.Job",
1008 "State",
1009 &error,
1010 &reply,
1011 "s");
1012 if (r < 0) {
1013 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1014 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1015 return true;
1016
1017 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1018 return false;
1019
1020 return r;
1021 }
1022
1023 /* We don't actually care about the state really. The fact
1024 * that we could read the job state is enough for us */
1025
1026 return true;
1027 }
1028
1029 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1030 _cleanup_free_ char *unit = NULL;
1031 Machine *mm;
1032 int r;
1033
1034 assert(m);
1035 assert(pid >= 1);
1036 assert(machine);
1037
1038 r = cg_pid_get_unit(pid, &unit);
1039 if (r < 0)
1040 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1041 else
1042 mm = hashmap_get(m->machine_units, unit);
1043
1044 if (!mm)
1045 return 0;
1046
1047 *machine = mm;
1048 return 1;
1049 }
1050
1051 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1052 Machine *machine;
1053
1054 assert(m);
1055 assert(name);
1056
1057 machine = hashmap_get(m->machines, name);
1058 if (!machine) {
1059 machine = machine_new(m, name);
1060 if (!machine)
1061 return -ENOMEM;
1062 }
1063
1064 if (_machine)
1065 *_machine = machine;
1066
1067 return 0;
1068 }