]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
nspawn: report back to systemd only very late whether we are OK
[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
1ddb263d 585 return bus_image_method_remove(bus, message, i, error);
08682124
LP
586}
587
ebd93cb6
LP
588static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
589 _cleanup_(image_unrefp) Image* i = NULL;
1ddb263d 590 const char *old_name;
ebd93cb6
LP
591 int r;
592
593 assert(bus);
594 assert(message);
595
1ddb263d 596 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
597 if (r < 0)
598 return r;
599
600 if (!image_name_is_valid(old_name))
601 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
602
603 r = image_find(old_name, &i);
604 if (r < 0)
605 return r;
606 if (r == 0)
607 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
608
1ddb263d 609 return bus_image_method_rename(bus, message, i, error);
ebd93cb6
LP
610}
611
612static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
613 _cleanup_(image_unrefp) Image *i = NULL;
1ddb263d
LP
614 const char *old_name;
615 int r;
ebd93cb6
LP
616
617 assert(bus);
1ddb263d 618 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
619 if (r < 0)
620 return r;
621
622 if (!image_name_is_valid(old_name))
623 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
624
625 r = image_find(old_name, &i);
626 if (r < 0)
627 return r;
628 if (r == 0)
629 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
630
1ddb263d 631 return bus_image_method_clone(bus, message, i, error);
ebd93cb6
LP
632}
633
634static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
635 _cleanup_(image_unrefp) Image *i = NULL;
636 const char *name;
1ddb263d 637 int r;
ebd93cb6
LP
638
639 assert(bus);
1ddb263d 640 r = sd_bus_message_read(message, "s", &name);
ebd93cb6
LP
641 if (r < 0)
642 return r;
643
644 if (!image_name_is_valid(name))
645 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
646
647 r = image_find(name, &i);
648 if (r < 0)
649 return r;
650 if (r == 0)
651 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
652
1ddb263d 653 return bus_image_method_mark_read_only(bus, message, i, error);
ebd93cb6
LP
654}
655
c3350683
LP
656const sd_bus_vtable manager_vtable[] = {
657 SD_BUS_VTABLE_START(0),
adacb957 658 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 659 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
660 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
661 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
b6b18498 662 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 663 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 664 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 665 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 666 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
adacb957
LP
667 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
668 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
3a6fb33c 669 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 670 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 671 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
d04c1fb8 672 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
08682124 673 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
ebd93cb6
LP
674 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
675 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
676 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
c3350683
LP
677 SD_BUS_SIGNAL("MachineNew", "so", 0),
678 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
679 SD_BUS_VTABLE_END
680};
1ee306e1 681
ebcf1f97 682int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 683 const char *path, *result, *unit;
1ee306e1 684 Manager *m = userdata;
c3350683
LP
685 Machine *machine;
686 uint32_t id;
687 int r;
1ee306e1 688
c3350683 689 assert(bus);
1ee306e1 690 assert(message);
c3350683 691 assert(m);
1ee306e1 692
c3350683
LP
693 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
694 if (r < 0) {
ebcf1f97
LP
695 bus_log_parse_error(r);
696 return r;
c3350683 697 }
6797c324 698
c3350683
LP
699 machine = hashmap_get(m->machine_units, unit);
700 if (!machine)
701 return 0;
6797c324 702
c3350683
LP
703 if (streq_ptr(path, machine->scope_job)) {
704 free(machine->scope_job);
705 machine->scope_job = NULL;
6797c324 706
c3350683
LP
707 if (machine->started) {
708 if (streq(result, "done"))
709 machine_send_create_reply(machine, NULL);
710 else {
ebcf1f97 711 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 712
ebcf1f97 713 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 714
ebcf1f97 715 machine_send_create_reply(machine, &e);
c3350683
LP
716 }
717 } else
718 machine_save(machine);
1ee306e1
LP
719 }
720
c3350683
LP
721 machine_add_to_gc_queue(machine);
722 return 0;
1ee306e1
LP
723}
724
ebcf1f97 725int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
726 _cleanup_free_ char *unit = NULL;
727 Manager *m = userdata;
728 Machine *machine;
729 const char *path;
ebcf1f97 730 int r;
554604b3 731
c3350683
LP
732 assert(bus);
733 assert(message);
734 assert(m);
554604b3 735
c3350683
LP
736 path = sd_bus_message_get_path(message);
737 if (!path)
554604b3 738 return 0;
554604b3 739
ebcf1f97
LP
740 r = unit_name_from_dbus_path(path, &unit);
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}