]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
qcow2: when dissecting qcow2, use btrfs clone ioctls for reflinking blocks to target
[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
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
369fail:
370 machine_add_to_gc_queue(m);
1ee306e1
LP
371 return r;
372}
373
9b5ed6fe
LP
374static 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
378static 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
ebcf1f97 382static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 383 Manager *m = userdata;
c3350683
LP
384 Machine *machine;
385 const char *name;
1ee306e1
LP
386 int r;
387
c3350683 388 assert(bus);
1ee306e1
LP
389 assert(message);
390 assert(m);
391
c3350683
LP
392 r = sd_bus_message_read(message, "s", &name);
393 if (r < 0)
ebcf1f97 394 return sd_bus_error_set_errno(error, r);
1ee306e1 395
c3350683
LP
396 machine = hashmap_get(m->machines, name);
397 if (!machine)
ebcf1f97 398 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 399
878cd7e9 400 return bus_machine_method_terminate(bus, message, machine, error);
c3350683 401}
1ee306e1 402
ebcf1f97 403static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
404 Manager *m = userdata;
405 Machine *machine;
406 const char *name;
c3350683 407 int r;
1ee306e1 408
c3350683
LP
409 assert(bus);
410 assert(message);
411 assert(m);
1ee306e1 412
878cd7e9 413 r = sd_bus_message_read(message, "s", &name);
c3350683 414 if (r < 0)
ebcf1f97 415 return sd_bus_error_set_errno(error, r);
1ee306e1 416
c3350683
LP
417 machine = hashmap_get(m->machines, name);
418 if (!machine)
ebcf1f97 419 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 420
878cd7e9
LP
421 return bus_machine_method_kill(bus, message, machine, error);
422}
423
424static 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);
c3350683 435 if (r < 0)
ebcf1f97 436 return sd_bus_error_set_errno(error, r);
1ee306e1 437
878cd7e9
LP
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);
c3350683 443}
1ee306e1 444
717603e3
LP
445static 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
cd61c3bf
LP
466static 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
b6b18498 490 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
cd61c3bf
LP
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
b6b18498 501 r = sd_bus_message_append(reply, "(ssbttto)",
cd61c3bf
LP
502 image->name,
503 image_type_to_string(image->type),
504 image->read_only,
10f9c755
LP
505 image->crtime,
506 image->mtime,
b6b18498 507 image->size,
cd61c3bf
LP
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
40205d70
LP
520static 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
5f8cc96a
LP
541static 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)
08682124 553 return r;
5f8cc96a
LP
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
08682124
LP
562static 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
1ddb263d 583 return bus_image_method_remove(bus, message, i, error);
08682124
LP
584}
585
ebd93cb6
LP
586static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
587 _cleanup_(image_unrefp) Image* i = NULL;
1ddb263d 588 const char *old_name;
ebd93cb6
LP
589 int r;
590
591 assert(bus);
592 assert(message);
593
1ddb263d 594 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
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);
ebd93cb6
LP
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
1ddb263d 607 return bus_image_method_rename(bus, message, i, error);
ebd93cb6
LP
608}
609
610static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
611 _cleanup_(image_unrefp) Image *i = NULL;
1ddb263d
LP
612 const char *old_name;
613 int r;
ebd93cb6
LP
614
615 assert(bus);
1ddb263d 616 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
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);
ebd93cb6
LP
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
1ddb263d 629 return bus_image_method_clone(bus, message, i, error);
ebd93cb6
LP
630}
631
632static 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;
1ddb263d 635 int r;
ebd93cb6
LP
636
637 assert(bus);
1ddb263d 638 r = sd_bus_message_read(message, "s", &name);
ebd93cb6
LP
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
1ddb263d 651 return bus_image_method_mark_read_only(bus, message, i, error);
ebd93cb6
LP
652}
653
c3350683
LP
654const sd_bus_vtable manager_vtable[] = {
655 SD_BUS_VTABLE_START(0),
adacb957 656 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 657 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
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),
b6b18498 660 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 661 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 662 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 663 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 664 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
adacb957
LP
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)),
3a6fb33c 667 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 668 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 669 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
d04c1fb8 670 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
08682124 671 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
ebd93cb6
LP
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),
c3350683
LP
675 SD_BUS_SIGNAL("MachineNew", "so", 0),
676 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
677 SD_BUS_VTABLE_END
678};
1ee306e1 679
ebcf1f97 680int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 681 const char *path, *result, *unit;
1ee306e1 682 Manager *m = userdata;
c3350683
LP
683 Machine *machine;
684 uint32_t id;
685 int r;
1ee306e1 686
c3350683 687 assert(bus);
1ee306e1 688 assert(message);
c3350683 689 assert(m);
1ee306e1 690
c3350683
LP
691 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
692 if (r < 0) {
ebcf1f97
LP
693 bus_log_parse_error(r);
694 return r;
c3350683 695 }
6797c324 696
c3350683
LP
697 machine = hashmap_get(m->machine_units, unit);
698 if (!machine)
699 return 0;
6797c324 700
c3350683
LP
701 if (streq_ptr(path, machine->scope_job)) {
702 free(machine->scope_job);
703 machine->scope_job = NULL;
6797c324 704
c3350683
LP
705 if (machine->started) {
706 if (streq(result, "done"))
707 machine_send_create_reply(machine, NULL);
708 else {
ebcf1f97 709 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 710
ebcf1f97 711 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 712
ebcf1f97 713 machine_send_create_reply(machine, &e);
c3350683
LP
714 }
715 } else
716 machine_save(machine);
1ee306e1
LP
717 }
718
c3350683
LP
719 machine_add_to_gc_queue(machine);
720 return 0;
1ee306e1
LP
721}
722
ebcf1f97 723int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
724 _cleanup_free_ char *unit = NULL;
725 Manager *m = userdata;
726 Machine *machine;
727 const char *path;
ebcf1f97 728 int r;
554604b3 729
c3350683
LP
730 assert(bus);
731 assert(message);
732 assert(m);
554604b3 733
c3350683
LP
734 path = sd_bus_message_get_path(message);
735 if (!path)
554604b3 736 return 0;
554604b3 737
ebcf1f97 738 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
739 if (r == -EINVAL) /* not for a unit */
740 return 0;
ebcf1f97
LP
741 if (r < 0)
742 return r;
554604b3 743
c3350683
LP
744 machine = hashmap_get(m->machine_units, unit);
745 if (machine)
746 machine_add_to_gc_queue(machine);
554604b3 747
c3350683
LP
748 return 0;
749}
554604b3 750
ebcf1f97 751int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
752 const char *path, *unit;
753 Manager *m = userdata;
754 Machine *machine;
755 int r;
554604b3 756
c3350683
LP
757 assert(bus);
758 assert(message);
759 assert(m);
554604b3 760
c3350683
LP
761 r = sd_bus_message_read(message, "so", &unit, &path);
762 if (r < 0) {
ebcf1f97
LP
763 bus_log_parse_error(r);
764 return r;
554604b3
LP
765 }
766
c3350683
LP
767 machine = hashmap_get(m->machine_units, unit);
768 if (machine)
769 machine_add_to_gc_queue(machine);
554604b3 770
c3350683
LP
771 return 0;
772}
554604b3 773
ebcf1f97 774int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 775 Manager *m = userdata;
a658cafa
LP
776 Machine *machine;
777 Iterator i;
c3350683 778 int b, r;
554604b3 779
c3350683 780 assert(bus);
554604b3 781
c3350683
LP
782 r = sd_bus_message_read(message, "b", &b);
783 if (r < 0) {
ebcf1f97
LP
784 bus_log_parse_error(r);
785 return r;
554604b3 786 }
a658cafa
LP
787 if (b)
788 return 0;
554604b3 789
a658cafa
LP
790 /* systemd finished reloading, let's recheck all our machines */
791 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 792
a658cafa
LP
793 HASHMAP_FOREACH(machine, m->machines, i)
794 machine_add_to_gc_queue(machine);
554604b3
LP
795
796 return 0;
797}
798
1ee306e1
LP
799int manager_start_scope(
800 Manager *manager,
801 const char *scope,
802 pid_t pid,
803 const char *slice,
804 const char *description,
c3350683
LP
805 sd_bus_message *more_properties,
806 sd_bus_error *error,
1ee306e1
LP
807 char **job) {
808
c3350683 809 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 810 int r;
1ee306e1
LP
811
812 assert(manager);
813 assert(scope);
814 assert(pid > 1);
815
c3350683
LP
816 r = sd_bus_message_new_method_call(
817 manager->bus,
151b9b96 818 &m,
1ee306e1
LP
819 "org.freedesktop.systemd1",
820 "/org/freedesktop/systemd1",
821 "org.freedesktop.systemd1.Manager",
151b9b96 822 "StartTransientUnit");
c3350683
LP
823 if (r < 0)
824 return r;
1ee306e1 825
a658cafa 826 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
827 if (r < 0)
828 return r;
1ee306e1 829
c3350683
LP
830 r = sd_bus_message_open_container(m, 'a', "(sv)");
831 if (r < 0)
832 return r;
1ee306e1
LP
833
834 if (!isempty(slice)) {
c3350683
LP
835 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
836 if (r < 0)
837 return r;
1ee306e1
LP
838 }
839
840 if (!isempty(description)) {
c3350683
LP
841 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
842 if (r < 0)
843 return r;
1ee306e1
LP
844 }
845
c3350683
LP
846 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
847 if (r < 0)
848 return r;
554604b3 849
a931ad47
LP
850 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
851 if (r < 0)
852 return r;
853
554604b3 854 if (more_properties) {
c3350683 855 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
856 if (r < 0)
857 return r;
858 }
859
c3350683
LP
860 r = sd_bus_message_close_container(m);
861 if (r < 0)
862 return r;
1ee306e1 863
86b8d289
LP
864 r = sd_bus_message_append(m, "a(sa(sv))", 0);
865 if (r < 0)
866 return r;
867
c49b30a2 868 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
869 if (r < 0)
870 return r;
1ee306e1
LP
871
872 if (job) {
873 const char *j;
874 char *copy;
875
c3350683
LP
876 r = sd_bus_message_read(reply, "o", &j);
877 if (r < 0)
878 return r;
1ee306e1
LP
879
880 copy = strdup(j);
881 if (!copy)
882 return -ENOMEM;
883
884 *job = copy;
885 }
886
c3350683 887 return 1;
1ee306e1
LP
888}
889
c3350683
LP
890int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
891 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
892 int r;
893
894 assert(manager);
895 assert(unit);
896
c3350683 897 r = sd_bus_call_method(
1ee306e1
LP
898 manager->bus,
899 "org.freedesktop.systemd1",
900 "/org/freedesktop/systemd1",
901 "org.freedesktop.systemd1.Manager",
902 "StopUnit",
1ee306e1 903 error,
c3350683
LP
904 &reply,
905 "ss", unit, "fail");
1ee306e1 906 if (r < 0) {
c3350683
LP
907 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
908 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
909
910 if (job)
911 *job = NULL;
912
c3350683 913 sd_bus_error_free(error);
6797c324
LP
914 return 0;
915 }
916
1ee306e1
LP
917 return r;
918 }
919
920 if (job) {
921 const char *j;
922 char *copy;
923
c3350683
LP
924 r = sd_bus_message_read(reply, "o", &j);
925 if (r < 0)
926 return r;
1ee306e1
LP
927
928 copy = strdup(j);
929 if (!copy)
930 return -ENOMEM;
931
932 *job = copy;
933 }
934
6797c324 935 return 1;
1ee306e1
LP
936}
937
de58a50e 938int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
939 assert(manager);
940 assert(unit);
941
a658cafa 942 return sd_bus_call_method(
1ee306e1
LP
943 manager->bus,
944 "org.freedesktop.systemd1",
945 "/org/freedesktop/systemd1",
946 "org.freedesktop.systemd1.Manager",
947 "KillUnit",
1ee306e1 948 error,
a658cafa 949 NULL,
de58a50e 950 "ssi", unit, "all", signo);
1ee306e1
LP
951}
952
953int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
954 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
955 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 956 _cleanup_free_ char *path = NULL;
1ee306e1 957 const char *state;
1ee306e1
LP
958 int r;
959
960 assert(manager);
961 assert(unit);
962
1ee306e1
LP
963 path = unit_dbus_path_from_name(unit);
964 if (!path)
965 return -ENOMEM;
966
c3350683 967 r = sd_bus_get_property(
1ee306e1
LP
968 manager->bus,
969 "org.freedesktop.systemd1",
970 path,
c3350683
LP
971 "org.freedesktop.systemd1.Unit",
972 "ActiveState",
1ee306e1 973 &error,
c3350683
LP
974 &reply,
975 "s");
1ee306e1 976 if (r < 0) {
c3350683
LP
977 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
978 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 979 return true;
6797c324 980
c3350683
LP
981 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
982 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 983 return false;
6797c324 984
1ee306e1
LP
985 return r;
986 }
987
c3350683
LP
988 r = sd_bus_message_read(reply, "s", &state);
989 if (r < 0)
1ee306e1 990 return -EINVAL;
1ee306e1
LP
991
992 return !streq(state, "inactive") && !streq(state, "failed");
993}
bd16acf3 994
c3350683
LP
995int 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;
bd16acf3 999
c3350683
LP
1000 assert(manager);
1001 assert(path);
bd16acf3 1002
c3350683
LP
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;
bd16acf3 1016
c3350683
LP
1017 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1018 return false;
bd16acf3 1019
bd16acf3 1020 return r;
c3350683 1021 }
bd16acf3 1022
c3350683
LP
1023 /* We don't actually care about the state really. The fact
1024 * that we could read the job state is enough for us */
bd16acf3 1025
c3350683 1026 return true;
bd16acf3 1027}
ab49725f
KS
1028
1029int 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
1051int 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}