]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined-dbus.c
Revert "machined: don't force terminate registered machines"
[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 r = machine_start(m, NULL, error);
358 if (r < 0)
359 goto fail;
360
361 p = machine_bus_path(m);
362 if (!p) {
363 r = -ENOMEM;
364 goto fail;
365 }
366
367 return sd_bus_reply_method_return(message, "o", p);
368
369 fail:
370 machine_add_to_gc_queue(m);
371 return r;
372 }
373
374 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
375 return method_register_machine_internal(bus, message, true, userdata, error);
376 }
377
378 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
379 return method_register_machine_internal(bus, message, false, userdata, error);
380 }
381
382 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
383 Manager *m = userdata;
384 Machine *machine;
385 const char *name;
386 int r;
387
388 assert(bus);
389 assert(message);
390 assert(m);
391
392 r = sd_bus_message_read(message, "s", &name);
393 if (r < 0)
394 return sd_bus_error_set_errno(error, r);
395
396 machine = hashmap_get(m->machines, name);
397 if (!machine)
398 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
399
400 return bus_machine_method_terminate(bus, message, machine, error);
401 }
402
403 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
404 Manager *m = userdata;
405 Machine *machine;
406 const char *name;
407 int r;
408
409 assert(bus);
410 assert(message);
411 assert(m);
412
413 r = sd_bus_message_read(message, "s", &name);
414 if (r < 0)
415 return sd_bus_error_set_errno(error, r);
416
417 machine = hashmap_get(m->machines, name);
418 if (!machine)
419 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
420
421 return bus_machine_method_kill(bus, message, machine, error);
422 }
423
424 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
425 Manager *m = userdata;
426 Machine *machine;
427 const char *name;
428 int r;
429
430 assert(bus);
431 assert(message);
432 assert(m);
433
434 r = sd_bus_message_read(message, "s", &name);
435 if (r < 0)
436 return sd_bus_error_set_errno(error, r);
437
438 machine = hashmap_get(m->machines, name);
439 if (!machine)
440 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
441
442 return bus_machine_method_get_addresses(bus, message, machine, error);
443 }
444
445 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
446 Manager *m = userdata;
447 Machine *machine;
448 const char *name;
449 int r;
450
451 assert(bus);
452 assert(message);
453 assert(m);
454
455 r = sd_bus_message_read(message, "s", &name);
456 if (r < 0)
457 return sd_bus_error_set_errno(error, r);
458
459 machine = hashmap_get(m->machines, name);
460 if (!machine)
461 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
462
463 return bus_machine_method_get_os_release(bus, message, machine, error);
464 }
465
466 static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
467 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
468 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
469 Manager *m = userdata;
470 Image *image;
471 Iterator i;
472 int r;
473
474 assert(bus);
475 assert(message);
476 assert(m);
477
478 images = hashmap_new(&string_hash_ops);
479 if (!images)
480 return -ENOMEM;
481
482 r = image_discover(images);
483 if (r < 0)
484 return r;
485
486 r = sd_bus_message_new_method_return(message, &reply);
487 if (r < 0)
488 return r;
489
490 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
491 if (r < 0)
492 return r;
493
494 HASHMAP_FOREACH(image, images, i) {
495 _cleanup_free_ char *p = NULL;
496
497 p = image_bus_path(image->name);
498 if (!p)
499 return -ENOMEM;
500
501 r = sd_bus_message_append(reply, "(ssbttto)",
502 image->name,
503 image_type_to_string(image->type),
504 image->read_only,
505 image->crtime,
506 image->mtime,
507 image->size,
508 p);
509 if (r < 0)
510 return r;
511 }
512
513 r = sd_bus_message_close_container(reply);
514 if (r < 0)
515 return r;
516
517 return sd_bus_send(bus, reply, NULL);
518 }
519
520 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
521 Manager *m = userdata;
522 Machine *machine;
523 const char *name;
524 int r;
525
526 assert(bus);
527 assert(message);
528 assert(m);
529
530 r = sd_bus_message_read(message, "s", &name);
531 if (r < 0)
532 return sd_bus_error_set_errno(error, r);
533
534 machine = hashmap_get(m->machines, name);
535 if (!machine)
536 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
537
538 return bus_machine_method_open_pty(bus, message, machine, error);
539 }
540
541 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
542 Manager *m = userdata;
543 Machine *machine;
544 const char *name;
545 int r;
546
547 assert(bus);
548 assert(message);
549 assert(m);
550
551 r = sd_bus_message_read(message, "s", &name);
552 if (r < 0)
553 return r;
554
555 machine = hashmap_get(m->machines, name);
556 if (!machine)
557 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
558
559 return bus_machine_method_open_login(bus, message, machine, error);
560 }
561
562 static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
563 _cleanup_(image_unrefp) Image* i = NULL;
564 const char *name;
565 int r;
566
567 assert(bus);
568 assert(message);
569
570 r = sd_bus_message_read(message, "s", &name);
571 if (r < 0)
572 return r;
573
574 if (!image_name_is_valid(name))
575 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
576
577 r = image_find(name, &i);
578 if (r < 0)
579 return r;
580 if (r == 0)
581 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
582
583 return bus_image_method_remove(bus, message, i, error);
584 }
585
586 static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
587 _cleanup_(image_unrefp) Image* i = NULL;
588 const char *old_name;
589 int r;
590
591 assert(bus);
592 assert(message);
593
594 r = sd_bus_message_read(message, "s", &old_name);
595 if (r < 0)
596 return r;
597
598 if (!image_name_is_valid(old_name))
599 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
600
601 r = image_find(old_name, &i);
602 if (r < 0)
603 return r;
604 if (r == 0)
605 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
606
607 return bus_image_method_rename(bus, message, i, error);
608 }
609
610 static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
611 _cleanup_(image_unrefp) Image *i = NULL;
612 const char *old_name;
613 int r;
614
615 assert(bus);
616 r = sd_bus_message_read(message, "s", &old_name);
617 if (r < 0)
618 return r;
619
620 if (!image_name_is_valid(old_name))
621 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
622
623 r = image_find(old_name, &i);
624 if (r < 0)
625 return r;
626 if (r == 0)
627 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
628
629 return bus_image_method_clone(bus, message, i, error);
630 }
631
632 static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
633 _cleanup_(image_unrefp) Image *i = NULL;
634 const char *name;
635 int r;
636
637 assert(bus);
638 r = sd_bus_message_read(message, "s", &name);
639 if (r < 0)
640 return r;
641
642 if (!image_name_is_valid(name))
643 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
644
645 r = image_find(name, &i);
646 if (r < 0)
647 return r;
648 if (r == 0)
649 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
650
651 return bus_image_method_mark_read_only(bus, message, i, error);
652 }
653
654 const sd_bus_vtable manager_vtable[] = {
655 SD_BUS_VTABLE_START(0),
656 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
657 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
658 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
659 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
660 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
661 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
662 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
663 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
664 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
665 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
666 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
667 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
668 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
669 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
670 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
671 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
672 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
673 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
674 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
675 SD_BUS_SIGNAL("MachineNew", "so", 0),
676 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
677 SD_BUS_VTABLE_END
678 };
679
680 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
681 const char *path, *result, *unit;
682 Manager *m = userdata;
683 Machine *machine;
684 uint32_t id;
685 int r;
686
687 assert(bus);
688 assert(message);
689 assert(m);
690
691 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
692 if (r < 0) {
693 bus_log_parse_error(r);
694 return r;
695 }
696
697 machine = hashmap_get(m->machine_units, unit);
698 if (!machine)
699 return 0;
700
701 if (streq_ptr(path, machine->scope_job)) {
702 free(machine->scope_job);
703 machine->scope_job = NULL;
704
705 if (machine->started) {
706 if (streq(result, "done"))
707 machine_send_create_reply(machine, NULL);
708 else {
709 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
710
711 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
712
713 machine_send_create_reply(machine, &e);
714 }
715 } else
716 machine_save(machine);
717 }
718
719 machine_add_to_gc_queue(machine);
720 return 0;
721 }
722
723 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
724 _cleanup_free_ char *unit = NULL;
725 Manager *m = userdata;
726 Machine *machine;
727 const char *path;
728 int r;
729
730 assert(bus);
731 assert(message);
732 assert(m);
733
734 path = sd_bus_message_get_path(message);
735 if (!path)
736 return 0;
737
738 r = unit_name_from_dbus_path(path, &unit);
739 if (r == -EINVAL) /* not for a unit */
740 return 0;
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 }