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