]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
Merge pull request #7398 from keszybz/udev-list
[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
cf30a8c1
LP
849static int method_get_image_hostname(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_hostname(message, i, error);
871}
872
873static int method_get_image_machine_id(sd_bus_message *message, void *userdata, sd_bus_error *error) {
874 _cleanup_(image_unrefp) Image *i = NULL;
875 const char *name;
876 int r;
877
878 assert(message);
879
880 r = sd_bus_message_read(message, "s", &name);
881 if (r < 0)
882 return r;
883
884 if (!image_name_is_valid(name))
885 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
886
887 r = image_find(name, &i);
888 if (r < 0)
889 return r;
890 if (r == 0)
891 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
892
893 i->userdata = userdata;
894 return bus_image_method_get_machine_id(message, i, error);
895}
896
897static int method_get_image_machine_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
898 _cleanup_(image_unrefp) Image *i = NULL;
899 const char *name;
900 int r;
901
902 assert(message);
903
904 r = sd_bus_message_read(message, "s", &name);
905 if (r < 0)
906 return r;
907
908 if (!image_name_is_valid(name))
909 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
910
911 r = image_find(name, &i);
912 if (r < 0)
913 return r;
914 if (r == 0)
915 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
916
917 i->userdata = userdata;
918 return bus_image_method_get_machine_info(message, i, error);
919}
920
9153b02b
LP
921static int method_get_image_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
922 _cleanup_(image_unrefp) Image *i = NULL;
923 const char *name;
924 int r;
925
926 assert(message);
927
928 r = sd_bus_message_read(message, "s", &name);
929 if (r < 0)
930 return r;
931
932 if (!image_name_is_valid(name))
933 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
934
935 r = image_find(name, &i);
936 if (r < 0)
937 return r;
938 if (r == 0)
939 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
940
941 i->userdata = userdata;
942 return bus_image_method_get_os_release(message, i, error);
943}
944
03c2b288
LP
945static int clean_pool_done(Operation *operation, int ret, sd_bus_error *error) {
946 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
947 _cleanup_fclose_ FILE *f = NULL;
948 bool success;
949 size_t n;
950 int r;
951
952 assert(operation);
953 assert(operation->extra_fd >= 0);
954
955 if (lseek(operation->extra_fd, 0, SEEK_SET) == (off_t) -1)
956 return -errno;
957
958 f = fdopen(operation->extra_fd, "re");
959 if (!f)
960 return -errno;
961
962 operation->extra_fd = -1;
963
964 /* The resulting temporary file starts with a boolean value that indicates success or not. */
965 errno = 0;
966 n = fread(&success, 1, sizeof(success), f);
967 if (n != sizeof(success))
968 return ret < 0 ? ret : (errno != 0 ? -errno : -EIO);
969
970 if (ret < 0) {
971 _cleanup_free_ char *name = NULL;
972
973 /* The clean-up operation failed. In this case the resulting temporary file should contain a boolean
974 * set to false followed by the name of the failed image. Let's try to read this and use it for the
975 * error message. If we can't read it, don't mind, and return the naked error. */
976
977 if (success) /* The resulting temporary file could not be updated, ignore it. */
978 return ret;
979
980 r = read_nul_string(f, &name);
981 if (r < 0 || isempty(name)) /* Same here... */
982 return ret;
983
984 return sd_bus_error_set_errnof(error, ret, "Failed to remove image %s: %m", name);
985 }
986
987 assert(success);
988
989 r = sd_bus_message_new_method_return(operation->message, &reply);
990 if (r < 0)
991 return r;
992
993 r = sd_bus_message_open_container(reply, 'a', "(st)");
994 if (r < 0)
995 return r;
996
997 /* On success the resulting temporary file will contain a list of image names that were removed followed by
998 * their size on disk. Let's read that and turn it into a bus message. */
999 for (;;) {
1000 _cleanup_free_ char *name = NULL;
1001 uint64_t size;
1002
1003 r = read_nul_string(f, &name);
1004 if (r < 0)
1005 return r;
1006 if (isempty(name)) /* reached the end */
1007 break;
1008
1009 errno = 0;
1010 n = fread(&size, 1, sizeof(size), f);
1011 if (n != sizeof(size))
1012 return errno != 0 ? -errno : -EIO;
1013
1014 r = sd_bus_message_append(reply, "(st)", name, size);
1015 if (r < 0)
1016 return r;
1017 }
1018
1019 r = sd_bus_message_close_container(reply);
1020 if (r < 0)
1021 return r;
1022
1023 return sd_bus_send(NULL, reply, NULL);
1024}
1025
d94c2b06
LP
1026static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1027 enum {
1028 REMOVE_ALL,
1029 REMOVE_HIDDEN,
1030 } mode;
1031
03c2b288
LP
1032 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
1033 _cleanup_close_ int result_fd = -1;
d94c2b06 1034 Manager *m = userdata;
03c2b288 1035 Operation *operation;
d94c2b06 1036 const char *mm;
03c2b288 1037 pid_t child;
d94c2b06
LP
1038 int r;
1039
1040 assert(message);
1041
03c2b288
LP
1042 if (m->n_operations >= OPERATIONS_MAX)
1043 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
1044
d94c2b06
LP
1045 r = sd_bus_message_read(message, "s", &mm);
1046 if (r < 0)
1047 return r;
1048
1049 if (streq(mm, "all"))
1050 mode = REMOVE_ALL;
1051 else if (streq(mm, "hidden"))
1052 mode = REMOVE_HIDDEN;
1053 else
1054 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mode '%s'.", mm);
1055
1056 r = bus_verify_polkit_async(
1057 message,
1058 CAP_SYS_ADMIN,
1059 "org.freedesktop.machine1.manage-machines",
1060 NULL,
1061 false,
1062 UID_INVALID,
1063 &m->polkit_registry,
1064 error);
1065 if (r < 0)
1066 return r;
1067 if (r == 0)
1068 return 1; /* Will call us back */
1069
03c2b288
LP
1070 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
1071 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
d94c2b06 1072
03c2b288
LP
1073 /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
1074 * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
595bfe7d 1075 * continuously */
992e8f22 1076 result_fd = open_tmpfile_unlinkable(NULL, O_RDWR|O_CLOEXEC);
03c2b288
LP
1077 if (result_fd < 0)
1078 return -errno;
d94c2b06 1079
03c2b288
LP
1080 /* This might be a slow operation, run it asynchronously in a background process */
1081 child = fork();
1082 if (child < 0)
1083 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
d94c2b06 1084
03c2b288
LP
1085 if (child == 0) {
1086 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
1087 bool success = true;
1088 Image *image;
1089 Iterator i;
1090 ssize_t l;
d94c2b06 1091
03c2b288 1092 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
d94c2b06 1093
03c2b288
LP
1094 images = hashmap_new(&string_hash_ops);
1095 if (!images) {
1096 r = -ENOMEM;
1097 goto child_fail;
1098 }
d94c2b06 1099
03c2b288
LP
1100 r = image_discover(images);
1101 if (r < 0)
1102 goto child_fail;
d94c2b06 1103
03c2b288
LP
1104 l = write(result_fd, &success, sizeof(success));
1105 if (l < 0) {
1106 r = -errno;
1107 goto child_fail;
1108 }
d94c2b06 1109
03c2b288
LP
1110 HASHMAP_FOREACH(image, images, i) {
1111
1112 /* We can't remove vendor images (i.e. those in /usr) */
1113 if (IMAGE_IS_VENDOR(image))
1114 continue;
1115
1116 if (IMAGE_IS_HOST(image))
1117 continue;
1118
1119 if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image))
1120 continue;
1121
1122 r = image_remove(image);
1123 if (r == -EBUSY) /* keep images that are currently being used. */
1124 continue;
1125 if (r < 0) {
1126 /* If the operation failed, let's override everything we wrote, and instead write there at which image we failed. */
1127 success = false;
1128 (void) ftruncate(result_fd, 0);
1129 (void) lseek(result_fd, 0, SEEK_SET);
1130 (void) write(result_fd, &success, sizeof(success));
1131 (void) write(result_fd, image->name, strlen(image->name)+1);
1132 goto child_fail;
1133 }
1134
1135 l = write(result_fd, image->name, strlen(image->name)+1);
1136 if (l < 0) {
1137 r = -errno;
1138 goto child_fail;
1139 }
1140
1141 l = write(result_fd, &image->usage_exclusive, sizeof(image->usage_exclusive));
1142 if (l < 0) {
1143 r = -errno;
1144 goto child_fail;
1145 }
1146 }
d94c2b06 1147
03c2b288
LP
1148 result_fd = safe_close(result_fd);
1149 _exit(EXIT_SUCCESS);
1150
1151 child_fail:
1152 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1153 _exit(EXIT_FAILURE);
d94c2b06
LP
1154 }
1155
03c2b288
LP
1156 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1157
1158 /* The clean-up might take a while, hence install a watch on the child and return */
1159
1160 r = operation_new(m, NULL, child, message, errno_pipe_fd[0], &operation);
1161 if (r < 0) {
1162 (void) sigkill_wait(child);
d94c2b06 1163 return r;
03c2b288 1164 }
d94c2b06 1165
03c2b288
LP
1166 operation->extra_fd = result_fd;
1167 operation->done = clean_pool_done;
1168
1169 result_fd = -1;
1170 errno_pipe_fd[0] = -1;
1171
1172 return 1;
d94c2b06
LP
1173}
1174
19070062 1175static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d6ce17c7
LP
1176 Manager *m = userdata;
1177 uint64_t limit;
1178 int r;
1179
19070062
LP
1180 assert(message);
1181
d6ce17c7
LP
1182 r = sd_bus_message_read(message, "t", &limit);
1183 if (r < 0)
1184 return r;
a90fb858
LP
1185 if (!FILE_SIZE_VALID_OR_INFINITY(limit))
1186 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
d6ce17c7
LP
1187
1188 r = bus_verify_polkit_async(
1189 message,
1190 CAP_SYS_ADMIN,
1191 "org.freedesktop.machine1.manage-machines",
403ed0e5 1192 NULL,
d6ce17c7
LP
1193 false,
1194 UID_INVALID,
1195 &m->polkit_registry,
1196 error);
1197 if (r < 0)
1198 return r;
1199 if (r == 0)
1200 return 1; /* Will call us back */
1201
4cee5eed
LP
1202 /* Set up the machine directory if necessary */
1203 r = setup_machine_directory(limit, error);
1204 if (r < 0)
1205 return r;
1206
05e8f270
LP
1207 /* Resize the backing loopback device, if there is one, except if we asked to drop any limit */
1208 if (limit != (uint64_t) -1) {
1209 r = btrfs_resize_loopback("/var/lib/machines", limit, false);
1210 if (r == -ENOTTY)
1211 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
1212 if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
1213 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
1214 }
efe02862 1215
5bcd08db
LP
1216 (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit);
1217
1218 r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit);
d6ce17c7
LP
1219 if (r == -ENOTTY)
1220 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
26166c88 1221 if (r < 0)
d6ce17c7
LP
1222 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
1223
1224 return sd_bus_reply_method_return(message, NULL);
1225}
1226
19070062 1227static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d6ce17c7
LP
1228 _cleanup_(image_unrefp) Image *i = NULL;
1229 const char *name;
1230 int r;
1231
19070062
LP
1232 assert(message);
1233
d6ce17c7
LP
1234 r = sd_bus_message_read(message, "s", &name);
1235 if (r < 0)
1236 return r;
1237
1238 if (!image_name_is_valid(name))
1239 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
1240
1241 r = image_find(name, &i);
1242 if (r < 0)
1243 return r;
1244 if (r == 0)
1245 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
1246
1247 i->userdata = userdata;
19070062 1248 return bus_image_method_set_limit(message, i, error);
d6ce17c7
LP
1249}
1250
c01ff965
LP
1251static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1252 _cleanup_fclose_ FILE *f = NULL;
1253 Manager *m = userdata;
1254 const char *name, *p;
1255 Machine *machine;
1256 uint32_t uid;
1257 int r;
1258
1259 r = sd_bus_message_read(message, "su", &name, &uid);
1260 if (r < 0)
1261 return r;
1262
c077529b 1263 if (!uid_is_valid(uid))
c01ff965
LP
1264 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
1265
1266 machine = hashmap_get(m->machines, name);
1267 if (!machine)
1268 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1269
a79366e2
LP
1270 if (machine->class != MACHINE_CONTAINER)
1271 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
1272
c01ff965
LP
1273 p = procfs_file_alloca(machine->leader, "uid_map");
1274 f = fopen(p, "re");
1275 if (!f)
1276 return -errno;
1277
1278 for (;;) {
1279 uid_t uid_base, uid_shift, uid_range, converted;
1280 int k;
1281
1282 errno = 0;
1283 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
1284 if (k < 0 && feof(f))
1285 break;
1286 if (k != 3) {
b3267152 1287 if (ferror(f) && errno > 0)
c01ff965
LP
1288 return -errno;
1289
1290 return -EIO;
1291 }
1292
1293 if (uid < uid_base || uid >= uid_base + uid_range)
1294 continue;
1295
1296 converted = uid - uid_base + uid_shift;
c077529b 1297 if (!uid_is_valid(converted))
c01ff965
LP
1298 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
1299
1300 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
1301 }
1302
1303 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
1304}
1305
1306static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1307 Manager *m = userdata;
1308 Machine *machine;
1309 uid_t uid;
1310 Iterator i;
1311 int r;
1312
1313 r = sd_bus_message_read(message, "u", &uid);
1314 if (r < 0)
1315 return r;
c077529b 1316 if (!uid_is_valid(uid))
c01ff965
LP
1317 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
1318 if (uid < 0x10000)
1319 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
1320
1321 HASHMAP_FOREACH(machine, m->machines, i) {
1322 _cleanup_fclose_ FILE *f = NULL;
1323 char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
1324
a79366e2
LP
1325 if (machine->class != MACHINE_CONTAINER)
1326 continue;
1327
c01ff965
LP
1328 xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
1329 f = fopen(p, "re");
1330 if (!f) {
1331 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
1332 continue;
1333 }
1334
1335 for (;;) {
1336 _cleanup_free_ char *o = NULL;
1337 uid_t uid_base, uid_shift, uid_range, converted;
1338 int k;
1339
1340 errno = 0;
1341 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
1342 if (k < 0 && feof(f))
1343 break;
1344 if (k != 3) {
b3267152 1345 if (ferror(f) && errno > 0)
c01ff965
LP
1346 return -errno;
1347
1348 return -EIO;
1349 }
1350
1351 if (uid < uid_shift || uid >= uid_shift + uid_range)
1352 continue;
1353
1354 converted = (uid - uid_shift + uid_base);
c077529b 1355 if (!uid_is_valid(converted))
c01ff965
LP
1356 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
1357
1358 o = machine_bus_path(machine);
1359 if (!o)
1360 return -ENOMEM;
1361
1362 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
1363 }
1364 }
1365
1366 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
1367}
1368
1369static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
1370 _cleanup_fclose_ FILE *f = NULL;
1371 Manager *m = groupdata;
1372 const char *name, *p;
1373 Machine *machine;
1374 uint32_t gid;
1375 int r;
1376
1377 r = sd_bus_message_read(message, "su", &name, &gid);
1378 if (r < 0)
1379 return r;
1380
c077529b 1381 if (!gid_is_valid(gid))
c01ff965
LP
1382 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1383
1384 machine = hashmap_get(m->machines, name);
1385 if (!machine)
1386 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1387
a79366e2
LP
1388 if (machine->class != MACHINE_CONTAINER)
1389 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
1390
c01ff965
LP
1391 p = procfs_file_alloca(machine->leader, "gid_map");
1392 f = fopen(p, "re");
1393 if (!f)
1394 return -errno;
1395
1396 for (;;) {
1397 gid_t gid_base, gid_shift, gid_range, converted;
1398 int k;
1399
1400 errno = 0;
1401 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1402 if (k < 0 && feof(f))
1403 break;
1404 if (k != 3) {
b3267152 1405 if (ferror(f) && errno > 0)
c01ff965
LP
1406 return -errno;
1407
1408 return -EIO;
1409 }
1410
1411 if (gid < gid_base || gid >= gid_base + gid_range)
1412 continue;
1413
1414 converted = gid - gid_base + gid_shift;
c077529b 1415 if (!gid_is_valid(converted))
c01ff965
LP
1416 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1417
1418 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
1419 }
1420
1421 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
1422}
1423
1424static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
1425 Manager *m = groupdata;
1426 Machine *machine;
1427 gid_t gid;
1428 Iterator i;
1429 int r;
1430
1431 r = sd_bus_message_read(message, "u", &gid);
1432 if (r < 0)
1433 return r;
c077529b 1434 if (!gid_is_valid(gid))
c01ff965
LP
1435 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1436 if (gid < 0x10000)
1437 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
1438
1439 HASHMAP_FOREACH(machine, m->machines, i) {
1440 _cleanup_fclose_ FILE *f = NULL;
1441 char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
1442
a79366e2
LP
1443 if (machine->class != MACHINE_CONTAINER)
1444 continue;
1445
c01ff965
LP
1446 xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
1447 f = fopen(p, "re");
1448 if (!f) {
1449 log_warning_errno(errno, "Failed top open %s, ignoring,", p);
1450 continue;
1451 }
1452
1453 for (;;) {
1454 _cleanup_free_ char *o = NULL;
1455 gid_t gid_base, gid_shift, gid_range, converted;
1456 int k;
1457
1458 errno = 0;
1459 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1460 if (k < 0 && feof(f))
1461 break;
1462 if (k != 3) {
b3267152 1463 if (ferror(f) && errno > 0)
c01ff965
LP
1464 return -errno;
1465
1466 return -EIO;
1467 }
1468
1469 if (gid < gid_shift || gid >= gid_shift + gid_range)
1470 continue;
1471
1472 converted = (gid - gid_shift + gid_base);
c077529b 1473 if (!gid_is_valid(converted))
c01ff965
LP
1474 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1475
1476 o = machine_bus_path(machine);
1477 if (!o)
1478 return -ENOMEM;
1479
1480 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
1481 }
1482 }
1483
1484 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
1485}
1486
c3350683
LP
1487const sd_bus_vtable manager_vtable[] = {
1488 SD_BUS_VTABLE_START(0),
160e3793
LP
1489 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
1490 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
1491 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
adacb957 1492 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 1493 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
1494 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
1495 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
b6b18498 1496 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 1497 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 1498 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 1499 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 1500 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
70244d1d
LP
1501 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1502 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
3a6fb33c 1503 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1504 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 1505 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
d04c1fb8 1506 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
49af9e13 1507 SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
1508 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1509 SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1510 SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
ae203207 1511 SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
3401419b 1512 SD_BUS_METHOD("GetMachineUIDShift", "s", "u", method_get_machine_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
1513 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
1514 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
1515 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
1516 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
cf30a8c1
LP
1517 SD_BUS_METHOD("GetImageHostname", "s", "s", method_get_image_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
1518 SD_BUS_METHOD("GetImageMachineID", "s", "ay", method_get_image_machine_id, SD_BUS_VTABLE_UNPRIVILEGED),
1519 SD_BUS_METHOD("GetImageMachineInfo", "s", "a{ss}", method_get_image_machine_info, SD_BUS_VTABLE_UNPRIVILEGED),
9153b02b 1520 SD_BUS_METHOD("GetImageOSRelease", "s", "a{ss}", method_get_image_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
d6ce17c7
LP
1521 SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
1522 SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
d94c2b06 1523 SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool, SD_BUS_VTABLE_UNPRIVILEGED),
c01ff965
LP
1524 SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1525 SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1526 SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
1527 SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683
LP
1528 SD_BUS_SIGNAL("MachineNew", "so", 0),
1529 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1530 SD_BUS_VTABLE_END
1531};
1ee306e1 1532
19070062 1533int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1534 const char *path, *result, *unit;
1ee306e1 1535 Manager *m = userdata;
c3350683
LP
1536 Machine *machine;
1537 uint32_t id;
1538 int r;
1ee306e1 1539
1ee306e1 1540 assert(message);
c3350683 1541 assert(m);
1ee306e1 1542
c3350683
LP
1543 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
1544 if (r < 0) {
ebcf1f97 1545 bus_log_parse_error(r);
65d73cf0 1546 return 0;
c3350683 1547 }
6797c324 1548
c3350683
LP
1549 machine = hashmap_get(m->machine_units, unit);
1550 if (!machine)
1551 return 0;
6797c324 1552
c3350683 1553 if (streq_ptr(path, machine->scope_job)) {
491ac9f2 1554 machine->scope_job = mfree(machine->scope_job);
6797c324 1555
c3350683
LP
1556 if (machine->started) {
1557 if (streq(result, "done"))
1558 machine_send_create_reply(machine, NULL);
1559 else {
4afd3348 1560 _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 1561
ebcf1f97 1562 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 1563
ebcf1f97 1564 machine_send_create_reply(machine, &e);
c3350683 1565 }
49f3fffd
LP
1566 }
1567
1568 machine_save(machine);
1ee306e1
LP
1569 }
1570
c3350683
LP
1571 machine_add_to_gc_queue(machine);
1572 return 0;
1ee306e1
LP
1573}
1574
19070062 1575int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1576 _cleanup_free_ char *unit = NULL;
49f3fffd 1577 const char *path;
c3350683
LP
1578 Manager *m = userdata;
1579 Machine *machine;
ebcf1f97 1580 int r;
554604b3 1581
c3350683
LP
1582 assert(message);
1583 assert(m);
554604b3 1584
c3350683
LP
1585 path = sd_bus_message_get_path(message);
1586 if (!path)
554604b3 1587 return 0;
554604b3 1588
ebcf1f97 1589 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
1590 if (r == -EINVAL) /* not for a unit */
1591 return 0;
9ed794a3 1592 if (r < 0) {
9b420b3c
LP
1593 log_oom();
1594 return 0;
1595 }
554604b3 1596
c3350683 1597 machine = hashmap_get(m->machine_units, unit);
9b420b3c
LP
1598 if (!machine)
1599 return 0;
1600
9b420b3c 1601 machine_add_to_gc_queue(machine);
c3350683
LP
1602 return 0;
1603}
554604b3 1604
19070062 1605int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
1606 const char *path, *unit;
1607 Manager *m = userdata;
1608 Machine *machine;
1609 int r;
554604b3 1610
c3350683
LP
1611 assert(message);
1612 assert(m);
554604b3 1613
c3350683
LP
1614 r = sd_bus_message_read(message, "so", &unit, &path);
1615 if (r < 0) {
ebcf1f97 1616 bus_log_parse_error(r);
9b420b3c 1617 return 0;
554604b3
LP
1618 }
1619
c3350683 1620 machine = hashmap_get(m->machine_units, unit);
9b420b3c
LP
1621 if (!machine)
1622 return 0;
1623
9b420b3c 1624 machine_add_to_gc_queue(machine);
c3350683
LP
1625 return 0;
1626}
554604b3 1627
19070062 1628int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1629 Manager *m = userdata;
a658cafa
LP
1630 Machine *machine;
1631 Iterator i;
c3350683 1632 int b, r;
554604b3 1633
19070062
LP
1634 assert(message);
1635 assert(m);
554604b3 1636
c3350683
LP
1637 r = sd_bus_message_read(message, "b", &b);
1638 if (r < 0) {
ebcf1f97 1639 bus_log_parse_error(r);
65d73cf0 1640 return 0;
554604b3 1641 }
a658cafa
LP
1642 if (b)
1643 return 0;
554604b3 1644
a658cafa
LP
1645 /* systemd finished reloading, let's recheck all our machines */
1646 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 1647
a658cafa
LP
1648 HASHMAP_FOREACH(machine, m->machines, i)
1649 machine_add_to_gc_queue(machine);
554604b3
LP
1650
1651 return 0;
1652}
1653
1ee306e1
LP
1654int manager_start_scope(
1655 Manager *manager,
1656 const char *scope,
1657 pid_t pid,
1658 const char *slice,
1659 const char *description,
c3350683
LP
1660 sd_bus_message *more_properties,
1661 sd_bus_error *error,
1ee306e1
LP
1662 char **job) {
1663
4afd3348 1664 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
554604b3 1665 int r;
1ee306e1
LP
1666
1667 assert(manager);
1668 assert(scope);
1669 assert(pid > 1);
1670
c3350683
LP
1671 r = sd_bus_message_new_method_call(
1672 manager->bus,
151b9b96 1673 &m,
1ee306e1
LP
1674 "org.freedesktop.systemd1",
1675 "/org/freedesktop/systemd1",
1676 "org.freedesktop.systemd1.Manager",
151b9b96 1677 "StartTransientUnit");
c3350683
LP
1678 if (r < 0)
1679 return r;
1ee306e1 1680
a658cafa 1681 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
1682 if (r < 0)
1683 return r;
1ee306e1 1684
c3350683
LP
1685 r = sd_bus_message_open_container(m, 'a', "(sv)");
1686 if (r < 0)
1687 return r;
1ee306e1
LP
1688
1689 if (!isempty(slice)) {
c3350683
LP
1690 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1691 if (r < 0)
1692 return r;
1ee306e1
LP
1693 }
1694
1695 if (!isempty(description)) {
c3350683
LP
1696 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1697 if (r < 0)
1698 return r;
1ee306e1
LP
1699 }
1700
c3350683
LP
1701 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1702 if (r < 0)
1703 return r;
554604b3 1704
a931ad47
LP
1705 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1706 if (r < 0)
1707 return r;
1708
cf7d1a30 1709 r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", UINT64_C(16384));
b370fec2
AC
1710 if (r < 0)
1711 return bus_log_create_error(r);
1712
554604b3 1713 if (more_properties) {
c3350683 1714 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
1715 if (r < 0)
1716 return r;
1717 }
1718
c3350683
LP
1719 r = sd_bus_message_close_container(m);
1720 if (r < 0)
1721 return r;
1ee306e1 1722
86b8d289
LP
1723 r = sd_bus_message_append(m, "a(sa(sv))", 0);
1724 if (r < 0)
1725 return r;
1726
c49b30a2 1727 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
1728 if (r < 0)
1729 return r;
1ee306e1
LP
1730
1731 if (job) {
1732 const char *j;
1733 char *copy;
1734
c3350683
LP
1735 r = sd_bus_message_read(reply, "o", &j);
1736 if (r < 0)
1737 return r;
1ee306e1
LP
1738
1739 copy = strdup(j);
1740 if (!copy)
1741 return -ENOMEM;
1742
1743 *job = copy;
1744 }
1745
c3350683 1746 return 1;
1ee306e1
LP
1747}
1748
c3350683 1749int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
4afd3348 1750 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1ee306e1
LP
1751 int r;
1752
1753 assert(manager);
1754 assert(unit);
1755
c3350683 1756 r = sd_bus_call_method(
1ee306e1
LP
1757 manager->bus,
1758 "org.freedesktop.systemd1",
1759 "/org/freedesktop/systemd1",
1760 "org.freedesktop.systemd1.Manager",
1761 "StopUnit",
1ee306e1 1762 error,
c3350683
LP
1763 &reply,
1764 "ss", unit, "fail");
1ee306e1 1765 if (r < 0) {
c3350683
LP
1766 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1767 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
1768
1769 if (job)
1770 *job = NULL;
1771
c3350683 1772 sd_bus_error_free(error);
6797c324
LP
1773 return 0;
1774 }
1775
1ee306e1
LP
1776 return r;
1777 }
1778
1779 if (job) {
1780 const char *j;
1781 char *copy;
1782
c3350683
LP
1783 r = sd_bus_message_read(reply, "o", &j);
1784 if (r < 0)
1785 return r;
1ee306e1
LP
1786
1787 copy = strdup(j);
1788 if (!copy)
1789 return -ENOMEM;
1790
1791 *job = copy;
1792 }
1793
6797c324 1794 return 1;
1ee306e1
LP
1795}
1796
de58a50e 1797int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
1798 assert(manager);
1799 assert(unit);
1800
a658cafa 1801 return sd_bus_call_method(
1ee306e1
LP
1802 manager->bus,
1803 "org.freedesktop.systemd1",
1804 "/org/freedesktop/systemd1",
1805 "org.freedesktop.systemd1.Manager",
1806 "KillUnit",
1ee306e1 1807 error,
a658cafa 1808 NULL,
de58a50e 1809 "ssi", unit, "all", signo);
1ee306e1
LP
1810}
1811
1812int manager_unit_is_active(Manager *manager, const char *unit) {
4afd3348
LP
1813 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1814 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1ee306e1 1815 _cleanup_free_ char *path = NULL;
1ee306e1 1816 const char *state;
1ee306e1
LP
1817 int r;
1818
1819 assert(manager);
1820 assert(unit);
1821
1ee306e1
LP
1822 path = unit_dbus_path_from_name(unit);
1823 if (!path)
1824 return -ENOMEM;
1825
c3350683 1826 r = sd_bus_get_property(
1ee306e1
LP
1827 manager->bus,
1828 "org.freedesktop.systemd1",
1829 path,
c3350683
LP
1830 "org.freedesktop.systemd1.Unit",
1831 "ActiveState",
1ee306e1 1832 &error,
c3350683
LP
1833 &reply,
1834 "s");
1ee306e1 1835 if (r < 0) {
c3350683
LP
1836 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1837 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 1838 return true;
6797c324 1839
c3350683
LP
1840 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1841 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 1842 return false;
6797c324 1843
1ee306e1
LP
1844 return r;
1845 }
1846
c3350683
LP
1847 r = sd_bus_message_read(reply, "s", &state);
1848 if (r < 0)
1ee306e1 1849 return -EINVAL;
1ee306e1 1850
9b420b3c 1851 return !STR_IN_SET(state, "inactive", "failed");
1ee306e1 1852}
bd16acf3 1853
c3350683 1854int manager_job_is_active(Manager *manager, const char *path) {
4afd3348
LP
1855 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1856 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
c3350683 1857 int r;
bd16acf3 1858
c3350683
LP
1859 assert(manager);
1860 assert(path);
bd16acf3 1861
c3350683
LP
1862 r = sd_bus_get_property(
1863 manager->bus,
1864 "org.freedesktop.systemd1",
1865 path,
1866 "org.freedesktop.systemd1.Job",
1867 "State",
1868 &error,
1869 &reply,
1870 "s");
1871 if (r < 0) {
1872 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1873 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1874 return true;
bd16acf3 1875
c3350683
LP
1876 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1877 return false;
bd16acf3 1878
bd16acf3 1879 return r;
c3350683 1880 }
bd16acf3 1881
c3350683
LP
1882 /* We don't actually care about the state really. The fact
1883 * that we could read the job state is enough for us */
bd16acf3 1884
c3350683 1885 return true;
bd16acf3 1886}
ab49725f
KS
1887
1888int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
ab49725f
KS
1889 Machine *mm;
1890 int r;
1891
1892 assert(m);
1893 assert(pid >= 1);
1894 assert(machine);
1895
4a0b58c4 1896 mm = hashmap_get(m->machine_leaders, PID_TO_PTR(pid));
077c8c36
LP
1897 if (!mm) {
1898 _cleanup_free_ char *unit = NULL;
ab49725f 1899
077c8c36
LP
1900 r = cg_pid_get_unit(pid, &unit);
1901 if (r >= 0)
1902 mm = hashmap_get(m->machine_units, unit);
1903 }
ab49725f
KS
1904 if (!mm)
1905 return 0;
1906
1907 *machine = mm;
1908 return 1;
1909}
1910
1911int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1912 Machine *machine;
1913
1914 assert(m);
1915 assert(name);
1916
1917 machine = hashmap_get(m->machines, name);
1918 if (!machine) {
fbe55073 1919 machine = machine_new(m, _MACHINE_CLASS_INVALID, name);
ab49725f
KS
1920 if (!machine)
1921 return -ENOMEM;
1922 }
1923
1924 if (_machine)
1925 *_machine = machine;
1926
1927 return 0;
1928}
9153b02b
LP
1929
1930int bus_reply_pair_array(sd_bus_message *m, char **l) {
1931 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1932 char **k, **v;
1933 int r;
1934
1935 r = sd_bus_message_new_method_return(m, &reply);
1936 if (r < 0)
1937 return r;
1938
1939 r = sd_bus_message_open_container(reply, 'a', "{ss}");
1940 if (r < 0)
1941 return r;
1942
1943 STRV_FOREACH_PAIR(k, v, l) {
1944 r = sd_bus_message_append(reply, "{ss}", *k, *v);
1945 if (r < 0)
1946 return r;
1947 }
1948
1949 r = sd_bus_message_close_container(reply);
1950 if (r < 0)
1951 return r;
1952
1953 return sd_bus_send(NULL, reply, NULL);
1954
1955}