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