]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / machine / machined-dbus.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
1ee306e1
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <errno.h>
22#include <string.h>
23#include <unistd.h>
1ee306e1 24
c3350683 25#include "sd-id128.h"
3ffd4af2 26
b5efdb8a 27#include "alloc-util.h"
3ffd4af2 28#include "btrfs-util.h"
96aad8d1 29#include "bus-common-errors.h"
3ffd4af2 30#include "bus-util.h"
23c80348 31#include "cgroup-util.h"
3ffd4af2 32#include "fd-util.h"
03c2b288 33#include "fileio.h"
f97b34a6 34#include "format-util.h"
25300b5a 35#include "hostname-util.h"
3ffd4af2 36#include "image-dbus.h"
a90fb858 37#include "io-util.h"
3ffd4af2 38#include "machine-dbus.h"
003dffde 39#include "machine-image.h"
4cee5eed 40#include "machine-pool.h"
c3350683 41#include "machined.h"
3ffd4af2
LP
42#include "path-util.h"
43#include "process-util.h"
15a5e950 44#include "stdio-util.h"
3ffd4af2
LP
45#include "strv.h"
46#include "unit-name.h"
b1d4f8e1 47#include "user-util.h"
1ee306e1 48
160e3793
LP
49static int property_get_pool_path(
50 sd_bus *bus,
51 const char *path,
52 const char *interface,
53 const char *property,
54 sd_bus_message *reply,
55 void *userdata,
56 sd_bus_error *error) {
57
58 assert(bus);
59 assert(reply);
60
61 return sd_bus_message_append(reply, "s", "/var/lib/machines");
62}
63
64static int property_get_pool_usage(
65 sd_bus *bus,
66 const char *path,
67 const char *interface,
68 const char *property,
69 sd_bus_message *reply,
70 void *userdata,
71 sd_bus_error *error) {
72
73 _cleanup_close_ int fd = -1;
74 uint64_t usage = (uint64_t) -1;
75 struct stat st;
76
77 assert(bus);
78 assert(reply);
79
80 /* We try to read the quota info from /var/lib/machines, as
81 * well as the usage of the loopback file
82 * /var/lib/machines.raw, and pick the larger value. */
83
84 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
85 if (fd >= 0) {
86 BtrfsQuotaInfo q;
87
5bcd08db 88 if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
cb81cd80 89 usage = q.referenced;
160e3793
LP
90 }
91
92 if (stat("/var/lib/machines.raw", &st) >= 0) {
93 if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
94 usage = st.st_blocks * 512ULL;
95 }
96
97 return sd_bus_message_append(reply, "t", usage);
98}
99
100static int property_get_pool_limit(
101 sd_bus *bus,
102 const char *path,
103 const char *interface,
104 const char *property,
105 sd_bus_message *reply,
106 void *userdata,
107 sd_bus_error *error) {
108
109 _cleanup_close_ int fd = -1;
110 uint64_t size = (uint64_t) -1;
111 struct stat st;
112
113 assert(bus);
114 assert(reply);
115
116 /* We try to read the quota limit from /var/lib/machines, as
117 * well as the size of the loopback file
118 * /var/lib/machines.raw, and pick the smaller value. */
119
120 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
121 if (fd >= 0) {
122 BtrfsQuotaInfo q;
123
5bcd08db 124 if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
cb81cd80 125 size = q.referenced_max;
160e3793
LP
126 }
127
128 if (stat("/var/lib/machines.raw", &st) >= 0) {
129 if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
130 size = st.st_size;
131 }
132
133 return sd_bus_message_append(reply, "t", size);
134}
135
19070062 136static int method_get_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
137 _cleanup_free_ char *p = NULL;
138 Manager *m = userdata;
139 Machine *machine;
140 const char *name;
141 int r;
142
c3350683
LP
143 assert(message);
144 assert(m);
145
146 r = sd_bus_message_read(message, "s", &name);
147 if (r < 0)
ebcf1f97 148 return r;
c3350683
LP
149
150 machine = hashmap_get(m->machines, name);
151 if (!machine)
ebcf1f97 152 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
c3350683
LP
153
154 p = machine_bus_path(machine);
155 if (!p)
ebcf1f97 156 return -ENOMEM;
c3350683 157
df2d202e 158 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
159}
160
19070062 161static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c2ce6a3d
LP
162 _cleanup_free_ char *p = NULL;
163 Manager *m = userdata;
164 const char *name;
165 int r;
166
c2ce6a3d
LP
167 assert(message);
168 assert(m);
169
170 r = sd_bus_message_read(message, "s", &name);
171 if (r < 0)
172 return r;
173
174 r = image_find(name, NULL);
175 if (r == 0)
176 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
177 if (r < 0)
178 return r;
179
180 p = image_bus_path(name);
181 if (!p)
182 return -ENOMEM;
183
184 return sd_bus_reply_method_return(message, "o", p);
185}
186
19070062 187static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
188 _cleanup_free_ char *p = NULL;
189 Manager *m = userdata;
190 Machine *machine = NULL;
4e724d9c 191 pid_t pid;
c3350683
LP
192 int r;
193
c3350683
LP
194 assert(message);
195 assert(m);
196
4e724d9c
LP
197 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
198
c3350683
LP
199 r = sd_bus_message_read(message, "u", &pid);
200 if (r < 0)
ebcf1f97 201 return r;
c3350683 202
07b38ba5 203 if (pid < 0)
06820eaf
LP
204 return -EINVAL;
205
4e724d9c 206 if (pid == 0) {
4afd3348 207 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
5b12334d
LP
208
209 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
210 if (r < 0)
211 return r;
212
213 r = sd_bus_creds_get_pid(creds, &pid);
4e724d9c 214 if (r < 0)
ebcf1f97 215 return r;
4e724d9c
LP
216 }
217
c3350683
LP
218 r = manager_get_machine_by_pid(m, pid, &machine);
219 if (r < 0)
ebcf1f97 220 return r;
c3350683 221 if (!machine)
de0671ee 222 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
223
224 p = machine_bus_path(machine);
225 if (!p)
ebcf1f97 226 return -ENOMEM;
c3350683 227
df2d202e 228 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
229}
230
19070062 231static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 232 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
c3350683
LP
233 Manager *m = userdata;
234 Machine *machine;
235 Iterator i;
236 int r;
237
c3350683
LP
238 assert(message);
239 assert(m);
240
df2d202e 241 r = sd_bus_message_new_method_return(message, &reply);
c3350683 242 if (r < 0)
ebcf1f97 243 return sd_bus_error_set_errno(error, r);
c3350683
LP
244
245 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
246 if (r < 0)
ebcf1f97 247 return sd_bus_error_set_errno(error, r);
c3350683
LP
248
249 HASHMAP_FOREACH(machine, m->machines, i) {
250 _cleanup_free_ char *p = NULL;
251
252 p = machine_bus_path(machine);
253 if (!p)
ebcf1f97 254 return -ENOMEM;
c3350683
LP
255
256 r = sd_bus_message_append(reply, "(ssso)",
257 machine->name,
258 strempty(machine_class_to_string(machine->class)),
259 machine->service,
260 p);
261 if (r < 0)
ebcf1f97 262 return sd_bus_error_set_errno(error, r);
c3350683 263 }
1ee306e1 264
c3350683
LP
265 r = sd_bus_message_close_container(reply);
266 if (r < 0)
ebcf1f97 267 return sd_bus_error_set_errno(error, r);
c3350683 268
9030ca46 269 return sd_bus_send(NULL, reply, NULL);
c3350683
LP
270}
271
9b5ed6fe 272static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
8aec412f 273 const char *name, *service, *class, *root_directory;
9b5ed6fe 274 const int32_t *netif = NULL;
1ee306e1
LP
275 MachineClass c;
276 uint32_t leader;
277 sd_id128_t id;
c3350683 278 const void *v;
1ee306e1 279 Machine *m;
9b5ed6fe 280 size_t n, n_netif = 0;
c3350683 281 int r;
1ee306e1 282
c3350683 283 assert(manager);
89f7c846
LP
284 assert(message);
285 assert(_m);
1ee306e1 286
c3350683
LP
287 r = sd_bus_message_read(message, "s", &name);
288 if (r < 0)
ebcf1f97 289 return r;
7f0d207d 290 if (!machine_name_is_valid(name))
ebcf1f97 291 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 292
c3350683
LP
293 r = sd_bus_message_read_array(message, 'y', &v, &n);
294 if (r < 0)
ebcf1f97 295 return r;
1ee306e1
LP
296 if (n == 0)
297 id = SD_ID128_NULL;
298 else if (n == 16)
299 memcpy(&id, v, n);
300 else
ebcf1f97 301 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 302
c3350683
LP
303 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
304 if (r < 0)
ebcf1f97 305 return r;
1ee306e1 306
9b5ed6fe
LP
307 if (read_network) {
308 size_t i;
309
310 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
311 if (r < 0)
312 return r;
313
314 n_netif /= sizeof(int32_t);
315
316 for (i = 0; i < n_netif; i++) {
317 if (netif[i] <= 0)
318 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
319 }
320 }
321
1ee306e1
LP
322 if (isempty(class))
323 c = _MACHINE_CLASS_INVALID;
324 else {
325 c = machine_class_from_string(class);
326 if (c < 0)
ebcf1f97 327 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
328 }
329
c3350683 330 if (leader == 1)
ebcf1f97 331 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 332
c3350683 333 if (!isempty(root_directory) && !path_is_absolute(root_directory))
ebcf1f97 334 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 335
c3350683 336 if (leader == 0) {
4afd3348 337 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
5b12334d
LP
338
339 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
340 if (r < 0)
341 return r;
342
c3350683 343 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
554604b3 344
5b12334d 345 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c3350683 346 if (r < 0)
ebcf1f97 347 return r;
c3350683 348 }
554604b3 349
1ee306e1 350 if (hashmap_get(manager->machines, name))
ebcf1f97 351 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1
LP
352
353 r = manager_add_machine(manager, name, &m);
354 if (r < 0)
ebcf1f97 355 return r;
1ee306e1
LP
356
357 m->leader = leader;
358 m->class = c;
359 m->id = id;
360
361 if (!isempty(service)) {
362 m->service = strdup(service);
363 if (!m->service) {
ebcf1f97 364 r = -ENOMEM;
1ee306e1
LP
365 goto fail;
366 }
367 }
368
369 if (!isempty(root_directory)) {
370 m->root_directory = strdup(root_directory);
371 if (!m->root_directory) {
ebcf1f97 372 r = -ENOMEM;
1ee306e1
LP
373 goto fail;
374 }
375 }
376
9b5ed6fe
LP
377 if (n_netif > 0) {
378 assert_cc(sizeof(int32_t) == sizeof(int));
379 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
380 if (!m->netif) {
381 r = -ENOMEM;
382 goto fail;
383 }
384
385 m->n_netif = n_netif;
386 }
387
89f7c846
LP
388 *_m = m;
389
390 return 1;
391
392fail:
393 machine_add_to_gc_queue(m);
394 return r;
395}
396
19070062 397static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
398 Manager *manager = userdata;
399 Machine *m = NULL;
400 int r;
401
19070062
LP
402 assert(message);
403 assert(manager);
404
9b5ed6fe 405 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
406 if (r < 0)
407 return r;
408
409 r = sd_bus_message_enter_container(message, 'a', "(sv)");
410 if (r < 0)
411 goto fail;
412
ebcf1f97
LP
413 r = machine_start(m, message, error);
414 if (r < 0)
1ee306e1
LP
415 goto fail;
416
c3350683 417 m->create_message = sd_bus_message_ref(message);
c3350683 418 return 1;
1ee306e1
LP
419
420fail:
a3e7f417 421 machine_add_to_gc_queue(m);
89f7c846
LP
422 return r;
423}
1ee306e1 424
19070062
LP
425static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
426 return method_create_machine_internal(message, true, userdata, error);
9b5ed6fe
LP
427}
428
19070062
LP
429static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
430 return method_create_machine_internal(message, false, userdata, error);
9b5ed6fe
LP
431}
432
19070062 433static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
434 Manager *manager = userdata;
435 _cleanup_free_ char *p = NULL;
436 Machine *m = NULL;
437 int r;
438
19070062
LP
439 assert(message);
440 assert(manager);
441
9b5ed6fe 442 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
443 if (r < 0)
444 return r;
445
446 r = cg_pid_get_unit(m->leader, &m->unit);
447 if (r < 0) {
048c386e
ZJS
448 r = sd_bus_error_set_errnof(error, r,
449 "Failed to determine unit of process "PID_FMT" : %m",
450 m->leader);
89f7c846
LP
451 goto fail;
452 }
453
454 r = machine_start(m, NULL, error);
455 if (r < 0)
456 goto fail;
457
458 p = machine_bus_path(m);
459 if (!p) {
460 r = -ENOMEM;
461 goto fail;
462 }
463
464 return sd_bus_reply_method_return(message, "o", p);
465
466fail:
467 machine_add_to_gc_queue(m);
1ee306e1
LP
468 return r;
469}
470
19070062
LP
471static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
472 return method_register_machine_internal(message, true, userdata, error);
9b5ed6fe
LP
473}
474
19070062
LP
475static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
476 return method_register_machine_internal(message, false, userdata, error);
9b5ed6fe
LP
477}
478
19070062 479static int method_terminate_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 480 Manager *m = userdata;
c3350683
LP
481 Machine *machine;
482 const char *name;
1ee306e1
LP
483 int r;
484
1ee306e1
LP
485 assert(message);
486 assert(m);
487
c3350683
LP
488 r = sd_bus_message_read(message, "s", &name);
489 if (r < 0)
ebcf1f97 490 return sd_bus_error_set_errno(error, r);
1ee306e1 491
c3350683
LP
492 machine = hashmap_get(m->machines, name);
493 if (!machine)
ebcf1f97 494 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 495
19070062 496 return bus_machine_method_terminate(message, machine, error);
c3350683 497}
1ee306e1 498
19070062 499static int method_kill_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
500 Manager *m = userdata;
501 Machine *machine;
502 const char *name;
c3350683 503 int r;
1ee306e1 504
c3350683
LP
505 assert(message);
506 assert(m);
1ee306e1 507
878cd7e9 508 r = sd_bus_message_read(message, "s", &name);
c3350683 509 if (r < 0)
ebcf1f97 510 return sd_bus_error_set_errno(error, r);
1ee306e1 511
c3350683
LP
512 machine = hashmap_get(m->machines, name);
513 if (!machine)
ebcf1f97 514 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 515
19070062 516 return bus_machine_method_kill(message, machine, error);
878cd7e9
LP
517}
518
19070062 519static int method_get_machine_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
878cd7e9
LP
520 Manager *m = userdata;
521 Machine *machine;
522 const char *name;
523 int r;
524
878cd7e9
LP
525 assert(message);
526 assert(m);
527
528 r = sd_bus_message_read(message, "s", &name);
c3350683 529 if (r < 0)
ebcf1f97 530 return sd_bus_error_set_errno(error, r);
1ee306e1 531
878cd7e9
LP
532 machine = hashmap_get(m->machines, name);
533 if (!machine)
534 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
535
19070062 536 return bus_machine_method_get_addresses(message, machine, error);
c3350683 537}
1ee306e1 538
19070062 539static int method_get_machine_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
717603e3
LP
540 Manager *m = userdata;
541 Machine *machine;
542 const char *name;
543 int r;
544
717603e3
LP
545 assert(message);
546 assert(m);
547
548 r = sd_bus_message_read(message, "s", &name);
549 if (r < 0)
550 return sd_bus_error_set_errno(error, r);
551
552 machine = hashmap_get(m->machines, name);
553 if (!machine)
554 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
555
19070062 556 return bus_machine_method_get_os_release(message, machine, error);
717603e3
LP
557}
558
19070062 559static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 560 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
cd61c3bf
LP
561 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
562 Manager *m = userdata;
563 Image *image;
564 Iterator i;
565 int r;
566
cd61c3bf
LP
567 assert(message);
568 assert(m);
569
570 images = hashmap_new(&string_hash_ops);
571 if (!images)
572 return -ENOMEM;
573
574 r = image_discover(images);
575 if (r < 0)
576 return r;
577
578 r = sd_bus_message_new_method_return(message, &reply);
579 if (r < 0)
580 return r;
581
b6b18498 582 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
cd61c3bf
LP
583 if (r < 0)
584 return r;
585
586 HASHMAP_FOREACH(image, images, i) {
587 _cleanup_free_ char *p = NULL;
588
589 p = image_bus_path(image->name);
590 if (!p)
591 return -ENOMEM;
592
b6b18498 593 r = sd_bus_message_append(reply, "(ssbttto)",
cd61c3bf
LP
594 image->name,
595 image_type_to_string(image->type),
596 image->read_only,
10f9c755
LP
597 image->crtime,
598 image->mtime,
c19de711 599 image->usage,
cd61c3bf
LP
600 p);
601 if (r < 0)
602 return r;
603 }
604
605 r = sd_bus_message_close_container(reply);
606 if (r < 0)
607 return r;
608
9030ca46 609 return sd_bus_send(NULL, reply, NULL);
cd61c3bf
LP
610}
611
19070062 612static int method_open_machine_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
40205d70
LP
613 Manager *m = userdata;
614 Machine *machine;
615 const char *name;
616 int r;
617
40205d70
LP
618 assert(message);
619 assert(m);
620
621 r = sd_bus_message_read(message, "s", &name);
622 if (r < 0)
623 return sd_bus_error_set_errno(error, r);
624
625 machine = hashmap_get(m->machines, name);
626 if (!machine)
627 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
628
19070062 629 return bus_machine_method_open_pty(message, machine, error);
40205d70
LP
630}
631
19070062 632static int method_open_machine_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
5f8cc96a
LP
633 Manager *m = userdata;
634 Machine *machine;
635 const char *name;
636 int r;
637
5f8cc96a
LP
638 assert(message);
639 assert(m);
640
641 r = sd_bus_message_read(message, "s", &name);
642 if (r < 0)
08682124 643 return r;
5f8cc96a
LP
644
645 machine = hashmap_get(m->machines, name);
646 if (!machine)
647 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
648
19070062 649 return bus_machine_method_open_login(message, machine, error);
5f8cc96a
LP
650}
651
49af9e13
LP
652static int method_open_machine_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
653 Manager *m = userdata;
654 Machine *machine;
655 const char *name;
656
657 int r;
658
659 assert(message);
660 assert(m);
661
662 r = sd_bus_message_read(message, "s", &name);
663 if (r < 0)
664 return r;
665
666 machine = hashmap_get(m->machines, name);
667 if (!machine)
668 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
669
670 return bus_machine_method_open_shell(message, machine, error);
671}
672
19070062 673static int method_bind_mount_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
90adaa25
LP
674 Manager *m = userdata;
675 Machine *machine;
676 const char *name;
677 int r;
678
90adaa25
LP
679 assert(message);
680 assert(m);
681
682 r = sd_bus_message_read(message, "s", &name);
683 if (r < 0)
684 return r;
685
686 machine = hashmap_get(m->machines, name);
687 if (!machine)
688 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
689
19070062 690 return bus_machine_method_bind_mount(message, machine, error);
90adaa25
LP
691}
692
19070062 693static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
0370612e
LP
694 Manager *m = userdata;
695 Machine *machine;
696 const char *name;
697 int r;
698
0370612e
LP
699 assert(message);
700 assert(m);
701
702 r = sd_bus_message_read(message, "s", &name);
703 if (r < 0)
704 return r;
705
706 machine = hashmap_get(m->machines, name);
707 if (!machine)
708 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
709
19070062 710 return bus_machine_method_copy(message, machine, error);
0370612e
LP
711}
712
ae203207
LP
713static int method_open_machine_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
714 Manager *m = userdata;
715 Machine *machine;
716 const char *name;
717 int r;
718
719 assert(message);
720 assert(m);
721
722 r = sd_bus_message_read(message, "s", &name);
723 if (r < 0)
724 return r;
725
726 machine = hashmap_get(m->machines, name);
727 if (!machine)
728 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
729
730 return bus_machine_method_open_root_directory(message, machine, error);
731}
732
3401419b
LP
733static int method_get_machine_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
734 Manager *m = userdata;
735 Machine *machine;
736 const char *name;
737 int r;
738
739 assert(message);
740 assert(m);
741
742 r = sd_bus_message_read(message, "s", &name);
743 if (r < 0)
744 return r;
745
746 machine = hashmap_get(m->machines, name);
747 if (!machine)
748 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
749
750 return bus_machine_method_get_uid_shift(message, machine, error);
751}
752
19070062 753static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
08682124
LP
754 _cleanup_(image_unrefp) Image* i = NULL;
755 const char *name;
756 int r;
757
08682124
LP
758 assert(message);
759
760 r = sd_bus_message_read(message, "s", &name);
761 if (r < 0)
762 return r;
763
764 if (!image_name_is_valid(name))
765 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
766
767 r = image_find(name, &i);
768 if (r < 0)
769 return r;
770 if (r == 0)
771 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
772
70244d1d 773 i->userdata = userdata;
19070062 774 return bus_image_method_remove(message, i, error);
08682124
LP
775}
776
19070062 777static int method_rename_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ebd93cb6 778 _cleanup_(image_unrefp) Image* i = NULL;
1ddb263d 779 const char *old_name;
ebd93cb6
LP
780 int r;
781
ebd93cb6
LP
782 assert(message);
783
1ddb263d 784 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
785 if (r < 0)
786 return r;
787
788 if (!image_name_is_valid(old_name))
789 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
790
791 r = image_find(old_name, &i);
792 if (r < 0)
793 return r;
794 if (r == 0)
795 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
796
70244d1d 797 i->userdata = userdata;
19070062 798 return bus_image_method_rename(message, i, error);
ebd93cb6
LP
799}
800
19070062 801static int method_clone_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ebd93cb6 802 _cleanup_(image_unrefp) Image *i = NULL;
1ddb263d
LP
803 const char *old_name;
804 int r;
ebd93cb6 805
19070062
LP
806 assert(message);
807
1ddb263d 808 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
809 if (r < 0)
810 return r;
811
812 if (!image_name_is_valid(old_name))
813 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
814
815 r = image_find(old_name, &i);
816 if (r < 0)
817 return r;
818 if (r == 0)
819 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
820
70244d1d 821 i->userdata = userdata;
19070062 822 return bus_image_method_clone(message, i, error);
ebd93cb6
LP
823}
824
19070062 825static int method_mark_image_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
ebd93cb6
LP
826 _cleanup_(image_unrefp) Image *i = NULL;
827 const char *name;
1ddb263d 828 int r;
ebd93cb6 829
19070062
LP
830 assert(message);
831
1ddb263d 832 r = sd_bus_message_read(message, "s", &name);
ebd93cb6
LP
833 if (r < 0)
834 return r;
835
836 if (!image_name_is_valid(name))
837 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
838
839 r = image_find(name, &i);
840 if (r < 0)
841 return r;
842 if (r == 0)
843 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
844
70244d1d 845 i->userdata = userdata;
19070062 846 return bus_image_method_mark_read_only(message, i, error);
ebd93cb6
LP
847}
848
9153b02b
LP
849static int method_get_image_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
850 _cleanup_(image_unrefp) Image *i = NULL;
851 const char *name;
852 int r;
853
854 assert(message);
855
856 r = sd_bus_message_read(message, "s", &name);
857 if (r < 0)
858 return r;
859
860 if (!image_name_is_valid(name))
861 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
862
863 r = image_find(name, &i);
864 if (r < 0)
865 return r;
866 if (r == 0)
867 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
868
869 i->userdata = userdata;
870 return bus_image_method_get_os_release(message, i, error);
871}
872
03c2b288
LP
873static int clean_pool_done(Operation *operation, int ret, sd_bus_error *error) {
874 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
875 _cleanup_fclose_ FILE *f = NULL;
876 bool success;
877 size_t n;
878 int r;
879
880 assert(operation);
881 assert(operation->extra_fd >= 0);
882
883 if (lseek(operation->extra_fd, 0, SEEK_SET) == (off_t) -1)
884 return -errno;
885
886 f = fdopen(operation->extra_fd, "re");
887 if (!f)
888 return -errno;
889
890 operation->extra_fd = -1;
891
892 /* The resulting temporary file starts with a boolean value that indicates success or not. */
893 errno = 0;
894 n = fread(&success, 1, sizeof(success), f);
895 if (n != sizeof(success))
896 return ret < 0 ? ret : (errno != 0 ? -errno : -EIO);
897
898 if (ret < 0) {
899 _cleanup_free_ char *name = NULL;
900
901 /* The clean-up operation failed. In this case the resulting temporary file should contain a boolean
902 * set to false followed by the name of the failed image. Let's try to read this and use it for the
903 * error message. If we can't read it, don't mind, and return the naked error. */
904
905 if (success) /* The resulting temporary file could not be updated, ignore it. */
906 return ret;
907
908 r = read_nul_string(f, &name);
909 if (r < 0 || isempty(name)) /* Same here... */
910 return ret;
911
912 return sd_bus_error_set_errnof(error, ret, "Failed to remove image %s: %m", name);
913 }
914
915 assert(success);
916
917 r = sd_bus_message_new_method_return(operation->message, &reply);
918 if (r < 0)
919 return r;
920
921 r = sd_bus_message_open_container(reply, 'a', "(st)");
922 if (r < 0)
923 return r;
924
925 /* On success the resulting temporary file will contain a list of image names that were removed followed by
926 * their size on disk. Let's read that and turn it into a bus message. */
927 for (;;) {
928 _cleanup_free_ char *name = NULL;
929 uint64_t size;
930
931 r = read_nul_string(f, &name);
932 if (r < 0)
933 return r;
934 if (isempty(name)) /* reached the end */
935 break;
936
937 errno = 0;
938 n = fread(&size, 1, sizeof(size), f);
939 if (n != sizeof(size))
940 return errno != 0 ? -errno : -EIO;
941
942 r = sd_bus_message_append(reply, "(st)", name, size);
943 if (r < 0)
944 return r;
945 }
946
947 r = sd_bus_message_close_container(reply);
948 if (r < 0)
949 return r;
950
951 return sd_bus_send(NULL, reply, NULL);
952}
953
d94c2b06
LP
954static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) {
955 enum {
956 REMOVE_ALL,
957 REMOVE_HIDDEN,
958 } mode;
959
03c2b288
LP
960 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
961 _cleanup_close_ int result_fd = -1;
d94c2b06 962 Manager *m = userdata;
03c2b288 963 Operation *operation;
d94c2b06 964 const char *mm;
03c2b288 965 pid_t child;
d94c2b06
LP
966 int r;
967
968 assert(message);
969
03c2b288
LP
970 if (m->n_operations >= OPERATIONS_MAX)
971 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
972
d94c2b06
LP
973 r = sd_bus_message_read(message, "s", &mm);
974 if (r < 0)
975 return r;
976
977 if (streq(mm, "all"))
978 mode = REMOVE_ALL;
979 else if (streq(mm, "hidden"))
980 mode = REMOVE_HIDDEN;
981 else
982 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mode '%s'.", mm);
983
984 r = bus_verify_polkit_async(
985 message,
986 CAP_SYS_ADMIN,
987 "org.freedesktop.machine1.manage-machines",
988 NULL,
989 false,
990 UID_INVALID,
991 &m->polkit_registry,
992 error);
993 if (r < 0)
994 return r;
995 if (r == 0)
996 return 1; /* Will call us back */
997
03c2b288
LP
998 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
999 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
d94c2b06 1000
03c2b288
LP
1001 /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
1002 * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
595bfe7d 1003 * continuously */
992e8f22 1004 result_fd = open_tmpfile_unlinkable(NULL, O_RDWR|O_CLOEXEC);
03c2b288
LP
1005 if (result_fd < 0)
1006 return -errno;
d94c2b06 1007
03c2b288
LP
1008 /* This might be a slow operation, run it asynchronously in a background process */
1009 child = fork();
1010 if (child < 0)
1011 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
d94c2b06 1012
03c2b288
LP
1013 if (child == 0) {
1014 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
1015 bool success = true;
1016 Image *image;
1017 Iterator i;
1018 ssize_t l;
d94c2b06 1019
03c2b288 1020 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
d94c2b06 1021
03c2b288
LP
1022 images = hashmap_new(&string_hash_ops);
1023 if (!images) {
1024 r = -ENOMEM;
1025 goto child_fail;
1026 }
d94c2b06 1027
03c2b288
LP
1028 r = image_discover(images);
1029 if (r < 0)
1030 goto child_fail;
d94c2b06 1031
03c2b288
LP
1032 l = write(result_fd, &success, sizeof(success));
1033 if (l < 0) {
1034 r = -errno;
1035 goto child_fail;
1036 }
d94c2b06 1037
03c2b288
LP
1038 HASHMAP_FOREACH(image, images, i) {
1039
1040 /* We can't remove vendor images (i.e. those in /usr) */
1041 if (IMAGE_IS_VENDOR(image))
1042 continue;
1043
1044 if (IMAGE_IS_HOST(image))
1045 continue;
1046
1047 if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image))
1048 continue;
1049
1050 r = image_remove(image);
1051 if (r == -EBUSY) /* keep images that are currently being used. */
1052 continue;
1053 if (r < 0) {
1054 /* If the operation failed, let's override everything we wrote, and instead write there at which image we failed. */
1055 success = false;
1056 (void) ftruncate(result_fd, 0);
1057 (void) lseek(result_fd, 0, SEEK_SET);
1058 (void) write(result_fd, &success, sizeof(success));
1059 (void) write(result_fd, image->name, strlen(image->name)+1);
1060 goto child_fail;
1061 }
1062
1063 l = write(result_fd, image->name, strlen(image->name)+1);
1064 if (l < 0) {
1065 r = -errno;
1066 goto child_fail;
1067 }
1068
1069 l = write(result_fd, &image->usage_exclusive, sizeof(image->usage_exclusive));
1070 if (l < 0) {
1071 r = -errno;
1072 goto child_fail;
1073 }
1074 }
d94c2b06 1075
03c2b288
LP
1076 result_fd = safe_close(result_fd);
1077 _exit(EXIT_SUCCESS);
1078
1079 child_fail:
1080 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1081 _exit(EXIT_FAILURE);
d94c2b06
LP
1082 }
1083
03c2b288
LP
1084 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1085
1086 /* The clean-up might take a while, hence install a watch on the child and return */
1087
1088 r = operation_new(m, NULL, child, message, errno_pipe_fd[0], &operation);
1089 if (r < 0) {
1090 (void) sigkill_wait(child);
d94c2b06 1091 return r;
03c2b288 1092 }
d94c2b06 1093
03c2b288
LP
1094 operation->extra_fd = result_fd;
1095 operation->done = clean_pool_done;
1096
1097 result_fd = -1;
1098 errno_pipe_fd[0] = -1;
1099
1100 return 1;
d94c2b06
LP
1101}
1102
19070062 1103static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d6ce17c7
LP
1104 Manager *m = userdata;
1105 uint64_t limit;
1106 int r;
1107
19070062
LP
1108 assert(message);
1109
d6ce17c7
LP
1110 r = sd_bus_message_read(message, "t", &limit);
1111 if (r < 0)
1112 return r;
a90fb858
LP
1113 if (!FILE_SIZE_VALID_OR_INFINITY(limit))
1114 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
d6ce17c7
LP
1115
1116 r = bus_verify_polkit_async(
1117 message,
1118 CAP_SYS_ADMIN,
1119 "org.freedesktop.machine1.manage-machines",
403ed0e5 1120 NULL,
d6ce17c7
LP
1121 false,
1122 UID_INVALID,
1123 &m->polkit_registry,
1124 error);
1125 if (r < 0)
1126 return r;
1127 if (r == 0)
1128 return 1; /* Will call us back */
1129
4cee5eed
LP
1130 /* Set up the machine directory if necessary */
1131 r = setup_machine_directory(limit, error);
1132 if (r < 0)
1133 return r;
1134
05e8f270
LP
1135 /* Resize the backing loopback device, if there is one, except if we asked to drop any limit */
1136 if (limit != (uint64_t) -1) {
1137 r = btrfs_resize_loopback("/var/lib/machines", limit, false);
1138 if (r == -ENOTTY)
1139 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
1140 if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
1141 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
1142 }
efe02862 1143
5bcd08db
LP
1144 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit);
1145
1146 r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit);
d6ce17c7
LP
1147 if (r == -ENOTTY)
1148 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
26166c88 1149 if (r < 0)
d6ce17c7
LP
1150 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
1151
1152 return sd_bus_reply_method_return(message, NULL);
1153}
1154
19070062 1155static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d6ce17c7
LP
1156 _cleanup_(image_unrefp) Image *i = NULL;
1157 const char *name;
1158 int r;
1159
19070062
LP
1160 assert(message);
1161
d6ce17c7
LP
1162 r = sd_bus_message_read(message, "s", &name);
1163 if (r < 0)
1164 return r;
1165
1166 if (!image_name_is_valid(name))
1167 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
1168
1169 r = image_find(name, &i);
1170 if (r < 0)
1171 return r;
1172 if (r == 0)
1173 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
1174
1175 i->userdata = userdata;
19070062 1176 return bus_image_method_set_limit(message, i, error);
d6ce17c7
LP
1177}
1178
c01ff965
LP
1179static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1180 _cleanup_fclose_ FILE *f = NULL;
1181 Manager *m = userdata;
1182 const char *name, *p;
1183 Machine *machine;
1184 uint32_t uid;
1185 int r;
1186
1187 r = sd_bus_message_read(message, "su", &name, &uid);
1188 if (r < 0)
1189 return r;
1190
c077529b 1191 if (!uid_is_valid(uid))
c01ff965
LP
1192 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
1193
1194 machine = hashmap_get(m->machines, name);
1195 if (!machine)
1196 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1197
a79366e2
LP
1198 if (machine->class != MACHINE_CONTAINER)
1199 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
1200
c01ff965
LP
1201 p = procfs_file_alloca(machine->leader, "uid_map");
1202 f = fopen(p, "re");
1203 if (!f)
1204 return -errno;
1205
1206 for (;;) {
1207 uid_t uid_base, uid_shift, uid_range, converted;
1208 int k;
1209
1210 errno = 0;
1211 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
1212 if (k < 0 && feof(f))
1213 break;
1214 if (k != 3) {
b3267152 1215 if (ferror(f) && errno > 0)
c01ff965
LP
1216 return -errno;
1217
1218 return -EIO;
1219 }
1220
1221 if (uid < uid_base || uid >= uid_base + uid_range)
1222 continue;
1223
1224 converted = uid - uid_base + uid_shift;
c077529b 1225 if (!uid_is_valid(converted))
c01ff965
LP
1226 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
1227
1228 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
1229 }
1230
1231 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
1232}
1233
1234static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1235 Manager *m = userdata;
1236 Machine *machine;
1237 uid_t uid;
1238 Iterator i;
1239 int r;
1240
1241 r = sd_bus_message_read(message, "u", &uid);
1242 if (r < 0)
1243 return r;
c077529b 1244 if (!uid_is_valid(uid))
c01ff965
LP
1245 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
1246 if (uid < 0x10000)
1247 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
1248
1249 HASHMAP_FOREACH(machine, m->machines, i) {
1250 _cleanup_fclose_ FILE *f = NULL;
1251 char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
1252
a79366e2
LP
1253 if (machine->class != MACHINE_CONTAINER)
1254 continue;
1255
c01ff965
LP
1256 xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
1257 f = fopen(p, "re");
1258 if (!f) {
1259 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
1260 continue;
1261 }
1262
1263 for (;;) {
1264 _cleanup_free_ char *o = NULL;
1265 uid_t uid_base, uid_shift, uid_range, converted;
1266 int k;
1267
1268 errno = 0;
1269 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
1270 if (k < 0 && feof(f))
1271 break;
1272 if (k != 3) {
b3267152 1273 if (ferror(f) && errno > 0)
c01ff965
LP
1274 return -errno;
1275
1276 return -EIO;
1277 }
1278
1279 if (uid < uid_shift || uid >= uid_shift + uid_range)
1280 continue;
1281
1282 converted = (uid - uid_shift + uid_base);
c077529b 1283 if (!uid_is_valid(converted))
c01ff965
LP
1284 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
1285
1286 o = machine_bus_path(machine);
1287 if (!o)
1288 return -ENOMEM;
1289
1290 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
1291 }
1292 }
1293
1294 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
1295}
1296
1297static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
1298 _cleanup_fclose_ FILE *f = NULL;
1299 Manager *m = groupdata;
1300 const char *name, *p;
1301 Machine *machine;
1302 uint32_t gid;
1303 int r;
1304
1305 r = sd_bus_message_read(message, "su", &name, &gid);
1306 if (r < 0)
1307 return r;
1308
c077529b 1309 if (!gid_is_valid(gid))
c01ff965
LP
1310 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1311
1312 machine = hashmap_get(m->machines, name);
1313 if (!machine)
1314 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1315
a79366e2
LP
1316 if (machine->class != MACHINE_CONTAINER)
1317 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
1318
c01ff965
LP
1319 p = procfs_file_alloca(machine->leader, "gid_map");
1320 f = fopen(p, "re");
1321 if (!f)
1322 return -errno;
1323
1324 for (;;) {
1325 gid_t gid_base, gid_shift, gid_range, converted;
1326 int k;
1327
1328 errno = 0;
1329 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1330 if (k < 0 && feof(f))
1331 break;
1332 if (k != 3) {
b3267152 1333 if (ferror(f) && errno > 0)
c01ff965
LP
1334 return -errno;
1335
1336 return -EIO;
1337 }
1338
1339 if (gid < gid_base || gid >= gid_base + gid_range)
1340 continue;
1341
1342 converted = gid - gid_base + gid_shift;
c077529b 1343 if (!gid_is_valid(converted))
c01ff965
LP
1344 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1345
1346 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
1347 }
1348
1349 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
1350}
1351
1352static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
1353 Manager *m = groupdata;
1354 Machine *machine;
1355 gid_t gid;
1356 Iterator i;
1357 int r;
1358
1359 r = sd_bus_message_read(message, "u", &gid);
1360 if (r < 0)
1361 return r;
c077529b 1362 if (!gid_is_valid(gid))
c01ff965
LP
1363 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1364 if (gid < 0x10000)
1365 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
1366
1367 HASHMAP_FOREACH(machine, m->machines, i) {
1368 _cleanup_fclose_ FILE *f = NULL;
1369 char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
1370
a79366e2
LP
1371 if (machine->class != MACHINE_CONTAINER)
1372 continue;
1373
c01ff965
LP
1374 xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
1375 f = fopen(p, "re");
1376 if (!f) {
1377 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
1378 continue;
1379 }
1380
1381 for (;;) {
1382 _cleanup_free_ char *o = NULL;
1383 gid_t gid_base, gid_shift, gid_range, converted;
1384 int k;
1385
1386 errno = 0;
1387 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1388 if (k < 0 && feof(f))
1389 break;
1390 if (k != 3) {
b3267152 1391 if (ferror(f) && errno > 0)
c01ff965
LP
1392 return -errno;
1393
1394 return -EIO;
1395 }
1396
1397 if (gid < gid_shift || gid >= gid_shift + gid_range)
1398 continue;
1399
1400 converted = (gid - gid_shift + gid_base);
c077529b 1401 if (!gid_is_valid(converted))
c01ff965
LP
1402 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1403
1404 o = machine_bus_path(machine);
1405 if (!o)
1406 return -ENOMEM;
1407
1408 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
1409 }
1410 }
1411
1412 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
1413}
1414
c3350683
LP
1415const sd_bus_vtable manager_vtable[] = {
1416 SD_BUS_VTABLE_START(0),
160e3793
LP
1417 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
1418 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
1419 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
adacb957 1420 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 1421 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
1422 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
1423 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
b6b18498 1424 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 1425 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 1426 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 1427 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 1428 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
70244d1d
LP
1429 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1430 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
3a6fb33c 1431 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1432 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 1433 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
d04c1fb8 1434 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
49af9e13 1435 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
1436 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1437 SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1438 SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
ae203207 1439 SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
3401419b 1440 SD_BUS_METHOD("GetMachineUIDShift", "s", "u", method_get_machine_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
1441 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
1442 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
1443 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
1444 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
9153b02b 1445 SD_BUS_METHOD("GetImageOSRelease", "s", "a{ss}", method_get_image_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
d6ce17c7
LP
1446 SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
1447 SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
d94c2b06 1448 SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool, SD_BUS_VTABLE_UNPRIVILEGED),
c01ff965
LP
1449 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1450 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1451 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
1452 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683
LP
1453 SD_BUS_SIGNAL("MachineNew", "so", 0),
1454 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1455 SD_BUS_VTABLE_END
1456};
1ee306e1 1457
19070062 1458int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1459 const char *path, *result, *unit;
1ee306e1 1460 Manager *m = userdata;
c3350683
LP
1461 Machine *machine;
1462 uint32_t id;
1463 int r;
1ee306e1 1464
1ee306e1 1465 assert(message);
c3350683 1466 assert(m);
1ee306e1 1467
c3350683
LP
1468 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
1469 if (r < 0) {
ebcf1f97 1470 bus_log_parse_error(r);
65d73cf0 1471 return 0;
c3350683 1472 }
6797c324 1473
c3350683
LP
1474 machine = hashmap_get(m->machine_units, unit);
1475 if (!machine)
1476 return 0;
6797c324 1477
c3350683 1478 if (streq_ptr(path, machine->scope_job)) {
491ac9f2 1479 machine->scope_job = mfree(machine->scope_job);
6797c324 1480
c3350683
LP
1481 if (machine->started) {
1482 if (streq(result, "done"))
1483 machine_send_create_reply(machine, NULL);
1484 else {
4afd3348 1485 _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 1486
ebcf1f97 1487 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 1488
ebcf1f97 1489 machine_send_create_reply(machine, &e);
c3350683 1490 }
49f3fffd
LP
1491 }
1492
1493 machine_save(machine);
1ee306e1
LP
1494 }
1495
c3350683
LP
1496 machine_add_to_gc_queue(machine);
1497 return 0;
1ee306e1
LP
1498}
1499
19070062 1500int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1501 _cleanup_free_ char *unit = NULL;
49f3fffd 1502 const char *path;
c3350683
LP
1503 Manager *m = userdata;
1504 Machine *machine;
ebcf1f97 1505 int r;
554604b3 1506
c3350683
LP
1507 assert(message);
1508 assert(m);
554604b3 1509
c3350683
LP
1510 path = sd_bus_message_get_path(message);
1511 if (!path)
554604b3 1512 return 0;
554604b3 1513
ebcf1f97 1514 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
1515 if (r == -EINVAL) /* not for a unit */
1516 return 0;
9ed794a3 1517 if (r < 0) {
9b420b3c
LP
1518 log_oom();
1519 return 0;
1520 }
554604b3 1521
c3350683 1522 machine = hashmap_get(m->machine_units, unit);
9b420b3c
LP
1523 if (!machine)
1524 return 0;
1525
9b420b3c 1526 machine_add_to_gc_queue(machine);
c3350683
LP
1527 return 0;
1528}
554604b3 1529
19070062 1530int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
1531 const char *path, *unit;
1532 Manager *m = userdata;
1533 Machine *machine;
1534 int r;
554604b3 1535
c3350683
LP
1536 assert(message);
1537 assert(m);
554604b3 1538
c3350683
LP
1539 r = sd_bus_message_read(message, "so", &unit, &path);
1540 if (r < 0) {
ebcf1f97 1541 bus_log_parse_error(r);
9b420b3c 1542 return 0;
554604b3
LP
1543 }
1544
c3350683 1545 machine = hashmap_get(m->machine_units, unit);
9b420b3c
LP
1546 if (!machine)
1547 return 0;
1548
9b420b3c 1549 machine_add_to_gc_queue(machine);
c3350683
LP
1550 return 0;
1551}
554604b3 1552
19070062 1553int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1554 Manager *m = userdata;
a658cafa
LP
1555 Machine *machine;
1556 Iterator i;
c3350683 1557 int b, r;
554604b3 1558
19070062
LP
1559 assert(message);
1560 assert(m);
554604b3 1561
c3350683
LP
1562 r = sd_bus_message_read(message, "b", &b);
1563 if (r < 0) {
ebcf1f97 1564 bus_log_parse_error(r);
65d73cf0 1565 return 0;
554604b3 1566 }
a658cafa
LP
1567 if (b)
1568 return 0;
554604b3 1569
a658cafa
LP
1570 /* systemd finished reloading, let's recheck all our machines */
1571 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 1572
a658cafa
LP
1573 HASHMAP_FOREACH(machine, m->machines, i)
1574 machine_add_to_gc_queue(machine);
554604b3
LP
1575
1576 return 0;
1577}
1578
1ee306e1
LP
1579int manager_start_scope(
1580 Manager *manager,
1581 const char *scope,
1582 pid_t pid,
1583 const char *slice,
1584 const char *description,
c3350683
LP
1585 sd_bus_message *more_properties,
1586 sd_bus_error *error,
1ee306e1
LP
1587 char **job) {
1588
4afd3348 1589 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
554604b3 1590 int r;
1ee306e1
LP
1591
1592 assert(manager);
1593 assert(scope);
1594 assert(pid > 1);
1595
c3350683
LP
1596 r = sd_bus_message_new_method_call(
1597 manager->bus,
151b9b96 1598 &m,
1ee306e1
LP
1599 "org.freedesktop.systemd1",
1600 "/org/freedesktop/systemd1",
1601 "org.freedesktop.systemd1.Manager",
151b9b96 1602 "StartTransientUnit");
c3350683
LP
1603 if (r < 0)
1604 return r;
1ee306e1 1605
a658cafa 1606 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
1607 if (r < 0)
1608 return r;
1ee306e1 1609
c3350683
LP
1610 r = sd_bus_message_open_container(m, 'a', "(sv)");
1611 if (r < 0)
1612 return r;
1ee306e1
LP
1613
1614 if (!isempty(slice)) {
c3350683
LP
1615 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1616 if (r < 0)
1617 return r;
1ee306e1
LP
1618 }
1619
1620 if (!isempty(description)) {
c3350683
LP
1621 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1622 if (r < 0)
1623 return r;
1ee306e1
LP
1624 }
1625
c3350683
LP
1626 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1627 if (r < 0)
1628 return r;
554604b3 1629
a931ad47
LP
1630 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1631 if (r < 0)
1632 return r;
1633
cf7d1a30 1634 r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", UINT64_C(16384));
b370fec2
AC
1635 if (r < 0)
1636 return bus_log_create_error(r);
1637
554604b3 1638 if (more_properties) {
c3350683 1639 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
1640 if (r < 0)
1641 return r;
1642 }
1643
c3350683
LP
1644 r = sd_bus_message_close_container(m);
1645 if (r < 0)
1646 return r;
1ee306e1 1647
86b8d289
LP
1648 r = sd_bus_message_append(m, "a(sa(sv))", 0);
1649 if (r < 0)
1650 return r;
1651
c49b30a2 1652 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
1653 if (r < 0)
1654 return r;
1ee306e1
LP
1655
1656 if (job) {
1657 const char *j;
1658 char *copy;
1659
c3350683
LP
1660 r = sd_bus_message_read(reply, "o", &j);
1661 if (r < 0)
1662 return r;
1ee306e1
LP
1663
1664 copy = strdup(j);
1665 if (!copy)
1666 return -ENOMEM;
1667
1668 *job = copy;
1669 }
1670
c3350683 1671 return 1;
1ee306e1
LP
1672}
1673
c3350683 1674int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
4afd3348 1675 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1ee306e1
LP
1676 int r;
1677
1678 assert(manager);
1679 assert(unit);
1680
c3350683 1681 r = sd_bus_call_method(
1ee306e1
LP
1682 manager->bus,
1683 "org.freedesktop.systemd1",
1684 "/org/freedesktop/systemd1",
1685 "org.freedesktop.systemd1.Manager",
1686 "StopUnit",
1ee306e1 1687 error,
c3350683
LP
1688 &reply,
1689 "ss", unit, "fail");
1ee306e1 1690 if (r < 0) {
c3350683
LP
1691 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1692 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
1693
1694 if (job)
1695 *job = NULL;
1696
c3350683 1697 sd_bus_error_free(error);
6797c324
LP
1698 return 0;
1699 }
1700
1ee306e1
LP
1701 return r;
1702 }
1703
1704 if (job) {
1705 const char *j;
1706 char *copy;
1707
c3350683
LP
1708 r = sd_bus_message_read(reply, "o", &j);
1709 if (r < 0)
1710 return r;
1ee306e1
LP
1711
1712 copy = strdup(j);
1713 if (!copy)
1714 return -ENOMEM;
1715
1716 *job = copy;
1717 }
1718
6797c324 1719 return 1;
1ee306e1
LP
1720}
1721
de58a50e 1722int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
1723 assert(manager);
1724 assert(unit);
1725
a658cafa 1726 return sd_bus_call_method(
1ee306e1
LP
1727 manager->bus,
1728 "org.freedesktop.systemd1",
1729 "/org/freedesktop/systemd1",
1730 "org.freedesktop.systemd1.Manager",
1731 "KillUnit",
1ee306e1 1732 error,
a658cafa 1733 NULL,
de58a50e 1734 "ssi", unit, "all", signo);
1ee306e1
LP
1735}
1736
1737int manager_unit_is_active(Manager *manager, const char *unit) {
4afd3348
LP
1738 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1739 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1ee306e1 1740 _cleanup_free_ char *path = NULL;
1ee306e1 1741 const char *state;
1ee306e1
LP
1742 int r;
1743
1744 assert(manager);
1745 assert(unit);
1746
1ee306e1
LP
1747 path = unit_dbus_path_from_name(unit);
1748 if (!path)
1749 return -ENOMEM;
1750
c3350683 1751 r = sd_bus_get_property(
1ee306e1
LP
1752 manager->bus,
1753 "org.freedesktop.systemd1",
1754 path,
c3350683
LP
1755 "org.freedesktop.systemd1.Unit",
1756 "ActiveState",
1ee306e1 1757 &error,
c3350683
LP
1758 &reply,
1759 "s");
1ee306e1 1760 if (r < 0) {
c3350683
LP
1761 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1762 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 1763 return true;
6797c324 1764
c3350683
LP
1765 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1766 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 1767 return false;
6797c324 1768
1ee306e1
LP
1769 return r;
1770 }
1771
c3350683
LP
1772 r = sd_bus_message_read(reply, "s", &state);
1773 if (r < 0)
1ee306e1 1774 return -EINVAL;
1ee306e1 1775
9b420b3c 1776 return !STR_IN_SET(state, "inactive", "failed");
1ee306e1 1777}
bd16acf3 1778
c3350683 1779int manager_job_is_active(Manager *manager, const char *path) {
4afd3348
LP
1780 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1781 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
c3350683 1782 int r;
bd16acf3 1783
c3350683
LP
1784 assert(manager);
1785 assert(path);
bd16acf3 1786
c3350683
LP
1787 r = sd_bus_get_property(
1788 manager->bus,
1789 "org.freedesktop.systemd1",
1790 path,
1791 "org.freedesktop.systemd1.Job",
1792 "State",
1793 &error,
1794 &reply,
1795 "s");
1796 if (r < 0) {
1797 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1798 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1799 return true;
bd16acf3 1800
c3350683
LP
1801 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1802 return false;
bd16acf3 1803
bd16acf3 1804 return r;
c3350683 1805 }
bd16acf3 1806
c3350683
LP
1807 /* We don't actually care about the state really. The fact
1808 * that we could read the job state is enough for us */
bd16acf3 1809
c3350683 1810 return true;
bd16acf3 1811}
ab49725f
KS
1812
1813int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
ab49725f
KS
1814 Machine *mm;
1815 int r;
1816
1817 assert(m);
1818 assert(pid >= 1);
1819 assert(machine);
1820
4a0b58c4 1821 mm = hashmap_get(m->machine_leaders, PID_TO_PTR(pid));
077c8c36
LP
1822 if (!mm) {
1823 _cleanup_free_ char *unit = NULL;
ab49725f 1824
077c8c36
LP
1825 r = cg_pid_get_unit(pid, &unit);
1826 if (r >= 0)
1827 mm = hashmap_get(m->machine_units, unit);
1828 }
ab49725f
KS
1829 if (!mm)
1830 return 0;
1831
1832 *machine = mm;
1833 return 1;
1834}
1835
1836int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1837 Machine *machine;
1838
1839 assert(m);
1840 assert(name);
1841
1842 machine = hashmap_get(m->machines, name);
1843 if (!machine) {
fbe55073 1844 machine = machine_new(m, _MACHINE_CLASS_INVALID, name);
ab49725f
KS
1845 if (!machine)
1846 return -ENOMEM;
1847 }
1848
1849 if (_machine)
1850 *_machine = machine;
1851
1852 return 0;
1853}
9153b02b
LP
1854
1855int bus_reply_pair_array(sd_bus_message *m, char **l) {
1856 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1857 char **k, **v;
1858 int r;
1859
1860 r = sd_bus_message_new_method_return(m, &reply);
1861 if (r < 0)
1862 return r;
1863
1864 r = sd_bus_message_open_container(reply, 'a', "{ss}");
1865 if (r < 0)
1866 return r;
1867
1868 STRV_FOREACH_PAIR(k, v, l) {
1869 r = sd_bus_message_append(reply, "{ss}", *k, *v);
1870 if (r < 0)
1871 return r;
1872 }
1873
1874 r = sd_bus_message_close_container(reply);
1875 if (r < 0)
1876 return r;
1877
1878 return sd_bus_send(NULL, reply, NULL);
1879
1880}