]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
update TODO
[thirdparty/systemd.git] / src / machine / machined-dbus.c
CommitLineData
1ee306e1
LP
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
c3350683
LP
27#include "sd-id128.h"
28#include "sd-messages.h"
1ee306e1
LP
29#include "strv.h"
30#include "mkdir.h"
31#include "path-util.h"
32#include "special.h"
1ee306e1
LP
33#include "fileio-label.h"
34#include "label.h"
35#include "utf8.h"
36#include "unit-name.h"
c3350683 37#include "bus-util.h"
96aad8d1 38#include "bus-common-errors.h"
c3350683 39#include "time-util.h"
23c80348 40#include "cgroup-util.h"
003dffde
LP
41#include "machine-image.h"
42#include "image-dbus.h"
c3350683 43#include "machined.h"
003dffde 44#include "machine-dbus.h"
1ee306e1 45
ebcf1f97 46static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
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)
ebcf1f97 59 return r;
c3350683
LP
60
61 machine = hashmap_get(m->machines, name);
62 if (!machine)
ebcf1f97 63 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
c3350683
LP
64
65 p = machine_bus_path(machine);
66 if (!p)
ebcf1f97 67 return -ENOMEM;
c3350683 68
df2d202e 69 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
70}
71
c2ce6a3d
LP
72static 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
ebcf1f97 99static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
100 _cleanup_free_ char *p = NULL;
101 Manager *m = userdata;
102 Machine *machine = NULL;
4e724d9c 103 pid_t pid;
c3350683
LP
104 int r;
105
106 assert(bus);
107 assert(message);
108 assert(m);
109
4e724d9c
LP
110 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
111
c3350683
LP
112 r = sd_bus_message_read(message, "u", &pid);
113 if (r < 0)
ebcf1f97 114 return r;
c3350683 115
4e724d9c 116 if (pid == 0) {
5b12334d
LP
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);
4e724d9c 124 if (r < 0)
ebcf1f97 125 return r;
4e724d9c
LP
126 }
127
c3350683
LP
128 r = manager_get_machine_by_pid(m, pid, &machine);
129 if (r < 0)
ebcf1f97 130 return r;
c3350683 131 if (!machine)
de0671ee 132 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
c3350683
LP
133
134 p = machine_bus_path(machine);
135 if (!p)
ebcf1f97 136 return -ENOMEM;
c3350683 137
df2d202e 138 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
139}
140
ebcf1f97 141static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
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
df2d202e 152 r = sd_bus_message_new_method_return(message, &reply);
c3350683 153 if (r < 0)
ebcf1f97 154 return sd_bus_error_set_errno(error, r);
c3350683
LP
155
156 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
157 if (r < 0)
ebcf1f97 158 return sd_bus_error_set_errno(error, r);
c3350683
LP
159
160 HASHMAP_FOREACH(machine, m->machines, i) {
161 _cleanup_free_ char *p = NULL;
162
163 p = machine_bus_path(machine);
164 if (!p)
ebcf1f97 165 return -ENOMEM;
c3350683
LP
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)
ebcf1f97 173 return sd_bus_error_set_errno(error, r);
c3350683 174 }
1ee306e1 175
c3350683
LP
176 r = sd_bus_message_close_container(reply);
177 if (r < 0)
ebcf1f97 178 return sd_bus_error_set_errno(error, r);
c3350683
LP
179
180 return sd_bus_send(bus, reply, NULL);
181}
182
9b5ed6fe 183static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
8aec412f 184 const char *name, *service, *class, *root_directory;
9b5ed6fe 185 const int32_t *netif = NULL;
1ee306e1
LP
186 MachineClass c;
187 uint32_t leader;
188 sd_id128_t id;
c3350683 189 const void *v;
1ee306e1 190 Machine *m;
9b5ed6fe 191 size_t n, n_netif = 0;
c3350683 192 int r;
1ee306e1 193
c3350683 194 assert(manager);
89f7c846
LP
195 assert(message);
196 assert(_m);
1ee306e1 197
c3350683
LP
198 r = sd_bus_message_read(message, "s", &name);
199 if (r < 0)
ebcf1f97 200 return r;
7f0d207d 201 if (!machine_name_is_valid(name))
ebcf1f97 202 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 203
c3350683
LP
204 r = sd_bus_message_read_array(message, 'y', &v, &n);
205 if (r < 0)
ebcf1f97 206 return r;
1ee306e1
LP
207 if (n == 0)
208 id = SD_ID128_NULL;
209 else if (n == 16)
210 memcpy(&id, v, n);
211 else
ebcf1f97 212 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 213
c3350683
LP
214 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
215 if (r < 0)
ebcf1f97 216 return r;
1ee306e1 217
9b5ed6fe
LP
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
1ee306e1
LP
233 if (isempty(class))
234 c = _MACHINE_CLASS_INVALID;
235 else {
236 c = machine_class_from_string(class);
237 if (c < 0)
ebcf1f97 238 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
239 }
240
c3350683 241 if (leader == 1)
ebcf1f97 242 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 243
c3350683 244 if (!isempty(root_directory) && !path_is_absolute(root_directory))
ebcf1f97 245 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 246
c3350683 247 if (leader == 0) {
5b12334d
LP
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
c3350683 254 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
554604b3 255
5b12334d 256 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c3350683 257 if (r < 0)
ebcf1f97 258 return r;
c3350683 259 }
554604b3 260
1ee306e1 261 if (hashmap_get(manager->machines, name))
ebcf1f97 262 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1
LP
263
264 r = manager_add_machine(manager, name, &m);
265 if (r < 0)
ebcf1f97 266 return r;
1ee306e1
LP
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) {
ebcf1f97 275 r = -ENOMEM;
1ee306e1
LP
276 goto fail;
277 }
278 }
279
280 if (!isempty(root_directory)) {
281 m->root_directory = strdup(root_directory);
282 if (!m->root_directory) {
ebcf1f97 283 r = -ENOMEM;
1ee306e1
LP
284 goto fail;
285 }
286 }
287
9b5ed6fe
LP
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
89f7c846
LP
299 *_m = m;
300
301 return 1;
302
303fail:
304 machine_add_to_gc_queue(m);
305 return r;
306}
307
9b5ed6fe 308static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
309 Manager *manager = userdata;
310 Machine *m = NULL;
311 int r;
312
9b5ed6fe 313 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
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
ebcf1f97
LP
321 r = machine_start(m, message, error);
322 if (r < 0)
1ee306e1
LP
323 goto fail;
324
c3350683 325 m->create_message = sd_bus_message_ref(message);
c3350683 326 return 1;
1ee306e1
LP
327
328fail:
a3e7f417 329 machine_add_to_gc_queue(m);
89f7c846
LP
330 return r;
331}
1ee306e1 332
9b5ed6fe
LP
333static 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
337static 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
341static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
342 Manager *manager = userdata;
343 _cleanup_free_ char *p = NULL;
344 Machine *m = NULL;
345 int r;
346
9b5ed6fe 347 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
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
8d90c8a8
LP
357 m->registered = true;
358
89f7c846
LP
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
371fail:
372 machine_add_to_gc_queue(m);
1ee306e1
LP
373 return r;
374}
375
9b5ed6fe
LP
376static 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
380static 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
ebcf1f97 384static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 385 Manager *m = userdata;
c3350683
LP
386 Machine *machine;
387 const char *name;
1ee306e1
LP
388 int r;
389
c3350683 390 assert(bus);
1ee306e1
LP
391 assert(message);
392 assert(m);
393
c3350683
LP
394 r = sd_bus_message_read(message, "s", &name);
395 if (r < 0)
ebcf1f97 396 return sd_bus_error_set_errno(error, r);
1ee306e1 397
c3350683
LP
398 machine = hashmap_get(m->machines, name);
399 if (!machine)
ebcf1f97 400 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 401
878cd7e9 402 return bus_machine_method_terminate(bus, message, machine, error);
c3350683 403}
1ee306e1 404
ebcf1f97 405static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
406 Manager *m = userdata;
407 Machine *machine;
408 const char *name;
c3350683 409 int r;
1ee306e1 410
c3350683
LP
411 assert(bus);
412 assert(message);
413 assert(m);
1ee306e1 414
878cd7e9 415 r = sd_bus_message_read(message, "s", &name);
c3350683 416 if (r < 0)
ebcf1f97 417 return sd_bus_error_set_errno(error, r);
1ee306e1 418
c3350683
LP
419 machine = hashmap_get(m->machines, name);
420 if (!machine)
ebcf1f97 421 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 422
878cd7e9
LP
423 return bus_machine_method_kill(bus, message, machine, error);
424}
425
426static 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);
c3350683 437 if (r < 0)
ebcf1f97 438 return sd_bus_error_set_errno(error, r);
1ee306e1 439
878cd7e9
LP
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);
c3350683 445}
1ee306e1 446
717603e3
LP
447static 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
cd61c3bf
LP
468static 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
b6b18498 492 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
cd61c3bf
LP
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
b6b18498 503 r = sd_bus_message_append(reply, "(ssbttto)",
cd61c3bf
LP
504 image->name,
505 image_type_to_string(image->type),
506 image->read_only,
10f9c755
LP
507 image->crtime,
508 image->mtime,
b6b18498 509 image->size,
cd61c3bf
LP
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
40205d70
LP
522static 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
5f8cc96a
LP
543static 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)
08682124 555 return r;
5f8cc96a
LP
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
08682124
LP
564static 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 r = image_remove(i);
586 if (r < 0)
587 return r;
588
589 return sd_bus_reply_method_return(message, NULL);
590}
591
ebd93cb6
LP
592static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
593 _cleanup_(image_unrefp) Image* i = NULL;
594 const char *old_name, *new_name;
595 int r;
596
597 assert(bus);
598 assert(message);
599
600 r = sd_bus_message_read(message, "ss", &old_name, &new_name);
601 if (r < 0)
602 return r;
603
604 if (!image_name_is_valid(old_name))
605 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
606 if (!image_name_is_valid(new_name))
607 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
608
609 r = image_find(old_name, &i);
610 if (r < 0)
611 return r;
612 if (r == 0)
613 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
614
615 r = image_rename(i, new_name);
616 if (r < 0)
617 return r;
618
619 return sd_bus_reply_method_return(message, NULL);
620}
621
622static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
623 _cleanup_(image_unrefp) Image *i = NULL;
624 const char *old_name, *new_name;
625 int read_only, r;
626
627 assert(bus);
628 r = sd_bus_message_read(message, "ssb", &old_name, &new_name, &read_only);
629 if (r < 0)
630 return r;
631
632 if (!image_name_is_valid(old_name))
633 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
634 if (!image_name_is_valid(new_name))
635 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
636
637 r = image_find(old_name, &i);
638 if (r < 0)
639 return r;
640 if (r == 0)
641 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
642
643 r = image_clone(i, new_name, read_only);
644 if (r < 0)
645 return r;
646
647 return sd_bus_reply_method_return(message, NULL);
648}
649
650static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
651 _cleanup_(image_unrefp) Image *i = NULL;
652 const char *name;
653 int read_only, r;
654
655 assert(bus);
656 r = sd_bus_message_read(message, "sb", &name, &read_only);
657 if (r < 0)
658 return r;
659
660 if (!image_name_is_valid(name))
661 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
662
663 r = image_find(name, &i);
664 if (r < 0)
665 return r;
666 if (r == 0)
667 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
668
669 r = image_read_only(i, read_only);
670 if (r < 0)
671 return r;
672
673 return sd_bus_reply_method_return(message, NULL);
674}
675
c3350683
LP
676const sd_bus_vtable manager_vtable[] = {
677 SD_BUS_VTABLE_START(0),
adacb957 678 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 679 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
680 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
681 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
b6b18498 682 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 683 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 684 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 685 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 686 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
adacb957
LP
687 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
688 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
3a6fb33c 689 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 690 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 691 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
d04c1fb8 692 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
08682124 693 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
ebd93cb6
LP
694 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
695 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
696 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
c3350683
LP
697 SD_BUS_SIGNAL("MachineNew", "so", 0),
698 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
699 SD_BUS_VTABLE_END
700};
1ee306e1 701
ebcf1f97 702int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 703 const char *path, *result, *unit;
1ee306e1 704 Manager *m = userdata;
c3350683
LP
705 Machine *machine;
706 uint32_t id;
707 int r;
1ee306e1 708
c3350683 709 assert(bus);
1ee306e1 710 assert(message);
c3350683 711 assert(m);
1ee306e1 712
c3350683
LP
713 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
714 if (r < 0) {
ebcf1f97
LP
715 bus_log_parse_error(r);
716 return r;
c3350683 717 }
6797c324 718
c3350683
LP
719 machine = hashmap_get(m->machine_units, unit);
720 if (!machine)
721 return 0;
6797c324 722
c3350683
LP
723 if (streq_ptr(path, machine->scope_job)) {
724 free(machine->scope_job);
725 machine->scope_job = NULL;
6797c324 726
c3350683
LP
727 if (machine->started) {
728 if (streq(result, "done"))
729 machine_send_create_reply(machine, NULL);
730 else {
ebcf1f97 731 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 732
ebcf1f97 733 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 734
ebcf1f97 735 machine_send_create_reply(machine, &e);
c3350683
LP
736 }
737 } else
738 machine_save(machine);
1ee306e1
LP
739 }
740
c3350683
LP
741 machine_add_to_gc_queue(machine);
742 return 0;
1ee306e1
LP
743}
744
ebcf1f97 745int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
746 _cleanup_free_ char *unit = NULL;
747 Manager *m = userdata;
748 Machine *machine;
749 const char *path;
ebcf1f97 750 int r;
554604b3 751
c3350683
LP
752 assert(bus);
753 assert(message);
754 assert(m);
554604b3 755
c3350683
LP
756 path = sd_bus_message_get_path(message);
757 if (!path)
554604b3 758 return 0;
554604b3 759
ebcf1f97
LP
760 r = unit_name_from_dbus_path(path, &unit);
761 if (r < 0)
762 return r;
554604b3 763
c3350683
LP
764 machine = hashmap_get(m->machine_units, unit);
765 if (machine)
766 machine_add_to_gc_queue(machine);
554604b3 767
c3350683
LP
768 return 0;
769}
554604b3 770
ebcf1f97 771int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
772 const char *path, *unit;
773 Manager *m = userdata;
774 Machine *machine;
775 int r;
554604b3 776
c3350683
LP
777 assert(bus);
778 assert(message);
779 assert(m);
554604b3 780
c3350683
LP
781 r = sd_bus_message_read(message, "so", &unit, &path);
782 if (r < 0) {
ebcf1f97
LP
783 bus_log_parse_error(r);
784 return r;
554604b3
LP
785 }
786
c3350683
LP
787 machine = hashmap_get(m->machine_units, unit);
788 if (machine)
789 machine_add_to_gc_queue(machine);
554604b3 790
c3350683
LP
791 return 0;
792}
554604b3 793
ebcf1f97 794int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 795 Manager *m = userdata;
a658cafa
LP
796 Machine *machine;
797 Iterator i;
c3350683 798 int b, r;
554604b3 799
c3350683 800 assert(bus);
554604b3 801
c3350683
LP
802 r = sd_bus_message_read(message, "b", &b);
803 if (r < 0) {
ebcf1f97
LP
804 bus_log_parse_error(r);
805 return r;
554604b3 806 }
a658cafa
LP
807 if (b)
808 return 0;
554604b3 809
a658cafa
LP
810 /* systemd finished reloading, let's recheck all our machines */
811 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 812
a658cafa
LP
813 HASHMAP_FOREACH(machine, m->machines, i)
814 machine_add_to_gc_queue(machine);
554604b3
LP
815
816 return 0;
817}
818
1ee306e1
LP
819int manager_start_scope(
820 Manager *manager,
821 const char *scope,
822 pid_t pid,
823 const char *slice,
824 const char *description,
c3350683
LP
825 sd_bus_message *more_properties,
826 sd_bus_error *error,
1ee306e1
LP
827 char **job) {
828
c3350683 829 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 830 int r;
1ee306e1
LP
831
832 assert(manager);
833 assert(scope);
834 assert(pid > 1);
835
c3350683
LP
836 r = sd_bus_message_new_method_call(
837 manager->bus,
151b9b96 838 &m,
1ee306e1
LP
839 "org.freedesktop.systemd1",
840 "/org/freedesktop/systemd1",
841 "org.freedesktop.systemd1.Manager",
151b9b96 842 "StartTransientUnit");
c3350683
LP
843 if (r < 0)
844 return r;
1ee306e1 845
a658cafa 846 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
847 if (r < 0)
848 return r;
1ee306e1 849
c3350683
LP
850 r = sd_bus_message_open_container(m, 'a', "(sv)");
851 if (r < 0)
852 return r;
1ee306e1
LP
853
854 if (!isempty(slice)) {
c3350683
LP
855 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
856 if (r < 0)
857 return r;
1ee306e1
LP
858 }
859
860 if (!isempty(description)) {
c3350683
LP
861 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
862 if (r < 0)
863 return r;
1ee306e1
LP
864 }
865
c3350683
LP
866 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
867 if (r < 0)
868 return r;
554604b3 869
a931ad47
LP
870 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
871 if (r < 0)
872 return r;
873
554604b3 874 if (more_properties) {
c3350683 875 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
876 if (r < 0)
877 return r;
878 }
879
c3350683
LP
880 r = sd_bus_message_close_container(m);
881 if (r < 0)
882 return r;
1ee306e1 883
86b8d289
LP
884 r = sd_bus_message_append(m, "a(sa(sv))", 0);
885 if (r < 0)
886 return r;
887
c49b30a2 888 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
889 if (r < 0)
890 return r;
1ee306e1
LP
891
892 if (job) {
893 const char *j;
894 char *copy;
895
c3350683
LP
896 r = sd_bus_message_read(reply, "o", &j);
897 if (r < 0)
898 return r;
1ee306e1
LP
899
900 copy = strdup(j);
901 if (!copy)
902 return -ENOMEM;
903
904 *job = copy;
905 }
906
c3350683 907 return 1;
1ee306e1
LP
908}
909
c3350683
LP
910int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
911 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
912 int r;
913
914 assert(manager);
915 assert(unit);
916
c3350683 917 r = sd_bus_call_method(
1ee306e1
LP
918 manager->bus,
919 "org.freedesktop.systemd1",
920 "/org/freedesktop/systemd1",
921 "org.freedesktop.systemd1.Manager",
922 "StopUnit",
1ee306e1 923 error,
c3350683
LP
924 &reply,
925 "ss", unit, "fail");
1ee306e1 926 if (r < 0) {
c3350683
LP
927 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
928 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
929
930 if (job)
931 *job = NULL;
932
c3350683 933 sd_bus_error_free(error);
6797c324
LP
934 return 0;
935 }
936
1ee306e1
LP
937 return r;
938 }
939
940 if (job) {
941 const char *j;
942 char *copy;
943
c3350683
LP
944 r = sd_bus_message_read(reply, "o", &j);
945 if (r < 0)
946 return r;
1ee306e1
LP
947
948 copy = strdup(j);
949 if (!copy)
950 return -ENOMEM;
951
952 *job = copy;
953 }
954
6797c324 955 return 1;
1ee306e1
LP
956}
957
de58a50e 958int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
959 assert(manager);
960 assert(unit);
961
a658cafa 962 return sd_bus_call_method(
1ee306e1
LP
963 manager->bus,
964 "org.freedesktop.systemd1",
965 "/org/freedesktop/systemd1",
966 "org.freedesktop.systemd1.Manager",
967 "KillUnit",
1ee306e1 968 error,
a658cafa 969 NULL,
de58a50e 970 "ssi", unit, "all", signo);
1ee306e1
LP
971}
972
973int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
974 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
975 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 976 _cleanup_free_ char *path = NULL;
1ee306e1 977 const char *state;
1ee306e1
LP
978 int r;
979
980 assert(manager);
981 assert(unit);
982
1ee306e1
LP
983 path = unit_dbus_path_from_name(unit);
984 if (!path)
985 return -ENOMEM;
986
c3350683 987 r = sd_bus_get_property(
1ee306e1
LP
988 manager->bus,
989 "org.freedesktop.systemd1",
990 path,
c3350683
LP
991 "org.freedesktop.systemd1.Unit",
992 "ActiveState",
1ee306e1 993 &error,
c3350683
LP
994 &reply,
995 "s");
1ee306e1 996 if (r < 0) {
c3350683
LP
997 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
998 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 999 return true;
6797c324 1000
c3350683
LP
1001 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1002 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 1003 return false;
6797c324 1004
1ee306e1
LP
1005 return r;
1006 }
1007
c3350683
LP
1008 r = sd_bus_message_read(reply, "s", &state);
1009 if (r < 0)
1ee306e1 1010 return -EINVAL;
1ee306e1
LP
1011
1012 return !streq(state, "inactive") && !streq(state, "failed");
1013}
bd16acf3 1014
c3350683
LP
1015int manager_job_is_active(Manager *manager, const char *path) {
1016 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1017 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1018 int r;
bd16acf3 1019
c3350683
LP
1020 assert(manager);
1021 assert(path);
bd16acf3 1022
c3350683
LP
1023 r = sd_bus_get_property(
1024 manager->bus,
1025 "org.freedesktop.systemd1",
1026 path,
1027 "org.freedesktop.systemd1.Job",
1028 "State",
1029 &error,
1030 &reply,
1031 "s");
1032 if (r < 0) {
1033 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1034 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1035 return true;
bd16acf3 1036
c3350683
LP
1037 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1038 return false;
bd16acf3 1039
bd16acf3 1040 return r;
c3350683 1041 }
bd16acf3 1042
c3350683
LP
1043 /* We don't actually care about the state really. The fact
1044 * that we could read the job state is enough for us */
bd16acf3 1045
c3350683 1046 return true;
bd16acf3 1047}
ab49725f
KS
1048
1049int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1050 _cleanup_free_ char *unit = NULL;
1051 Machine *mm;
1052 int r;
1053
1054 assert(m);
1055 assert(pid >= 1);
1056 assert(machine);
1057
1058 r = cg_pid_get_unit(pid, &unit);
1059 if (r < 0)
1060 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1061 else
1062 mm = hashmap_get(m->machine_units, unit);
1063
1064 if (!mm)
1065 return 0;
1066
1067 *machine = mm;
1068 return 1;
1069}
1070
1071int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1072 Machine *machine;
1073
1074 assert(m);
1075 assert(name);
1076
1077 machine = hashmap_get(m->machines, name);
1078 if (!machine) {
1079 machine = machine_new(m, name);
1080 if (!machine)
1081 return -ENOMEM;
1082 }
1083
1084 if (_machine)
1085 *_machine = machine;
1086
1087 return 0;
1088}