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