]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
shared: fix wrong assertion in barrier_set_role()
[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>
1ee306e1 25
c3350683 26#include "sd-id128.h"
1ee306e1 27#include "path-util.h"
1ee306e1 28#include "unit-name.h"
c3350683 29#include "bus-util.h"
96aad8d1 30#include "bus-common-errors.h"
23c80348 31#include "cgroup-util.h"
003dffde
LP
32#include "machine-image.h"
33#include "image-dbus.h"
c3350683 34#include "machined.h"
003dffde 35#include "machine-dbus.h"
1ee306e1 36
ebcf1f97 37static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
38 _cleanup_free_ char *p = NULL;
39 Manager *m = userdata;
40 Machine *machine;
41 const char *name;
42 int r;
43
44 assert(bus);
45 assert(message);
46 assert(m);
47
48 r = sd_bus_message_read(message, "s", &name);
49 if (r < 0)
ebcf1f97 50 return r;
c3350683
LP
51
52 machine = hashmap_get(m->machines, name);
53 if (!machine)
ebcf1f97 54 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
c3350683
LP
55
56 p = machine_bus_path(machine);
57 if (!p)
ebcf1f97 58 return -ENOMEM;
c3350683 59
df2d202e 60 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
61}
62
c2ce6a3d
LP
63static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
64 _cleanup_free_ char *p = NULL;
65 Manager *m = userdata;
66 const char *name;
67 int r;
68
69 assert(bus);
70 assert(message);
71 assert(m);
72
73 r = sd_bus_message_read(message, "s", &name);
74 if (r < 0)
75 return r;
76
77 r = image_find(name, NULL);
78 if (r == 0)
79 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
80 if (r < 0)
81 return r;
82
83 p = image_bus_path(name);
84 if (!p)
85 return -ENOMEM;
86
87 return sd_bus_reply_method_return(message, "o", p);
88}
89
ebcf1f97 90static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
91 _cleanup_free_ char *p = NULL;
92 Manager *m = userdata;
93 Machine *machine = NULL;
4e724d9c 94 pid_t pid;
c3350683
LP
95 int r;
96
97 assert(bus);
98 assert(message);
99 assert(m);
100
4e724d9c
LP
101 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
102
c3350683
LP
103 r = sd_bus_message_read(message, "u", &pid);
104 if (r < 0)
ebcf1f97 105 return r;
c3350683 106
4e724d9c 107 if (pid == 0) {
5b12334d
LP
108 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
109
110 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
111 if (r < 0)
112 return r;
113
114 r = sd_bus_creds_get_pid(creds, &pid);
4e724d9c 115 if (r < 0)
ebcf1f97 116 return r;
4e724d9c
LP
117 }
118
c3350683
LP
119 r = manager_get_machine_by_pid(m, pid, &machine);
120 if (r < 0)
ebcf1f97 121 return r;
c3350683 122 if (!machine)
de0671ee 123 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
124
125 p = machine_bus_path(machine);
126 if (!p)
ebcf1f97 127 return -ENOMEM;
c3350683 128
df2d202e 129 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
130}
131
ebcf1f97 132static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
133 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
134 Manager *m = userdata;
135 Machine *machine;
136 Iterator i;
137 int r;
138
139 assert(bus);
140 assert(message);
141 assert(m);
142
df2d202e 143 r = sd_bus_message_new_method_return(message, &reply);
c3350683 144 if (r < 0)
ebcf1f97 145 return sd_bus_error_set_errno(error, r);
c3350683
LP
146
147 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
148 if (r < 0)
ebcf1f97 149 return sd_bus_error_set_errno(error, r);
c3350683
LP
150
151 HASHMAP_FOREACH(machine, m->machines, i) {
152 _cleanup_free_ char *p = NULL;
153
154 p = machine_bus_path(machine);
155 if (!p)
ebcf1f97 156 return -ENOMEM;
c3350683
LP
157
158 r = sd_bus_message_append(reply, "(ssso)",
159 machine->name,
160 strempty(machine_class_to_string(machine->class)),
161 machine->service,
162 p);
163 if (r < 0)
ebcf1f97 164 return sd_bus_error_set_errno(error, r);
c3350683 165 }
1ee306e1 166
c3350683
LP
167 r = sd_bus_message_close_container(reply);
168 if (r < 0)
ebcf1f97 169 return sd_bus_error_set_errno(error, r);
c3350683
LP
170
171 return sd_bus_send(bus, reply, NULL);
172}
173
9b5ed6fe 174static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
8aec412f 175 const char *name, *service, *class, *root_directory;
9b5ed6fe 176 const int32_t *netif = NULL;
1ee306e1
LP
177 MachineClass c;
178 uint32_t leader;
179 sd_id128_t id;
c3350683 180 const void *v;
1ee306e1 181 Machine *m;
9b5ed6fe 182 size_t n, n_netif = 0;
c3350683 183 int r;
1ee306e1 184
c3350683 185 assert(manager);
89f7c846
LP
186 assert(message);
187 assert(_m);
1ee306e1 188
c3350683
LP
189 r = sd_bus_message_read(message, "s", &name);
190 if (r < 0)
ebcf1f97 191 return r;
7f0d207d 192 if (!machine_name_is_valid(name))
ebcf1f97 193 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 194
c3350683
LP
195 r = sd_bus_message_read_array(message, 'y', &v, &n);
196 if (r < 0)
ebcf1f97 197 return r;
1ee306e1
LP
198 if (n == 0)
199 id = SD_ID128_NULL;
200 else if (n == 16)
201 memcpy(&id, v, n);
202 else
ebcf1f97 203 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 204
c3350683
LP
205 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
206 if (r < 0)
ebcf1f97 207 return r;
1ee306e1 208
9b5ed6fe
LP
209 if (read_network) {
210 size_t i;
211
212 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
213 if (r < 0)
214 return r;
215
216 n_netif /= sizeof(int32_t);
217
218 for (i = 0; i < n_netif; i++) {
219 if (netif[i] <= 0)
220 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
221 }
222 }
223
1ee306e1
LP
224 if (isempty(class))
225 c = _MACHINE_CLASS_INVALID;
226 else {
227 c = machine_class_from_string(class);
228 if (c < 0)
ebcf1f97 229 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
230 }
231
c3350683 232 if (leader == 1)
ebcf1f97 233 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 234
c3350683 235 if (!isempty(root_directory) && !path_is_absolute(root_directory))
ebcf1f97 236 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 237
c3350683 238 if (leader == 0) {
5b12334d
LP
239 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
240
241 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
242 if (r < 0)
243 return r;
244
c3350683 245 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
554604b3 246
5b12334d 247 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c3350683 248 if (r < 0)
ebcf1f97 249 return r;
c3350683 250 }
554604b3 251
1ee306e1 252 if (hashmap_get(manager->machines, name))
ebcf1f97 253 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1
LP
254
255 r = manager_add_machine(manager, name, &m);
256 if (r < 0)
ebcf1f97 257 return r;
1ee306e1
LP
258
259 m->leader = leader;
260 m->class = c;
261 m->id = id;
262
263 if (!isempty(service)) {
264 m->service = strdup(service);
265 if (!m->service) {
ebcf1f97 266 r = -ENOMEM;
1ee306e1
LP
267 goto fail;
268 }
269 }
270
271 if (!isempty(root_directory)) {
272 m->root_directory = strdup(root_directory);
273 if (!m->root_directory) {
ebcf1f97 274 r = -ENOMEM;
1ee306e1
LP
275 goto fail;
276 }
277 }
278
9b5ed6fe
LP
279 if (n_netif > 0) {
280 assert_cc(sizeof(int32_t) == sizeof(int));
281 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
282 if (!m->netif) {
283 r = -ENOMEM;
284 goto fail;
285 }
286
287 m->n_netif = n_netif;
288 }
289
89f7c846
LP
290 *_m = m;
291
292 return 1;
293
294fail:
295 machine_add_to_gc_queue(m);
296 return r;
297}
298
9b5ed6fe 299static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
300 Manager *manager = userdata;
301 Machine *m = NULL;
302 int r;
303
9b5ed6fe 304 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
305 if (r < 0)
306 return r;
307
308 r = sd_bus_message_enter_container(message, 'a', "(sv)");
309 if (r < 0)
310 goto fail;
311
ebcf1f97
LP
312 r = machine_start(m, message, error);
313 if (r < 0)
1ee306e1
LP
314 goto fail;
315
c3350683 316 m->create_message = sd_bus_message_ref(message);
c3350683 317 return 1;
1ee306e1
LP
318
319fail:
a3e7f417 320 machine_add_to_gc_queue(m);
89f7c846
LP
321 return r;
322}
1ee306e1 323
9b5ed6fe
LP
324static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
325 return method_create_machine_internal(bus, message, true, userdata, error);
326}
327
328static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
329 return method_create_machine_internal(bus, message, false, userdata, error);
330}
331
332static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
333 Manager *manager = userdata;
334 _cleanup_free_ char *p = NULL;
335 Machine *m = NULL;
336 int r;
337
9b5ed6fe 338 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
339 if (r < 0)
340 return r;
341
342 r = cg_pid_get_unit(m->leader, &m->unit);
343 if (r < 0) {
344 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
345 goto fail;
346 }
347
348 r = machine_start(m, NULL, error);
349 if (r < 0)
350 goto fail;
351
352 p = machine_bus_path(m);
353 if (!p) {
354 r = -ENOMEM;
355 goto fail;
356 }
357
358 return sd_bus_reply_method_return(message, "o", p);
359
360fail:
361 machine_add_to_gc_queue(m);
1ee306e1
LP
362 return r;
363}
364
9b5ed6fe
LP
365static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
366 return method_register_machine_internal(bus, message, true, userdata, error);
367}
368
369static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
370 return method_register_machine_internal(bus, message, false, userdata, error);
371}
372
ebcf1f97 373static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 374 Manager *m = userdata;
c3350683
LP
375 Machine *machine;
376 const char *name;
1ee306e1
LP
377 int r;
378
c3350683 379 assert(bus);
1ee306e1
LP
380 assert(message);
381 assert(m);
382
c3350683
LP
383 r = sd_bus_message_read(message, "s", &name);
384 if (r < 0)
ebcf1f97 385 return sd_bus_error_set_errno(error, r);
1ee306e1 386
c3350683
LP
387 machine = hashmap_get(m->machines, name);
388 if (!machine)
ebcf1f97 389 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 390
878cd7e9 391 return bus_machine_method_terminate(bus, message, machine, error);
c3350683 392}
1ee306e1 393
ebcf1f97 394static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
395 Manager *m = userdata;
396 Machine *machine;
397 const char *name;
c3350683 398 int r;
1ee306e1 399
c3350683
LP
400 assert(bus);
401 assert(message);
402 assert(m);
1ee306e1 403
878cd7e9 404 r = sd_bus_message_read(message, "s", &name);
c3350683 405 if (r < 0)
ebcf1f97 406 return sd_bus_error_set_errno(error, r);
1ee306e1 407
c3350683
LP
408 machine = hashmap_get(m->machines, name);
409 if (!machine)
ebcf1f97 410 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 411
878cd7e9
LP
412 return bus_machine_method_kill(bus, message, machine, error);
413}
414
415static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
416 Manager *m = userdata;
417 Machine *machine;
418 const char *name;
419 int r;
420
421 assert(bus);
422 assert(message);
423 assert(m);
424
425 r = sd_bus_message_read(message, "s", &name);
c3350683 426 if (r < 0)
ebcf1f97 427 return sd_bus_error_set_errno(error, r);
1ee306e1 428
878cd7e9
LP
429 machine = hashmap_get(m->machines, name);
430 if (!machine)
431 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
432
433 return bus_machine_method_get_addresses(bus, message, machine, error);
c3350683 434}
1ee306e1 435
717603e3
LP
436static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
437 Manager *m = userdata;
438 Machine *machine;
439 const char *name;
440 int r;
441
442 assert(bus);
443 assert(message);
444 assert(m);
445
446 r = sd_bus_message_read(message, "s", &name);
447 if (r < 0)
448 return sd_bus_error_set_errno(error, r);
449
450 machine = hashmap_get(m->machines, name);
451 if (!machine)
452 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
453
454 return bus_machine_method_get_os_release(bus, message, machine, error);
455}
456
cd61c3bf
LP
457static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
458 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
459 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
460 Manager *m = userdata;
461 Image *image;
462 Iterator i;
463 int r;
464
465 assert(bus);
466 assert(message);
467 assert(m);
468
469 images = hashmap_new(&string_hash_ops);
470 if (!images)
471 return -ENOMEM;
472
473 r = image_discover(images);
474 if (r < 0)
475 return r;
476
477 r = sd_bus_message_new_method_return(message, &reply);
478 if (r < 0)
479 return r;
480
b6b18498 481 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
cd61c3bf
LP
482 if (r < 0)
483 return r;
484
485 HASHMAP_FOREACH(image, images, i) {
486 _cleanup_free_ char *p = NULL;
487
488 p = image_bus_path(image->name);
489 if (!p)
490 return -ENOMEM;
491
b6b18498 492 r = sd_bus_message_append(reply, "(ssbttto)",
cd61c3bf
LP
493 image->name,
494 image_type_to_string(image->type),
495 image->read_only,
10f9c755
LP
496 image->crtime,
497 image->mtime,
c19de711 498 image->usage,
cd61c3bf
LP
499 p);
500 if (r < 0)
501 return r;
502 }
503
504 r = sd_bus_message_close_container(reply);
505 if (r < 0)
506 return r;
507
508 return sd_bus_send(bus, reply, NULL);
509}
510
40205d70
LP
511static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
512 Manager *m = userdata;
513 Machine *machine;
514 const char *name;
515 int r;
516
517 assert(bus);
518 assert(message);
519 assert(m);
520
521 r = sd_bus_message_read(message, "s", &name);
522 if (r < 0)
523 return sd_bus_error_set_errno(error, r);
524
525 machine = hashmap_get(m->machines, name);
526 if (!machine)
527 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
528
529 return bus_machine_method_open_pty(bus, message, machine, error);
530}
531
5f8cc96a
LP
532static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
533 Manager *m = userdata;
534 Machine *machine;
535 const char *name;
536 int r;
537
538 assert(bus);
539 assert(message);
540 assert(m);
541
542 r = sd_bus_message_read(message, "s", &name);
543 if (r < 0)
08682124 544 return r;
5f8cc96a
LP
545
546 machine = hashmap_get(m->machines, name);
547 if (!machine)
548 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
549
550 return bus_machine_method_open_login(bus, message, machine, error);
551}
552
90adaa25
LP
553static int method_bind_mount_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
554 Manager *m = userdata;
555 Machine *machine;
556 const char *name;
557 int r;
558
559 assert(bus);
560 assert(message);
561 assert(m);
562
563 r = sd_bus_message_read(message, "s", &name);
564 if (r < 0)
565 return r;
566
567 machine = hashmap_get(m->machines, name);
568 if (!machine)
569 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
570
571 return bus_machine_method_bind_mount(bus, message, machine, error);
572}
573
0370612e
LP
574static int method_copy_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
575 Manager *m = userdata;
576 Machine *machine;
577 const char *name;
578 int r;
579
580 assert(bus);
581 assert(message);
582 assert(m);
583
584 r = sd_bus_message_read(message, "s", &name);
585 if (r < 0)
586 return r;
587
588 machine = hashmap_get(m->machines, name);
589 if (!machine)
590 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
591
592 return bus_machine_method_copy(bus, message, machine, error);
593}
594
08682124
LP
595static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
596 _cleanup_(image_unrefp) Image* i = NULL;
597 const char *name;
598 int r;
599
600 assert(bus);
601 assert(message);
602
603 r = sd_bus_message_read(message, "s", &name);
604 if (r < 0)
605 return r;
606
607 if (!image_name_is_valid(name))
608 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
609
610 r = image_find(name, &i);
611 if (r < 0)
612 return r;
613 if (r == 0)
614 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
615
70244d1d 616 i->userdata = userdata;
1ddb263d 617 return bus_image_method_remove(bus, message, i, error);
08682124
LP
618}
619
ebd93cb6
LP
620static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
621 _cleanup_(image_unrefp) Image* i = NULL;
1ddb263d 622 const char *old_name;
ebd93cb6
LP
623 int r;
624
625 assert(bus);
626 assert(message);
627
1ddb263d 628 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
629 if (r < 0)
630 return r;
631
632 if (!image_name_is_valid(old_name))
633 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
634
635 r = image_find(old_name, &i);
636 if (r < 0)
637 return r;
638 if (r == 0)
639 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
640
70244d1d 641 i->userdata = userdata;
1ddb263d 642 return bus_image_method_rename(bus, message, i, error);
ebd93cb6
LP
643}
644
645static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
646 _cleanup_(image_unrefp) Image *i = NULL;
1ddb263d
LP
647 const char *old_name;
648 int r;
ebd93cb6
LP
649
650 assert(bus);
1ddb263d 651 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
652 if (r < 0)
653 return r;
654
655 if (!image_name_is_valid(old_name))
656 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
657
658 r = image_find(old_name, &i);
659 if (r < 0)
660 return r;
661 if (r == 0)
662 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
663
70244d1d 664 i->userdata = userdata;
1ddb263d 665 return bus_image_method_clone(bus, message, i, error);
ebd93cb6
LP
666}
667
668static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
669 _cleanup_(image_unrefp) Image *i = NULL;
670 const char *name;
1ddb263d 671 int r;
ebd93cb6
LP
672
673 assert(bus);
1ddb263d 674 r = sd_bus_message_read(message, "s", &name);
ebd93cb6
LP
675 if (r < 0)
676 return r;
677
678 if (!image_name_is_valid(name))
679 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
680
681 r = image_find(name, &i);
682 if (r < 0)
683 return r;
684 if (r == 0)
685 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
686
70244d1d 687 i->userdata = userdata;
1ddb263d 688 return bus_image_method_mark_read_only(bus, message, i, error);
ebd93cb6
LP
689}
690
c3350683
LP
691const sd_bus_vtable manager_vtable[] = {
692 SD_BUS_VTABLE_START(0),
adacb957 693 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 694 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
695 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
696 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
b6b18498 697 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 698 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 699 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 700 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 701 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
70244d1d
LP
702 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
703 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
3a6fb33c 704 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 705 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 706 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
d04c1fb8 707 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
708 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
709 SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
710 SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
711 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
712 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
713 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
714 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683
LP
715 SD_BUS_SIGNAL("MachineNew", "so", 0),
716 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
717 SD_BUS_VTABLE_END
718};
1ee306e1 719
ebcf1f97 720int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 721 const char *path, *result, *unit;
1ee306e1 722 Manager *m = userdata;
c3350683
LP
723 Machine *machine;
724 uint32_t id;
725 int r;
1ee306e1 726
c3350683 727 assert(bus);
1ee306e1 728 assert(message);
c3350683 729 assert(m);
1ee306e1 730
c3350683
LP
731 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
732 if (r < 0) {
ebcf1f97
LP
733 bus_log_parse_error(r);
734 return r;
c3350683 735 }
6797c324 736
c3350683
LP
737 machine = hashmap_get(m->machine_units, unit);
738 if (!machine)
739 return 0;
6797c324 740
c3350683
LP
741 if (streq_ptr(path, machine->scope_job)) {
742 free(machine->scope_job);
743 machine->scope_job = NULL;
6797c324 744
c3350683
LP
745 if (machine->started) {
746 if (streq(result, "done"))
747 machine_send_create_reply(machine, NULL);
748 else {
ebcf1f97 749 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 750
ebcf1f97 751 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 752
ebcf1f97 753 machine_send_create_reply(machine, &e);
c3350683
LP
754 }
755 } else
756 machine_save(machine);
1ee306e1
LP
757 }
758
c3350683
LP
759 machine_add_to_gc_queue(machine);
760 return 0;
1ee306e1
LP
761}
762
ebcf1f97 763int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
764 _cleanup_free_ char *unit = NULL;
765 Manager *m = userdata;
766 Machine *machine;
767 const char *path;
ebcf1f97 768 int r;
554604b3 769
c3350683
LP
770 assert(bus);
771 assert(message);
772 assert(m);
554604b3 773
c3350683
LP
774 path = sd_bus_message_get_path(message);
775 if (!path)
554604b3 776 return 0;
554604b3 777
ebcf1f97 778 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
779 if (r == -EINVAL) /* not for a unit */
780 return 0;
ebcf1f97
LP
781 if (r < 0)
782 return r;
554604b3 783
c3350683
LP
784 machine = hashmap_get(m->machine_units, unit);
785 if (machine)
786 machine_add_to_gc_queue(machine);
554604b3 787
c3350683
LP
788 return 0;
789}
554604b3 790
ebcf1f97 791int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
792 const char *path, *unit;
793 Manager *m = userdata;
794 Machine *machine;
795 int r;
554604b3 796
c3350683
LP
797 assert(bus);
798 assert(message);
799 assert(m);
554604b3 800
c3350683
LP
801 r = sd_bus_message_read(message, "so", &unit, &path);
802 if (r < 0) {
ebcf1f97
LP
803 bus_log_parse_error(r);
804 return r;
554604b3
LP
805 }
806
c3350683
LP
807 machine = hashmap_get(m->machine_units, unit);
808 if (machine)
809 machine_add_to_gc_queue(machine);
554604b3 810
c3350683
LP
811 return 0;
812}
554604b3 813
ebcf1f97 814int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 815 Manager *m = userdata;
a658cafa
LP
816 Machine *machine;
817 Iterator i;
c3350683 818 int b, r;
554604b3 819
c3350683 820 assert(bus);
554604b3 821
c3350683
LP
822 r = sd_bus_message_read(message, "b", &b);
823 if (r < 0) {
ebcf1f97
LP
824 bus_log_parse_error(r);
825 return r;
554604b3 826 }
a658cafa
LP
827 if (b)
828 return 0;
554604b3 829
a658cafa
LP
830 /* systemd finished reloading, let's recheck all our machines */
831 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 832
a658cafa
LP
833 HASHMAP_FOREACH(machine, m->machines, i)
834 machine_add_to_gc_queue(machine);
554604b3
LP
835
836 return 0;
837}
838
1ee306e1
LP
839int manager_start_scope(
840 Manager *manager,
841 const char *scope,
842 pid_t pid,
843 const char *slice,
844 const char *description,
c3350683
LP
845 sd_bus_message *more_properties,
846 sd_bus_error *error,
1ee306e1
LP
847 char **job) {
848
c3350683 849 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 850 int r;
1ee306e1
LP
851
852 assert(manager);
853 assert(scope);
854 assert(pid > 1);
855
c3350683
LP
856 r = sd_bus_message_new_method_call(
857 manager->bus,
151b9b96 858 &m,
1ee306e1
LP
859 "org.freedesktop.systemd1",
860 "/org/freedesktop/systemd1",
861 "org.freedesktop.systemd1.Manager",
151b9b96 862 "StartTransientUnit");
c3350683
LP
863 if (r < 0)
864 return r;
1ee306e1 865
a658cafa 866 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
867 if (r < 0)
868 return r;
1ee306e1 869
c3350683
LP
870 r = sd_bus_message_open_container(m, 'a', "(sv)");
871 if (r < 0)
872 return r;
1ee306e1
LP
873
874 if (!isempty(slice)) {
c3350683
LP
875 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
876 if (r < 0)
877 return r;
1ee306e1
LP
878 }
879
880 if (!isempty(description)) {
c3350683
LP
881 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
882 if (r < 0)
883 return r;
1ee306e1
LP
884 }
885
c3350683
LP
886 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
887 if (r < 0)
888 return r;
554604b3 889
a931ad47
LP
890 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
891 if (r < 0)
892 return r;
893
554604b3 894 if (more_properties) {
c3350683 895 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
896 if (r < 0)
897 return r;
898 }
899
c3350683
LP
900 r = sd_bus_message_close_container(m);
901 if (r < 0)
902 return r;
1ee306e1 903
86b8d289
LP
904 r = sd_bus_message_append(m, "a(sa(sv))", 0);
905 if (r < 0)
906 return r;
907
c49b30a2 908 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
909 if (r < 0)
910 return r;
1ee306e1
LP
911
912 if (job) {
913 const char *j;
914 char *copy;
915
c3350683
LP
916 r = sd_bus_message_read(reply, "o", &j);
917 if (r < 0)
918 return r;
1ee306e1
LP
919
920 copy = strdup(j);
921 if (!copy)
922 return -ENOMEM;
923
924 *job = copy;
925 }
926
c3350683 927 return 1;
1ee306e1
LP
928}
929
c3350683
LP
930int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
931 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
932 int r;
933
934 assert(manager);
935 assert(unit);
936
c3350683 937 r = sd_bus_call_method(
1ee306e1
LP
938 manager->bus,
939 "org.freedesktop.systemd1",
940 "/org/freedesktop/systemd1",
941 "org.freedesktop.systemd1.Manager",
942 "StopUnit",
1ee306e1 943 error,
c3350683
LP
944 &reply,
945 "ss", unit, "fail");
1ee306e1 946 if (r < 0) {
c3350683
LP
947 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
948 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
949
950 if (job)
951 *job = NULL;
952
c3350683 953 sd_bus_error_free(error);
6797c324
LP
954 return 0;
955 }
956
1ee306e1
LP
957 return r;
958 }
959
960 if (job) {
961 const char *j;
962 char *copy;
963
c3350683
LP
964 r = sd_bus_message_read(reply, "o", &j);
965 if (r < 0)
966 return r;
1ee306e1
LP
967
968 copy = strdup(j);
969 if (!copy)
970 return -ENOMEM;
971
972 *job = copy;
973 }
974
6797c324 975 return 1;
1ee306e1
LP
976}
977
de58a50e 978int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
979 assert(manager);
980 assert(unit);
981
a658cafa 982 return sd_bus_call_method(
1ee306e1
LP
983 manager->bus,
984 "org.freedesktop.systemd1",
985 "/org/freedesktop/systemd1",
986 "org.freedesktop.systemd1.Manager",
987 "KillUnit",
1ee306e1 988 error,
a658cafa 989 NULL,
de58a50e 990 "ssi", unit, "all", signo);
1ee306e1
LP
991}
992
993int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
994 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
995 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 996 _cleanup_free_ char *path = NULL;
1ee306e1 997 const char *state;
1ee306e1
LP
998 int r;
999
1000 assert(manager);
1001 assert(unit);
1002
1ee306e1
LP
1003 path = unit_dbus_path_from_name(unit);
1004 if (!path)
1005 return -ENOMEM;
1006
c3350683 1007 r = sd_bus_get_property(
1ee306e1
LP
1008 manager->bus,
1009 "org.freedesktop.systemd1",
1010 path,
c3350683
LP
1011 "org.freedesktop.systemd1.Unit",
1012 "ActiveState",
1ee306e1 1013 &error,
c3350683
LP
1014 &reply,
1015 "s");
1ee306e1 1016 if (r < 0) {
c3350683
LP
1017 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1018 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 1019 return true;
6797c324 1020
c3350683
LP
1021 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1022 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 1023 return false;
6797c324 1024
1ee306e1
LP
1025 return r;
1026 }
1027
c3350683
LP
1028 r = sd_bus_message_read(reply, "s", &state);
1029 if (r < 0)
1ee306e1 1030 return -EINVAL;
1ee306e1
LP
1031
1032 return !streq(state, "inactive") && !streq(state, "failed");
1033}
bd16acf3 1034
c3350683
LP
1035int manager_job_is_active(Manager *manager, const char *path) {
1036 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1037 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1038 int r;
bd16acf3 1039
c3350683
LP
1040 assert(manager);
1041 assert(path);
bd16acf3 1042
c3350683
LP
1043 r = sd_bus_get_property(
1044 manager->bus,
1045 "org.freedesktop.systemd1",
1046 path,
1047 "org.freedesktop.systemd1.Job",
1048 "State",
1049 &error,
1050 &reply,
1051 "s");
1052 if (r < 0) {
1053 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1054 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1055 return true;
bd16acf3 1056
c3350683
LP
1057 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1058 return false;
bd16acf3 1059
bd16acf3 1060 return r;
c3350683 1061 }
bd16acf3 1062
c3350683
LP
1063 /* We don't actually care about the state really. The fact
1064 * that we could read the job state is enough for us */
bd16acf3 1065
c3350683 1066 return true;
bd16acf3 1067}
ab49725f
KS
1068
1069int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1070 _cleanup_free_ char *unit = NULL;
1071 Machine *mm;
1072 int r;
1073
1074 assert(m);
1075 assert(pid >= 1);
1076 assert(machine);
1077
1078 r = cg_pid_get_unit(pid, &unit);
1079 if (r < 0)
1080 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1081 else
1082 mm = hashmap_get(m->machine_units, unit);
1083
1084 if (!mm)
1085 return 0;
1086
1087 *machine = mm;
1088 return 1;
1089}
1090
1091int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1092 Machine *machine;
1093
1094 assert(m);
1095 assert(name);
1096
1097 machine = hashmap_get(m->machines, name);
1098 if (!machine) {
1099 machine = machine_new(m, name);
1100 if (!machine)
1101 return -ENOMEM;
1102 }
1103
1104 if (_machine)
1105 *_machine = machine;
1106
1107 return 0;
1108}