]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
util.h: order includes, as suggested by CODING_STYLE
[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"
9b420b3c 27#include "strv.h"
1ee306e1 28#include "path-util.h"
1ee306e1 29#include "unit-name.h"
c3350683 30#include "bus-util.h"
96aad8d1 31#include "bus-common-errors.h"
23c80348 32#include "cgroup-util.h"
160e3793 33#include "btrfs-util.h"
c01ff965
LP
34#include "formats-util.h"
35#include "process-util.h"
25300b5a 36#include "hostname-util.h"
003dffde 37#include "machine-image.h"
4cee5eed 38#include "machine-pool.h"
003dffde 39#include "image-dbus.h"
c3350683 40#include "machined.h"
003dffde 41#include "machine-dbus.h"
1ee306e1 42
160e3793
LP
43static int property_get_pool_path(
44 sd_bus *bus,
45 const char *path,
46 const char *interface,
47 const char *property,
48 sd_bus_message *reply,
49 void *userdata,
50 sd_bus_error *error) {
51
52 assert(bus);
53 assert(reply);
54
55 return sd_bus_message_append(reply, "s", "/var/lib/machines");
56}
57
58static int property_get_pool_usage(
59 sd_bus *bus,
60 const char *path,
61 const char *interface,
62 const char *property,
63 sd_bus_message *reply,
64 void *userdata,
65 sd_bus_error *error) {
66
67 _cleanup_close_ int fd = -1;
68 uint64_t usage = (uint64_t) -1;
69 struct stat st;
70
71 assert(bus);
72 assert(reply);
73
74 /* We try to read the quota info from /var/lib/machines, as
75 * well as the usage of the loopback file
76 * /var/lib/machines.raw, and pick the larger value. */
77
78 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
79 if (fd >= 0) {
80 BtrfsQuotaInfo q;
81
82 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
cb81cd80 83 usage = q.referenced;
160e3793
LP
84 }
85
86 if (stat("/var/lib/machines.raw", &st) >= 0) {
87 if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
88 usage = st.st_blocks * 512ULL;
89 }
90
91 return sd_bus_message_append(reply, "t", usage);
92}
93
94static int property_get_pool_limit(
95 sd_bus *bus,
96 const char *path,
97 const char *interface,
98 const char *property,
99 sd_bus_message *reply,
100 void *userdata,
101 sd_bus_error *error) {
102
103 _cleanup_close_ int fd = -1;
104 uint64_t size = (uint64_t) -1;
105 struct stat st;
106
107 assert(bus);
108 assert(reply);
109
110 /* We try to read the quota limit from /var/lib/machines, as
111 * well as the size of the loopback file
112 * /var/lib/machines.raw, and pick the smaller value. */
113
114 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
115 if (fd >= 0) {
116 BtrfsQuotaInfo q;
117
118 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
cb81cd80 119 size = q.referenced_max;
160e3793
LP
120 }
121
122 if (stat("/var/lib/machines.raw", &st) >= 0) {
123 if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
124 size = st.st_size;
125 }
126
127 return sd_bus_message_append(reply, "t", size);
128}
129
19070062 130static int method_get_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
131 _cleanup_free_ char *p = NULL;
132 Manager *m = userdata;
133 Machine *machine;
134 const char *name;
135 int r;
136
c3350683
LP
137 assert(message);
138 assert(m);
139
140 r = sd_bus_message_read(message, "s", &name);
141 if (r < 0)
ebcf1f97 142 return r;
c3350683
LP
143
144 machine = hashmap_get(m->machines, name);
145 if (!machine)
ebcf1f97 146 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
c3350683
LP
147
148 p = machine_bus_path(machine);
149 if (!p)
ebcf1f97 150 return -ENOMEM;
c3350683 151
df2d202e 152 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
153}
154
19070062 155static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c2ce6a3d
LP
156 _cleanup_free_ char *p = NULL;
157 Manager *m = userdata;
158 const char *name;
159 int r;
160
c2ce6a3d
LP
161 assert(message);
162 assert(m);
163
164 r = sd_bus_message_read(message, "s", &name);
165 if (r < 0)
166 return r;
167
168 r = image_find(name, NULL);
169 if (r == 0)
170 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
171 if (r < 0)
172 return r;
173
174 p = image_bus_path(name);
175 if (!p)
176 return -ENOMEM;
177
178 return sd_bus_reply_method_return(message, "o", p);
179}
180
19070062 181static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
182 _cleanup_free_ char *p = NULL;
183 Manager *m = userdata;
184 Machine *machine = NULL;
4e724d9c 185 pid_t pid;
c3350683
LP
186 int r;
187
c3350683
LP
188 assert(message);
189 assert(m);
190
4e724d9c
LP
191 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
192
c3350683
LP
193 r = sd_bus_message_read(message, "u", &pid);
194 if (r < 0)
ebcf1f97 195 return r;
c3350683 196
4e724d9c 197 if (pid == 0) {
5b12334d
LP
198 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
199
200 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
201 if (r < 0)
202 return r;
203
204 r = sd_bus_creds_get_pid(creds, &pid);
4e724d9c 205 if (r < 0)
ebcf1f97 206 return r;
4e724d9c
LP
207 }
208
c3350683
LP
209 r = manager_get_machine_by_pid(m, pid, &machine);
210 if (r < 0)
ebcf1f97 211 return r;
c3350683 212 if (!machine)
de0671ee 213 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
214
215 p = machine_bus_path(machine);
216 if (!p)
ebcf1f97 217 return -ENOMEM;
c3350683 218
df2d202e 219 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
220}
221
19070062 222static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
223 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
224 Manager *m = userdata;
225 Machine *machine;
226 Iterator i;
227 int r;
228
c3350683
LP
229 assert(message);
230 assert(m);
231
df2d202e 232 r = sd_bus_message_new_method_return(message, &reply);
c3350683 233 if (r < 0)
ebcf1f97 234 return sd_bus_error_set_errno(error, r);
c3350683
LP
235
236 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
237 if (r < 0)
ebcf1f97 238 return sd_bus_error_set_errno(error, r);
c3350683
LP
239
240 HASHMAP_FOREACH(machine, m->machines, i) {
241 _cleanup_free_ char *p = NULL;
242
243 p = machine_bus_path(machine);
244 if (!p)
ebcf1f97 245 return -ENOMEM;
c3350683
LP
246
247 r = sd_bus_message_append(reply, "(ssso)",
248 machine->name,
249 strempty(machine_class_to_string(machine->class)),
250 machine->service,
251 p);
252 if (r < 0)
ebcf1f97 253 return sd_bus_error_set_errno(error, r);
c3350683 254 }
1ee306e1 255
c3350683
LP
256 r = sd_bus_message_close_container(reply);
257 if (r < 0)
ebcf1f97 258 return sd_bus_error_set_errno(error, r);
c3350683 259
9030ca46 260 return sd_bus_send(NULL, reply, NULL);
c3350683
LP
261}
262
9b5ed6fe 263static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
8aec412f 264 const char *name, *service, *class, *root_directory;
9b5ed6fe 265 const int32_t *netif = NULL;
1ee306e1
LP
266 MachineClass c;
267 uint32_t leader;
268 sd_id128_t id;
c3350683 269 const void *v;
1ee306e1 270 Machine *m;
9b5ed6fe 271 size_t n, n_netif = 0;
c3350683 272 int r;
1ee306e1 273
c3350683 274 assert(manager);
89f7c846
LP
275 assert(message);
276 assert(_m);
1ee306e1 277
c3350683
LP
278 r = sd_bus_message_read(message, "s", &name);
279 if (r < 0)
ebcf1f97 280 return r;
7f0d207d 281 if (!machine_name_is_valid(name))
ebcf1f97 282 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 283
c3350683
LP
284 r = sd_bus_message_read_array(message, 'y', &v, &n);
285 if (r < 0)
ebcf1f97 286 return r;
1ee306e1
LP
287 if (n == 0)
288 id = SD_ID128_NULL;
289 else if (n == 16)
290 memcpy(&id, v, n);
291 else
ebcf1f97 292 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 293
c3350683
LP
294 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
295 if (r < 0)
ebcf1f97 296 return r;
1ee306e1 297
9b5ed6fe
LP
298 if (read_network) {
299 size_t i;
300
301 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
302 if (r < 0)
303 return r;
304
305 n_netif /= sizeof(int32_t);
306
307 for (i = 0; i < n_netif; i++) {
308 if (netif[i] <= 0)
309 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
310 }
311 }
312
1ee306e1
LP
313 if (isempty(class))
314 c = _MACHINE_CLASS_INVALID;
315 else {
316 c = machine_class_from_string(class);
317 if (c < 0)
ebcf1f97 318 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
319 }
320
c3350683 321 if (leader == 1)
ebcf1f97 322 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 323
c3350683 324 if (!isempty(root_directory) && !path_is_absolute(root_directory))
ebcf1f97 325 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 326
c3350683 327 if (leader == 0) {
5b12334d
LP
328 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
329
330 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
331 if (r < 0)
332 return r;
333
c3350683 334 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
554604b3 335
5b12334d 336 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c3350683 337 if (r < 0)
ebcf1f97 338 return r;
c3350683 339 }
554604b3 340
1ee306e1 341 if (hashmap_get(manager->machines, name))
ebcf1f97 342 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1
LP
343
344 r = manager_add_machine(manager, name, &m);
345 if (r < 0)
ebcf1f97 346 return r;
1ee306e1
LP
347
348 m->leader = leader;
349 m->class = c;
350 m->id = id;
351
352 if (!isempty(service)) {
353 m->service = strdup(service);
354 if (!m->service) {
ebcf1f97 355 r = -ENOMEM;
1ee306e1
LP
356 goto fail;
357 }
358 }
359
360 if (!isempty(root_directory)) {
361 m->root_directory = strdup(root_directory);
362 if (!m->root_directory) {
ebcf1f97 363 r = -ENOMEM;
1ee306e1
LP
364 goto fail;
365 }
366 }
367
9b5ed6fe
LP
368 if (n_netif > 0) {
369 assert_cc(sizeof(int32_t) == sizeof(int));
370 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
371 if (!m->netif) {
372 r = -ENOMEM;
373 goto fail;
374 }
375
376 m->n_netif = n_netif;
377 }
378
89f7c846
LP
379 *_m = m;
380
381 return 1;
382
383fail:
384 machine_add_to_gc_queue(m);
385 return r;
386}
387
19070062 388static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
389 Manager *manager = userdata;
390 Machine *m = NULL;
391 int r;
392
19070062
LP
393 assert(message);
394 assert(manager);
395
9b5ed6fe 396 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
397 if (r < 0)
398 return r;
399
400 r = sd_bus_message_enter_container(message, 'a', "(sv)");
401 if (r < 0)
402 goto fail;
403
ebcf1f97
LP
404 r = machine_start(m, message, error);
405 if (r < 0)
1ee306e1
LP
406 goto fail;
407
c3350683 408 m->create_message = sd_bus_message_ref(message);
c3350683 409 return 1;
1ee306e1
LP
410
411fail:
a3e7f417 412 machine_add_to_gc_queue(m);
89f7c846
LP
413 return r;
414}
1ee306e1 415
19070062
LP
416static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
417 return method_create_machine_internal(message, true, userdata, error);
9b5ed6fe
LP
418}
419
19070062
LP
420static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
421 return method_create_machine_internal(message, false, userdata, error);
9b5ed6fe
LP
422}
423
19070062 424static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
425 Manager *manager = userdata;
426 _cleanup_free_ char *p = NULL;
427 Machine *m = NULL;
428 int r;
429
19070062
LP
430 assert(message);
431 assert(manager);
432
9b5ed6fe 433 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
434 if (r < 0)
435 return r;
436
437 r = cg_pid_get_unit(m->leader, &m->unit);
438 if (r < 0) {
439 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
440 goto fail;
441 }
442
443 r = machine_start(m, NULL, error);
444 if (r < 0)
445 goto fail;
446
447 p = machine_bus_path(m);
448 if (!p) {
449 r = -ENOMEM;
450 goto fail;
451 }
452
453 return sd_bus_reply_method_return(message, "o", p);
454
455fail:
456 machine_add_to_gc_queue(m);
1ee306e1
LP
457 return r;
458}
459
19070062
LP
460static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
461 return method_register_machine_internal(message, true, userdata, error);
9b5ed6fe
LP
462}
463
19070062
LP
464static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
465 return method_register_machine_internal(message, false, userdata, error);
9b5ed6fe
LP
466}
467
19070062 468static int method_terminate_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 469 Manager *m = userdata;
c3350683
LP
470 Machine *machine;
471 const char *name;
1ee306e1
LP
472 int r;
473
1ee306e1
LP
474 assert(message);
475 assert(m);
476
c3350683
LP
477 r = sd_bus_message_read(message, "s", &name);
478 if (r < 0)
ebcf1f97 479 return sd_bus_error_set_errno(error, r);
1ee306e1 480
c3350683
LP
481 machine = hashmap_get(m->machines, name);
482 if (!machine)
ebcf1f97 483 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 484
19070062 485 return bus_machine_method_terminate(message, machine, error);
c3350683 486}
1ee306e1 487
19070062 488static int method_kill_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
489 Manager *m = userdata;
490 Machine *machine;
491 const char *name;
c3350683 492 int r;
1ee306e1 493
c3350683
LP
494 assert(message);
495 assert(m);
1ee306e1 496
878cd7e9 497 r = sd_bus_message_read(message, "s", &name);
c3350683 498 if (r < 0)
ebcf1f97 499 return sd_bus_error_set_errno(error, r);
1ee306e1 500
c3350683
LP
501 machine = hashmap_get(m->machines, name);
502 if (!machine)
ebcf1f97 503 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 504
19070062 505 return bus_machine_method_kill(message, machine, error);
878cd7e9
LP
506}
507
19070062 508static int method_get_machine_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
878cd7e9
LP
509 Manager *m = userdata;
510 Machine *machine;
511 const char *name;
512 int r;
513
878cd7e9
LP
514 assert(message);
515 assert(m);
516
517 r = sd_bus_message_read(message, "s", &name);
c3350683 518 if (r < 0)
ebcf1f97 519 return sd_bus_error_set_errno(error, r);
1ee306e1 520
878cd7e9
LP
521 machine = hashmap_get(m->machines, name);
522 if (!machine)
523 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
524
19070062 525 return bus_machine_method_get_addresses(message, machine, error);
c3350683 526}
1ee306e1 527
19070062 528static int method_get_machine_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
717603e3
LP
529 Manager *m = userdata;
530 Machine *machine;
531 const char *name;
532 int r;
533
717603e3
LP
534 assert(message);
535 assert(m);
536
537 r = sd_bus_message_read(message, "s", &name);
538 if (r < 0)
539 return sd_bus_error_set_errno(error, r);
540
541 machine = hashmap_get(m->machines, name);
542 if (!machine)
543 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
544
19070062 545 return bus_machine_method_get_os_release(message, machine, error);
717603e3
LP
546}
547
19070062 548static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cd61c3bf
LP
549 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
550 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
551 Manager *m = userdata;
552 Image *image;
553 Iterator i;
554 int r;
555
cd61c3bf
LP
556 assert(message);
557 assert(m);
558
559 images = hashmap_new(&string_hash_ops);
560 if (!images)
561 return -ENOMEM;
562
563 r = image_discover(images);
564 if (r < 0)
565 return r;
566
567 r = sd_bus_message_new_method_return(message, &reply);
568 if (r < 0)
569 return r;
570
b6b18498 571 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
cd61c3bf
LP
572 if (r < 0)
573 return r;
574
575 HASHMAP_FOREACH(image, images, i) {
576 _cleanup_free_ char *p = NULL;
577
578 p = image_bus_path(image->name);
579 if (!p)
580 return -ENOMEM;
581
b6b18498 582 r = sd_bus_message_append(reply, "(ssbttto)",
cd61c3bf
LP
583 image->name,
584 image_type_to_string(image->type),
585 image->read_only,
10f9c755
LP
586 image->crtime,
587 image->mtime,
c19de711 588 image->usage,
cd61c3bf
LP
589 p);
590 if (r < 0)
591 return r;
592 }
593
594 r = sd_bus_message_close_container(reply);
595 if (r < 0)
596 return r;
597
9030ca46 598 return sd_bus_send(NULL, reply, NULL);
cd61c3bf
LP
599}
600
19070062 601static int method_open_machine_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
40205d70
LP
602 Manager *m = userdata;
603 Machine *machine;
604 const char *name;
605 int r;
606
40205d70
LP
607 assert(message);
608 assert(m);
609
610 r = sd_bus_message_read(message, "s", &name);
611 if (r < 0)
612 return sd_bus_error_set_errno(error, r);
613
614 machine = hashmap_get(m->machines, name);
615 if (!machine)
616 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
617
19070062 618 return bus_machine_method_open_pty(message, machine, error);
40205d70
LP
619}
620
19070062 621static int method_open_machine_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
5f8cc96a
LP
622 Manager *m = userdata;
623 Machine *machine;
624 const char *name;
625 int r;
626
5f8cc96a
LP
627 assert(message);
628 assert(m);
629
630 r = sd_bus_message_read(message, "s", &name);
631 if (r < 0)
08682124 632 return r;
5f8cc96a
LP
633
634 machine = hashmap_get(m->machines, name);
635 if (!machine)
636 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
637
19070062 638 return bus_machine_method_open_login(message, machine, error);
5f8cc96a
LP
639}
640
49af9e13
LP
641static int method_open_machine_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
642 Manager *m = userdata;
643 Machine *machine;
644 const char *name;
645
646 int r;
647
648 assert(message);
649 assert(m);
650
651 r = sd_bus_message_read(message, "s", &name);
652 if (r < 0)
653 return r;
654
655 machine = hashmap_get(m->machines, name);
656 if (!machine)
657 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
658
659 return bus_machine_method_open_shell(message, machine, error);
660}
661
19070062 662static int method_bind_mount_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
90adaa25
LP
663 Manager *m = userdata;
664 Machine *machine;
665 const char *name;
666 int r;
667
90adaa25
LP
668 assert(message);
669 assert(m);
670
671 r = sd_bus_message_read(message, "s", &name);
672 if (r < 0)
673 return r;
674
675 machine = hashmap_get(m->machines, name);
676 if (!machine)
677 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
678
19070062 679 return bus_machine_method_bind_mount(message, machine, error);
90adaa25
LP
680}
681
19070062 682static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
0370612e
LP
683 Manager *m = userdata;
684 Machine *machine;
685 const char *name;
686 int r;
687
0370612e
LP
688 assert(message);
689 assert(m);
690
691 r = sd_bus_message_read(message, "s", &name);
692 if (r < 0)
693 return r;
694
695 machine = hashmap_get(m->machines, name);
696 if (!machine)
697 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
698
19070062 699 return bus_machine_method_copy(message, machine, error);
0370612e
LP
700}
701
19070062 702static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
08682124
LP
703 _cleanup_(image_unrefp) Image* i = NULL;
704 const char *name;
705 int r;
706
08682124
LP
707 assert(message);
708
709 r = sd_bus_message_read(message, "s", &name);
710 if (r < 0)
711 return r;
712
713 if (!image_name_is_valid(name))
714 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
715
716 r = image_find(name, &i);
717 if (r < 0)
718 return r;
719 if (r == 0)
720 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
721
70244d1d 722 i->userdata = userdata;
19070062 723 return bus_image_method_remove(message, i, error);
08682124
LP
724}
725
19070062 726static int method_rename_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ebd93cb6 727 _cleanup_(image_unrefp) Image* i = NULL;
1ddb263d 728 const char *old_name;
ebd93cb6
LP
729 int r;
730
ebd93cb6
LP
731 assert(message);
732
1ddb263d 733 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
734 if (r < 0)
735 return r;
736
737 if (!image_name_is_valid(old_name))
738 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
739
740 r = image_find(old_name, &i);
741 if (r < 0)
742 return r;
743 if (r == 0)
744 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
745
70244d1d 746 i->userdata = userdata;
19070062 747 return bus_image_method_rename(message, i, error);
ebd93cb6
LP
748}
749
19070062 750static int method_clone_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ebd93cb6 751 _cleanup_(image_unrefp) Image *i = NULL;
1ddb263d
LP
752 const char *old_name;
753 int r;
ebd93cb6 754
19070062
LP
755 assert(message);
756
1ddb263d 757 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
758 if (r < 0)
759 return r;
760
761 if (!image_name_is_valid(old_name))
762 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
763
764 r = image_find(old_name, &i);
765 if (r < 0)
766 return r;
767 if (r == 0)
768 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
769
70244d1d 770 i->userdata = userdata;
19070062 771 return bus_image_method_clone(message, i, error);
ebd93cb6
LP
772}
773
19070062 774static int method_mark_image_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ebd93cb6
LP
775 _cleanup_(image_unrefp) Image *i = NULL;
776 const char *name;
1ddb263d 777 int r;
ebd93cb6 778
19070062
LP
779 assert(message);
780
1ddb263d 781 r = sd_bus_message_read(message, "s", &name);
ebd93cb6
LP
782 if (r < 0)
783 return r;
784
785 if (!image_name_is_valid(name))
786 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
787
788 r = image_find(name, &i);
789 if (r < 0)
790 return r;
791 if (r == 0)
792 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
793
70244d1d 794 i->userdata = userdata;
19070062 795 return bus_image_method_mark_read_only(message, i, error);
ebd93cb6
LP
796}
797
19070062 798static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d6ce17c7
LP
799 Manager *m = userdata;
800 uint64_t limit;
801 int r;
802
19070062
LP
803 assert(message);
804
d6ce17c7
LP
805 r = sd_bus_message_read(message, "t", &limit);
806 if (r < 0)
807 return r;
808
809 r = bus_verify_polkit_async(
810 message,
811 CAP_SYS_ADMIN,
812 "org.freedesktop.machine1.manage-machines",
403ed0e5 813 NULL,
d6ce17c7
LP
814 false,
815 UID_INVALID,
816 &m->polkit_registry,
817 error);
818 if (r < 0)
819 return r;
820 if (r == 0)
821 return 1; /* Will call us back */
822
4cee5eed
LP
823 /* Set up the machine directory if necessary */
824 r = setup_machine_directory(limit, error);
825 if (r < 0)
826 return r;
827
26166c88
LP
828 r = btrfs_resize_loopback("/var/lib/machines", limit, false);
829 if (r == -ENOTTY)
830 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
831 if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
efe02862
LP
832 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
833
d6ce17c7
LP
834 r = btrfs_quota_limit("/var/lib/machines", limit);
835 if (r == -ENOTTY)
836 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
26166c88 837 if (r < 0)
d6ce17c7
LP
838 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
839
840 return sd_bus_reply_method_return(message, NULL);
841}
842
19070062 843static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d6ce17c7
LP
844 _cleanup_(image_unrefp) Image *i = NULL;
845 const char *name;
846 int r;
847
19070062
LP
848 assert(message);
849
d6ce17c7
LP
850 r = sd_bus_message_read(message, "s", &name);
851 if (r < 0)
852 return r;
853
854 if (!image_name_is_valid(name))
855 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
856
857 r = image_find(name, &i);
858 if (r < 0)
859 return r;
860 if (r == 0)
861 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
862
863 i->userdata = userdata;
19070062 864 return bus_image_method_set_limit(message, i, error);
d6ce17c7
LP
865}
866
c01ff965
LP
867static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
868 _cleanup_fclose_ FILE *f = NULL;
869 Manager *m = userdata;
870 const char *name, *p;
871 Machine *machine;
872 uint32_t uid;
873 int r;
874
875 r = sd_bus_message_read(message, "su", &name, &uid);
876 if (r < 0)
877 return r;
878
879 if (UID_IS_INVALID(uid))
880 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
881
882 machine = hashmap_get(m->machines, name);
883 if (!machine)
884 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
885
a79366e2
LP
886 if (machine->class != MACHINE_CONTAINER)
887 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
888
c01ff965
LP
889 p = procfs_file_alloca(machine->leader, "uid_map");
890 f = fopen(p, "re");
891 if (!f)
892 return -errno;
893
894 for (;;) {
895 uid_t uid_base, uid_shift, uid_range, converted;
896 int k;
897
898 errno = 0;
899 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
900 if (k < 0 && feof(f))
901 break;
902 if (k != 3) {
903 if (ferror(f) && errno != 0)
904 return -errno;
905
906 return -EIO;
907 }
908
909 if (uid < uid_base || uid >= uid_base + uid_range)
910 continue;
911
912 converted = uid - uid_base + uid_shift;
913 if (UID_IS_INVALID(converted))
914 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
915
916 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
917 }
918
919 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
920}
921
922static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
923 Manager *m = userdata;
924 Machine *machine;
925 uid_t uid;
926 Iterator i;
927 int r;
928
929 r = sd_bus_message_read(message, "u", &uid);
930 if (r < 0)
931 return r;
932 if (UID_IS_INVALID(uid))
933 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
934 if (uid < 0x10000)
935 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
936
937 HASHMAP_FOREACH(machine, m->machines, i) {
938 _cleanup_fclose_ FILE *f = NULL;
939 char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
940
a79366e2
LP
941 if (machine->class != MACHINE_CONTAINER)
942 continue;
943
c01ff965
LP
944 xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
945 f = fopen(p, "re");
946 if (!f) {
947 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
948 continue;
949 }
950
951 for (;;) {
952 _cleanup_free_ char *o = NULL;
953 uid_t uid_base, uid_shift, uid_range, converted;
954 int k;
955
956 errno = 0;
957 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
958 if (k < 0 && feof(f))
959 break;
960 if (k != 3) {
961 if (ferror(f) && errno != 0)
962 return -errno;
963
964 return -EIO;
965 }
966
967 if (uid < uid_shift || uid >= uid_shift + uid_range)
968 continue;
969
970 converted = (uid - uid_shift + uid_base);
971 if (UID_IS_INVALID(converted))
972 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
973
974 o = machine_bus_path(machine);
975 if (!o)
976 return -ENOMEM;
977
978 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
979 }
980 }
981
982 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
983}
984
985static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
986 _cleanup_fclose_ FILE *f = NULL;
987 Manager *m = groupdata;
988 const char *name, *p;
989 Machine *machine;
990 uint32_t gid;
991 int r;
992
993 r = sd_bus_message_read(message, "su", &name, &gid);
994 if (r < 0)
995 return r;
996
997 if (GID_IS_INVALID(gid))
998 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
999
1000 machine = hashmap_get(m->machines, name);
1001 if (!machine)
1002 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1003
a79366e2
LP
1004 if (machine->class != MACHINE_CONTAINER)
1005 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
1006
c01ff965
LP
1007 p = procfs_file_alloca(machine->leader, "gid_map");
1008 f = fopen(p, "re");
1009 if (!f)
1010 return -errno;
1011
1012 for (;;) {
1013 gid_t gid_base, gid_shift, gid_range, converted;
1014 int k;
1015
1016 errno = 0;
1017 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1018 if (k < 0 && feof(f))
1019 break;
1020 if (k != 3) {
1021 if (ferror(f) && errno != 0)
1022 return -errno;
1023
1024 return -EIO;
1025 }
1026
1027 if (gid < gid_base || gid >= gid_base + gid_range)
1028 continue;
1029
1030 converted = gid - gid_base + gid_shift;
1031 if (GID_IS_INVALID(converted))
1032 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1033
1034 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
1035 }
1036
1037 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
1038}
1039
1040static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
1041 Manager *m = groupdata;
1042 Machine *machine;
1043 gid_t gid;
1044 Iterator i;
1045 int r;
1046
1047 r = sd_bus_message_read(message, "u", &gid);
1048 if (r < 0)
1049 return r;
1050 if (GID_IS_INVALID(gid))
1051 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1052 if (gid < 0x10000)
1053 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
1054
1055 HASHMAP_FOREACH(machine, m->machines, i) {
1056 _cleanup_fclose_ FILE *f = NULL;
1057 char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
1058
a79366e2
LP
1059 if (machine->class != MACHINE_CONTAINER)
1060 continue;
1061
c01ff965
LP
1062 xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
1063 f = fopen(p, "re");
1064 if (!f) {
1065 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
1066 continue;
1067 }
1068
1069 for (;;) {
1070 _cleanup_free_ char *o = NULL;
1071 gid_t gid_base, gid_shift, gid_range, converted;
1072 int k;
1073
1074 errno = 0;
1075 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1076 if (k < 0 && feof(f))
1077 break;
1078 if (k != 3) {
1079 if (ferror(f) && errno != 0)
1080 return -errno;
1081
1082 return -EIO;
1083 }
1084
1085 if (gid < gid_shift || gid >= gid_shift + gid_range)
1086 continue;
1087
1088 converted = (gid - gid_shift + gid_base);
1089 if (GID_IS_INVALID(converted))
1090 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1091
1092 o = machine_bus_path(machine);
1093 if (!o)
1094 return -ENOMEM;
1095
1096 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
1097 }
1098 }
1099
1100 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
1101}
1102
c3350683
LP
1103const sd_bus_vtable manager_vtable[] = {
1104 SD_BUS_VTABLE_START(0),
160e3793
LP
1105 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
1106 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
1107 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
adacb957 1108 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 1109 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
1110 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
1111 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
b6b18498 1112 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 1113 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 1114 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 1115 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 1116 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
70244d1d
LP
1117 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1118 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
3a6fb33c 1119 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1120 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 1121 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
d04c1fb8 1122 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
49af9e13 1123 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
1124 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1125 SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1126 SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1127 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
1128 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
1129 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
1130 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
d6ce17c7
LP
1131 SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
1132 SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
c01ff965
LP
1133 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1134 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1135 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
1136 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683
LP
1137 SD_BUS_SIGNAL("MachineNew", "so", 0),
1138 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1139 SD_BUS_VTABLE_END
1140};
1ee306e1 1141
19070062 1142int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1143 const char *path, *result, *unit;
1ee306e1 1144 Manager *m = userdata;
c3350683
LP
1145 Machine *machine;
1146 uint32_t id;
1147 int r;
1ee306e1 1148
1ee306e1 1149 assert(message);
c3350683 1150 assert(m);
1ee306e1 1151
c3350683
LP
1152 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
1153 if (r < 0) {
ebcf1f97 1154 bus_log_parse_error(r);
65d73cf0 1155 return 0;
c3350683 1156 }
6797c324 1157
c3350683
LP
1158 machine = hashmap_get(m->machine_units, unit);
1159 if (!machine)
1160 return 0;
6797c324 1161
c3350683 1162 if (streq_ptr(path, machine->scope_job)) {
491ac9f2 1163 machine->scope_job = mfree(machine->scope_job);
6797c324 1164
c3350683
LP
1165 if (machine->started) {
1166 if (streq(result, "done"))
1167 machine_send_create_reply(machine, NULL);
1168 else {
ebcf1f97 1169 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 1170
ebcf1f97 1171 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 1172
ebcf1f97 1173 machine_send_create_reply(machine, &e);
c3350683 1174 }
49f3fffd
LP
1175 }
1176
1177 machine_save(machine);
1ee306e1
LP
1178 }
1179
c3350683
LP
1180 machine_add_to_gc_queue(machine);
1181 return 0;
1ee306e1
LP
1182}
1183
19070062 1184int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1185 _cleanup_free_ char *unit = NULL;
49f3fffd 1186 const char *path;
c3350683
LP
1187 Manager *m = userdata;
1188 Machine *machine;
ebcf1f97 1189 int r;
554604b3 1190
c3350683
LP
1191 assert(message);
1192 assert(m);
554604b3 1193
c3350683
LP
1194 path = sd_bus_message_get_path(message);
1195 if (!path)
554604b3 1196 return 0;
554604b3 1197
ebcf1f97 1198 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
1199 if (r == -EINVAL) /* not for a unit */
1200 return 0;
9b420b3c
LP
1201 if (r < 0){
1202 log_oom();
1203 return 0;
1204 }
554604b3 1205
c3350683 1206 machine = hashmap_get(m->machine_units, unit);
9b420b3c
LP
1207 if (!machine)
1208 return 0;
1209
9b420b3c 1210 machine_add_to_gc_queue(machine);
c3350683
LP
1211 return 0;
1212}
554604b3 1213
19070062 1214int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
1215 const char *path, *unit;
1216 Manager *m = userdata;
1217 Machine *machine;
1218 int r;
554604b3 1219
c3350683
LP
1220 assert(message);
1221 assert(m);
554604b3 1222
c3350683
LP
1223 r = sd_bus_message_read(message, "so", &unit, &path);
1224 if (r < 0) {
ebcf1f97 1225 bus_log_parse_error(r);
9b420b3c 1226 return 0;
554604b3
LP
1227 }
1228
c3350683 1229 machine = hashmap_get(m->machine_units, unit);
9b420b3c
LP
1230 if (!machine)
1231 return 0;
1232
9b420b3c 1233 machine_add_to_gc_queue(machine);
c3350683
LP
1234 return 0;
1235}
554604b3 1236
19070062 1237int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1238 Manager *m = userdata;
a658cafa
LP
1239 Machine *machine;
1240 Iterator i;
c3350683 1241 int b, r;
554604b3 1242
19070062
LP
1243 assert(message);
1244 assert(m);
554604b3 1245
c3350683
LP
1246 r = sd_bus_message_read(message, "b", &b);
1247 if (r < 0) {
ebcf1f97 1248 bus_log_parse_error(r);
65d73cf0 1249 return 0;
554604b3 1250 }
a658cafa
LP
1251 if (b)
1252 return 0;
554604b3 1253
a658cafa
LP
1254 /* systemd finished reloading, let's recheck all our machines */
1255 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 1256
a658cafa
LP
1257 HASHMAP_FOREACH(machine, m->machines, i)
1258 machine_add_to_gc_queue(machine);
554604b3
LP
1259
1260 return 0;
1261}
1262
1ee306e1
LP
1263int manager_start_scope(
1264 Manager *manager,
1265 const char *scope,
1266 pid_t pid,
1267 const char *slice,
1268 const char *description,
c3350683
LP
1269 sd_bus_message *more_properties,
1270 sd_bus_error *error,
1ee306e1
LP
1271 char **job) {
1272
c3350683 1273 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 1274 int r;
1ee306e1
LP
1275
1276 assert(manager);
1277 assert(scope);
1278 assert(pid > 1);
1279
c3350683
LP
1280 r = sd_bus_message_new_method_call(
1281 manager->bus,
151b9b96 1282 &m,
1ee306e1
LP
1283 "org.freedesktop.systemd1",
1284 "/org/freedesktop/systemd1",
1285 "org.freedesktop.systemd1.Manager",
151b9b96 1286 "StartTransientUnit");
c3350683
LP
1287 if (r < 0)
1288 return r;
1ee306e1 1289
a658cafa 1290 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
1291 if (r < 0)
1292 return r;
1ee306e1 1293
c3350683
LP
1294 r = sd_bus_message_open_container(m, 'a', "(sv)");
1295 if (r < 0)
1296 return r;
1ee306e1
LP
1297
1298 if (!isempty(slice)) {
c3350683
LP
1299 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1300 if (r < 0)
1301 return r;
1ee306e1
LP
1302 }
1303
1304 if (!isempty(description)) {
c3350683
LP
1305 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1306 if (r < 0)
1307 return r;
1ee306e1
LP
1308 }
1309
c3350683
LP
1310 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1311 if (r < 0)
1312 return r;
554604b3 1313
a931ad47
LP
1314 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1315 if (r < 0)
1316 return r;
1317
554604b3 1318 if (more_properties) {
c3350683 1319 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
1320 if (r < 0)
1321 return r;
1322 }
1323
c3350683
LP
1324 r = sd_bus_message_close_container(m);
1325 if (r < 0)
1326 return r;
1ee306e1 1327
86b8d289
LP
1328 r = sd_bus_message_append(m, "a(sa(sv))", 0);
1329 if (r < 0)
1330 return r;
1331
c49b30a2 1332 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
1333 if (r < 0)
1334 return r;
1ee306e1
LP
1335
1336 if (job) {
1337 const char *j;
1338 char *copy;
1339
c3350683
LP
1340 r = sd_bus_message_read(reply, "o", &j);
1341 if (r < 0)
1342 return r;
1ee306e1
LP
1343
1344 copy = strdup(j);
1345 if (!copy)
1346 return -ENOMEM;
1347
1348 *job = copy;
1349 }
1350
c3350683 1351 return 1;
1ee306e1
LP
1352}
1353
c3350683
LP
1354int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
1355 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
1356 int r;
1357
1358 assert(manager);
1359 assert(unit);
1360
c3350683 1361 r = sd_bus_call_method(
1ee306e1
LP
1362 manager->bus,
1363 "org.freedesktop.systemd1",
1364 "/org/freedesktop/systemd1",
1365 "org.freedesktop.systemd1.Manager",
1366 "StopUnit",
1ee306e1 1367 error,
c3350683
LP
1368 &reply,
1369 "ss", unit, "fail");
1ee306e1 1370 if (r < 0) {
c3350683
LP
1371 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1372 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
1373
1374 if (job)
1375 *job = NULL;
1376
c3350683 1377 sd_bus_error_free(error);
6797c324
LP
1378 return 0;
1379 }
1380
1ee306e1
LP
1381 return r;
1382 }
1383
1384 if (job) {
1385 const char *j;
1386 char *copy;
1387
c3350683
LP
1388 r = sd_bus_message_read(reply, "o", &j);
1389 if (r < 0)
1390 return r;
1ee306e1
LP
1391
1392 copy = strdup(j);
1393 if (!copy)
1394 return -ENOMEM;
1395
1396 *job = copy;
1397 }
1398
6797c324 1399 return 1;
1ee306e1
LP
1400}
1401
de58a50e 1402int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
1403 assert(manager);
1404 assert(unit);
1405
a658cafa 1406 return sd_bus_call_method(
1ee306e1
LP
1407 manager->bus,
1408 "org.freedesktop.systemd1",
1409 "/org/freedesktop/systemd1",
1410 "org.freedesktop.systemd1.Manager",
1411 "KillUnit",
1ee306e1 1412 error,
a658cafa 1413 NULL,
de58a50e 1414 "ssi", unit, "all", signo);
1ee306e1
LP
1415}
1416
1417int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
1418 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1419 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 1420 _cleanup_free_ char *path = NULL;
1ee306e1 1421 const char *state;
1ee306e1
LP
1422 int r;
1423
1424 assert(manager);
1425 assert(unit);
1426
1ee306e1
LP
1427 path = unit_dbus_path_from_name(unit);
1428 if (!path)
1429 return -ENOMEM;
1430
c3350683 1431 r = sd_bus_get_property(
1ee306e1
LP
1432 manager->bus,
1433 "org.freedesktop.systemd1",
1434 path,
c3350683
LP
1435 "org.freedesktop.systemd1.Unit",
1436 "ActiveState",
1ee306e1 1437 &error,
c3350683
LP
1438 &reply,
1439 "s");
1ee306e1 1440 if (r < 0) {
c3350683
LP
1441 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1442 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 1443 return true;
6797c324 1444
c3350683
LP
1445 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1446 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 1447 return false;
6797c324 1448
1ee306e1
LP
1449 return r;
1450 }
1451
c3350683
LP
1452 r = sd_bus_message_read(reply, "s", &state);
1453 if (r < 0)
1ee306e1 1454 return -EINVAL;
1ee306e1 1455
9b420b3c 1456 return !STR_IN_SET(state, "inactive", "failed");
1ee306e1 1457}
bd16acf3 1458
c3350683
LP
1459int manager_job_is_active(Manager *manager, const char *path) {
1460 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1461 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1462 int r;
bd16acf3 1463
c3350683
LP
1464 assert(manager);
1465 assert(path);
bd16acf3 1466
c3350683
LP
1467 r = sd_bus_get_property(
1468 manager->bus,
1469 "org.freedesktop.systemd1",
1470 path,
1471 "org.freedesktop.systemd1.Job",
1472 "State",
1473 &error,
1474 &reply,
1475 "s");
1476 if (r < 0) {
1477 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1478 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1479 return true;
bd16acf3 1480
c3350683
LP
1481 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1482 return false;
bd16acf3 1483
bd16acf3 1484 return r;
c3350683 1485 }
bd16acf3 1486
c3350683
LP
1487 /* We don't actually care about the state really. The fact
1488 * that we could read the job state is enough for us */
bd16acf3 1489
c3350683 1490 return true;
bd16acf3 1491}
ab49725f
KS
1492
1493int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
ab49725f
KS
1494 Machine *mm;
1495 int r;
1496
1497 assert(m);
1498 assert(pid >= 1);
1499 assert(machine);
1500
077c8c36
LP
1501 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1502 if (!mm) {
1503 _cleanup_free_ char *unit = NULL;
ab49725f 1504
077c8c36
LP
1505 r = cg_pid_get_unit(pid, &unit);
1506 if (r >= 0)
1507 mm = hashmap_get(m->machine_units, unit);
1508 }
ab49725f
KS
1509 if (!mm)
1510 return 0;
1511
1512 *machine = mm;
1513 return 1;
1514}
1515
1516int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1517 Machine *machine;
1518
1519 assert(m);
1520 assert(name);
1521
1522 machine = hashmap_get(m->machines, name);
1523 if (!machine) {
fbe55073 1524 machine = machine_new(m, _MACHINE_CLASS_INVALID, name);
ab49725f
KS
1525 if (!machine)
1526 return -ENOMEM;
1527 }
1528
1529 if (_machine)
1530 *_machine = machine;
1531
1532 return 0;
1533}