]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
machined: various simplifications
[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,
c19de711 507 image->usage,
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
90adaa25
LP
562static int method_bind_mount_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
563 Manager *m = userdata;
564 Machine *machine;
565 const char *name;
566 int r;
567
568 assert(bus);
569 assert(message);
570 assert(m);
571
572 r = sd_bus_message_read(message, "s", &name);
573 if (r < 0)
574 return r;
575
576 machine = hashmap_get(m->machines, name);
577 if (!machine)
578 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
579
580 return bus_machine_method_bind_mount(bus, message, machine, error);
581}
582
08682124
LP
583static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
584 _cleanup_(image_unrefp) Image* i = NULL;
585 const char *name;
586 int r;
587
588 assert(bus);
589 assert(message);
590
591 r = sd_bus_message_read(message, "s", &name);
592 if (r < 0)
593 return r;
594
595 if (!image_name_is_valid(name))
596 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
597
598 r = image_find(name, &i);
599 if (r < 0)
600 return r;
601 if (r == 0)
602 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
603
1ddb263d 604 return bus_image_method_remove(bus, message, i, error);
08682124
LP
605}
606
ebd93cb6
LP
607static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
608 _cleanup_(image_unrefp) Image* i = NULL;
1ddb263d 609 const char *old_name;
ebd93cb6
LP
610 int r;
611
612 assert(bus);
613 assert(message);
614
1ddb263d 615 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
616 if (r < 0)
617 return r;
618
619 if (!image_name_is_valid(old_name))
620 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
621
622 r = image_find(old_name, &i);
623 if (r < 0)
624 return r;
625 if (r == 0)
626 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
627
1ddb263d 628 return bus_image_method_rename(bus, message, i, error);
ebd93cb6
LP
629}
630
631static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
632 _cleanup_(image_unrefp) Image *i = NULL;
1ddb263d
LP
633 const char *old_name;
634 int r;
ebd93cb6
LP
635
636 assert(bus);
1ddb263d 637 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
638 if (r < 0)
639 return r;
640
641 if (!image_name_is_valid(old_name))
642 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
643
644 r = image_find(old_name, &i);
645 if (r < 0)
646 return r;
647 if (r == 0)
648 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
649
1ddb263d 650 return bus_image_method_clone(bus, message, i, error);
ebd93cb6
LP
651}
652
653static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
654 _cleanup_(image_unrefp) Image *i = NULL;
655 const char *name;
1ddb263d 656 int r;
ebd93cb6
LP
657
658 assert(bus);
1ddb263d 659 r = sd_bus_message_read(message, "s", &name);
ebd93cb6
LP
660 if (r < 0)
661 return r;
662
663 if (!image_name_is_valid(name))
664 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
665
666 r = image_find(name, &i);
667 if (r < 0)
668 return r;
669 if (r == 0)
670 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
671
1ddb263d 672 return bus_image_method_mark_read_only(bus, message, i, error);
ebd93cb6
LP
673}
674
c3350683
LP
675const sd_bus_vtable manager_vtable[] = {
676 SD_BUS_VTABLE_START(0),
adacb957 677 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 678 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
679 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
680 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
b6b18498 681 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 682 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 683 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 684 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 685 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
adacb957
LP
686 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
687 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
3a6fb33c 688 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 689 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 690 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
d04c1fb8 691 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
08682124 692 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
ebd93cb6
LP
693 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
694 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
695 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
90adaa25 696 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, 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 760 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
761 if (r == -EINVAL) /* not for a unit */
762 return 0;
ebcf1f97
LP
763 if (r < 0)
764 return r;
554604b3 765
c3350683
LP
766 machine = hashmap_get(m->machine_units, unit);
767 if (machine)
768 machine_add_to_gc_queue(machine);
554604b3 769
c3350683
LP
770 return 0;
771}
554604b3 772
ebcf1f97 773int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
774 const char *path, *unit;
775 Manager *m = userdata;
776 Machine *machine;
777 int r;
554604b3 778
c3350683
LP
779 assert(bus);
780 assert(message);
781 assert(m);
554604b3 782
c3350683
LP
783 r = sd_bus_message_read(message, "so", &unit, &path);
784 if (r < 0) {
ebcf1f97
LP
785 bus_log_parse_error(r);
786 return r;
554604b3
LP
787 }
788
c3350683
LP
789 machine = hashmap_get(m->machine_units, unit);
790 if (machine)
791 machine_add_to_gc_queue(machine);
554604b3 792
c3350683
LP
793 return 0;
794}
554604b3 795
ebcf1f97 796int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 797 Manager *m = userdata;
a658cafa
LP
798 Machine *machine;
799 Iterator i;
c3350683 800 int b, r;
554604b3 801
c3350683 802 assert(bus);
554604b3 803
c3350683
LP
804 r = sd_bus_message_read(message, "b", &b);
805 if (r < 0) {
ebcf1f97
LP
806 bus_log_parse_error(r);
807 return r;
554604b3 808 }
a658cafa
LP
809 if (b)
810 return 0;
554604b3 811
a658cafa
LP
812 /* systemd finished reloading, let's recheck all our machines */
813 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 814
a658cafa
LP
815 HASHMAP_FOREACH(machine, m->machines, i)
816 machine_add_to_gc_queue(machine);
554604b3
LP
817
818 return 0;
819}
820
1ee306e1
LP
821int manager_start_scope(
822 Manager *manager,
823 const char *scope,
824 pid_t pid,
825 const char *slice,
826 const char *description,
c3350683
LP
827 sd_bus_message *more_properties,
828 sd_bus_error *error,
1ee306e1
LP
829 char **job) {
830
c3350683 831 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 832 int r;
1ee306e1
LP
833
834 assert(manager);
835 assert(scope);
836 assert(pid > 1);
837
c3350683
LP
838 r = sd_bus_message_new_method_call(
839 manager->bus,
151b9b96 840 &m,
1ee306e1
LP
841 "org.freedesktop.systemd1",
842 "/org/freedesktop/systemd1",
843 "org.freedesktop.systemd1.Manager",
151b9b96 844 "StartTransientUnit");
c3350683
LP
845 if (r < 0)
846 return r;
1ee306e1 847
a658cafa 848 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
849 if (r < 0)
850 return r;
1ee306e1 851
c3350683
LP
852 r = sd_bus_message_open_container(m, 'a', "(sv)");
853 if (r < 0)
854 return r;
1ee306e1
LP
855
856 if (!isempty(slice)) {
c3350683
LP
857 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
858 if (r < 0)
859 return r;
1ee306e1
LP
860 }
861
862 if (!isempty(description)) {
c3350683
LP
863 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
864 if (r < 0)
865 return r;
1ee306e1
LP
866 }
867
c3350683
LP
868 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
869 if (r < 0)
870 return r;
554604b3 871
a931ad47
LP
872 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
873 if (r < 0)
874 return r;
875
554604b3 876 if (more_properties) {
c3350683 877 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
878 if (r < 0)
879 return r;
880 }
881
c3350683
LP
882 r = sd_bus_message_close_container(m);
883 if (r < 0)
884 return r;
1ee306e1 885
86b8d289
LP
886 r = sd_bus_message_append(m, "a(sa(sv))", 0);
887 if (r < 0)
888 return r;
889
c49b30a2 890 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
891 if (r < 0)
892 return r;
1ee306e1
LP
893
894 if (job) {
895 const char *j;
896 char *copy;
897
c3350683
LP
898 r = sd_bus_message_read(reply, "o", &j);
899 if (r < 0)
900 return r;
1ee306e1
LP
901
902 copy = strdup(j);
903 if (!copy)
904 return -ENOMEM;
905
906 *job = copy;
907 }
908
c3350683 909 return 1;
1ee306e1
LP
910}
911
c3350683
LP
912int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
913 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
914 int r;
915
916 assert(manager);
917 assert(unit);
918
c3350683 919 r = sd_bus_call_method(
1ee306e1
LP
920 manager->bus,
921 "org.freedesktop.systemd1",
922 "/org/freedesktop/systemd1",
923 "org.freedesktop.systemd1.Manager",
924 "StopUnit",
1ee306e1 925 error,
c3350683
LP
926 &reply,
927 "ss", unit, "fail");
1ee306e1 928 if (r < 0) {
c3350683
LP
929 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
930 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
931
932 if (job)
933 *job = NULL;
934
c3350683 935 sd_bus_error_free(error);
6797c324
LP
936 return 0;
937 }
938
1ee306e1
LP
939 return r;
940 }
941
942 if (job) {
943 const char *j;
944 char *copy;
945
c3350683
LP
946 r = sd_bus_message_read(reply, "o", &j);
947 if (r < 0)
948 return r;
1ee306e1
LP
949
950 copy = strdup(j);
951 if (!copy)
952 return -ENOMEM;
953
954 *job = copy;
955 }
956
6797c324 957 return 1;
1ee306e1
LP
958}
959
de58a50e 960int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
961 assert(manager);
962 assert(unit);
963
a658cafa 964 return sd_bus_call_method(
1ee306e1
LP
965 manager->bus,
966 "org.freedesktop.systemd1",
967 "/org/freedesktop/systemd1",
968 "org.freedesktop.systemd1.Manager",
969 "KillUnit",
1ee306e1 970 error,
a658cafa 971 NULL,
de58a50e 972 "ssi", unit, "all", signo);
1ee306e1
LP
973}
974
975int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
976 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
977 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 978 _cleanup_free_ char *path = NULL;
1ee306e1 979 const char *state;
1ee306e1
LP
980 int r;
981
982 assert(manager);
983 assert(unit);
984
1ee306e1
LP
985 path = unit_dbus_path_from_name(unit);
986 if (!path)
987 return -ENOMEM;
988
c3350683 989 r = sd_bus_get_property(
1ee306e1
LP
990 manager->bus,
991 "org.freedesktop.systemd1",
992 path,
c3350683
LP
993 "org.freedesktop.systemd1.Unit",
994 "ActiveState",
1ee306e1 995 &error,
c3350683
LP
996 &reply,
997 "s");
1ee306e1 998 if (r < 0) {
c3350683
LP
999 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1000 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 1001 return true;
6797c324 1002
c3350683
LP
1003 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1004 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 1005 return false;
6797c324 1006
1ee306e1
LP
1007 return r;
1008 }
1009
c3350683
LP
1010 r = sd_bus_message_read(reply, "s", &state);
1011 if (r < 0)
1ee306e1 1012 return -EINVAL;
1ee306e1
LP
1013
1014 return !streq(state, "inactive") && !streq(state, "failed");
1015}
bd16acf3 1016
c3350683
LP
1017int manager_job_is_active(Manager *manager, const char *path) {
1018 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1019 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1020 int r;
bd16acf3 1021
c3350683
LP
1022 assert(manager);
1023 assert(path);
bd16acf3 1024
c3350683
LP
1025 r = sd_bus_get_property(
1026 manager->bus,
1027 "org.freedesktop.systemd1",
1028 path,
1029 "org.freedesktop.systemd1.Job",
1030 "State",
1031 &error,
1032 &reply,
1033 "s");
1034 if (r < 0) {
1035 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1036 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1037 return true;
bd16acf3 1038
c3350683
LP
1039 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1040 return false;
bd16acf3 1041
bd16acf3 1042 return r;
c3350683 1043 }
bd16acf3 1044
c3350683
LP
1045 /* We don't actually care about the state really. The fact
1046 * that we could read the job state is enough for us */
bd16acf3 1047
c3350683 1048 return true;
bd16acf3 1049}
ab49725f
KS
1050
1051int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1052 _cleanup_free_ char *unit = NULL;
1053 Machine *mm;
1054 int r;
1055
1056 assert(m);
1057 assert(pid >= 1);
1058 assert(machine);
1059
1060 r = cg_pid_get_unit(pid, &unit);
1061 if (r < 0)
1062 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1063 else
1064 mm = hashmap_get(m->machine_units, unit);
1065
1066 if (!mm)
1067 return 0;
1068
1069 *machine = mm;
1070 return 1;
1071}
1072
1073int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1074 Machine *machine;
1075
1076 assert(m);
1077 assert(name);
1078
1079 machine = hashmap_get(m->machines, name);
1080 if (!machine) {
1081 machine = machine_new(m, name);
1082 if (!machine)
1083 return -ENOMEM;
1084 }
1085
1086 if (_machine)
1087 *_machine = machine;
1088
1089 return 0;
1090}