]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
man: fix typo
[thirdparty/systemd.git] / src / machine / machined-dbus.c
CommitLineData
1ee306e1
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <string.h>
24#include <unistd.h>
1ee306e1 25
c3350683 26#include "sd-id128.h"
1ee306e1 27#include "path-util.h"
1ee306e1 28#include "unit-name.h"
c3350683 29#include "bus-util.h"
96aad8d1 30#include "bus-common-errors.h"
23c80348 31#include "cgroup-util.h"
160e3793 32#include "btrfs-util.h"
003dffde 33#include "machine-image.h"
4cee5eed 34#include "machine-pool.h"
003dffde 35#include "image-dbus.h"
c3350683 36#include "machined.h"
003dffde 37#include "machine-dbus.h"
1ee306e1 38
160e3793
LP
39static int property_get_pool_path(
40 sd_bus *bus,
41 const char *path,
42 const char *interface,
43 const char *property,
44 sd_bus_message *reply,
45 void *userdata,
46 sd_bus_error *error) {
47
48 assert(bus);
49 assert(reply);
50
51 return sd_bus_message_append(reply, "s", "/var/lib/machines");
52}
53
54static int property_get_pool_usage(
55 sd_bus *bus,
56 const char *path,
57 const char *interface,
58 const char *property,
59 sd_bus_message *reply,
60 void *userdata,
61 sd_bus_error *error) {
62
63 _cleanup_close_ int fd = -1;
64 uint64_t usage = (uint64_t) -1;
65 struct stat st;
66
67 assert(bus);
68 assert(reply);
69
70 /* We try to read the quota info from /var/lib/machines, as
71 * well as the usage of the loopback file
72 * /var/lib/machines.raw, and pick the larger value. */
73
74 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
75 if (fd >= 0) {
76 BtrfsQuotaInfo q;
77
78 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
79 usage = q.referred;
80 }
81
82 if (stat("/var/lib/machines.raw", &st) >= 0) {
83 if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
84 usage = st.st_blocks * 512ULL;
85 }
86
87 return sd_bus_message_append(reply, "t", usage);
88}
89
90static int property_get_pool_limit(
91 sd_bus *bus,
92 const char *path,
93 const char *interface,
94 const char *property,
95 sd_bus_message *reply,
96 void *userdata,
97 sd_bus_error *error) {
98
99 _cleanup_close_ int fd = -1;
100 uint64_t size = (uint64_t) -1;
101 struct stat st;
102
103 assert(bus);
104 assert(reply);
105
106 /* We try to read the quota limit from /var/lib/machines, as
107 * well as the size of the loopback file
108 * /var/lib/machines.raw, and pick the smaller value. */
109
110 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
111 if (fd >= 0) {
112 BtrfsQuotaInfo q;
113
114 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
115 size = q.referred_max;
116 }
117
118 if (stat("/var/lib/machines.raw", &st) >= 0) {
119 if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
120 size = st.st_size;
121 }
122
123 return sd_bus_message_append(reply, "t", size);
124}
125
ebcf1f97 126static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
127 _cleanup_free_ char *p = NULL;
128 Manager *m = userdata;
129 Machine *machine;
130 const char *name;
131 int r;
132
133 assert(bus);
134 assert(message);
135 assert(m);
136
137 r = sd_bus_message_read(message, "s", &name);
138 if (r < 0)
ebcf1f97 139 return r;
c3350683
LP
140
141 machine = hashmap_get(m->machines, name);
142 if (!machine)
ebcf1f97 143 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
c3350683
LP
144
145 p = machine_bus_path(machine);
146 if (!p)
ebcf1f97 147 return -ENOMEM;
c3350683 148
df2d202e 149 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
150}
151
c2ce6a3d
LP
152static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
153 _cleanup_free_ char *p = NULL;
154 Manager *m = userdata;
155 const char *name;
156 int r;
157
158 assert(bus);
159 assert(message);
160 assert(m);
161
162 r = sd_bus_message_read(message, "s", &name);
163 if (r < 0)
164 return r;
165
166 r = image_find(name, NULL);
167 if (r == 0)
168 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
169 if (r < 0)
170 return r;
171
172 p = image_bus_path(name);
173 if (!p)
174 return -ENOMEM;
175
176 return sd_bus_reply_method_return(message, "o", p);
177}
178
ebcf1f97 179static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
180 _cleanup_free_ char *p = NULL;
181 Manager *m = userdata;
182 Machine *machine = NULL;
4e724d9c 183 pid_t pid;
c3350683
LP
184 int r;
185
186 assert(bus);
187 assert(message);
188 assert(m);
189
4e724d9c
LP
190 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
191
c3350683
LP
192 r = sd_bus_message_read(message, "u", &pid);
193 if (r < 0)
ebcf1f97 194 return r;
c3350683 195
4e724d9c 196 if (pid == 0) {
5b12334d
LP
197 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
198
199 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
200 if (r < 0)
201 return r;
202
203 r = sd_bus_creds_get_pid(creds, &pid);
4e724d9c 204 if (r < 0)
ebcf1f97 205 return r;
4e724d9c
LP
206 }
207
c3350683
LP
208 r = manager_get_machine_by_pid(m, pid, &machine);
209 if (r < 0)
ebcf1f97 210 return r;
c3350683 211 if (!machine)
de0671ee 212 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
c3350683
LP
213
214 p = machine_bus_path(machine);
215 if (!p)
ebcf1f97 216 return -ENOMEM;
c3350683 217
df2d202e 218 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
219}
220
ebcf1f97 221static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
222 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
223 Manager *m = userdata;
224 Machine *machine;
225 Iterator i;
226 int r;
227
228 assert(bus);
229 assert(message);
230 assert(m);
231
df2d202e 232 r = sd_bus_message_new_method_return(message, &reply);
c3350683 233 if (r < 0)
ebcf1f97 234 return sd_bus_error_set_errno(error, r);
c3350683
LP
235
236 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
237 if (r < 0)
ebcf1f97 238 return sd_bus_error_set_errno(error, r);
c3350683
LP
239
240 HASHMAP_FOREACH(machine, m->machines, i) {
241 _cleanup_free_ char *p = NULL;
242
243 p = machine_bus_path(machine);
244 if (!p)
ebcf1f97 245 return -ENOMEM;
c3350683
LP
246
247 r = sd_bus_message_append(reply, "(ssso)",
248 machine->name,
249 strempty(machine_class_to_string(machine->class)),
250 machine->service,
251 p);
252 if (r < 0)
ebcf1f97 253 return sd_bus_error_set_errno(error, r);
c3350683 254 }
1ee306e1 255
c3350683
LP
256 r = sd_bus_message_close_container(reply);
257 if (r < 0)
ebcf1f97 258 return sd_bus_error_set_errno(error, r);
c3350683
LP
259
260 return sd_bus_send(bus, reply, NULL);
261}
262
9b5ed6fe 263static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
8aec412f 264 const char *name, *service, *class, *root_directory;
9b5ed6fe 265 const int32_t *netif = NULL;
1ee306e1
LP
266 MachineClass c;
267 uint32_t leader;
268 sd_id128_t id;
c3350683 269 const void *v;
1ee306e1 270 Machine *m;
9b5ed6fe 271 size_t n, n_netif = 0;
c3350683 272 int r;
1ee306e1 273
c3350683 274 assert(manager);
89f7c846
LP
275 assert(message);
276 assert(_m);
1ee306e1 277
c3350683
LP
278 r = sd_bus_message_read(message, "s", &name);
279 if (r < 0)
ebcf1f97 280 return r;
7f0d207d 281 if (!machine_name_is_valid(name))
ebcf1f97 282 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 283
c3350683
LP
284 r = sd_bus_message_read_array(message, 'y', &v, &n);
285 if (r < 0)
ebcf1f97 286 return r;
1ee306e1
LP
287 if (n == 0)
288 id = SD_ID128_NULL;
289 else if (n == 16)
290 memcpy(&id, v, n);
291 else
ebcf1f97 292 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 293
c3350683
LP
294 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
295 if (r < 0)
ebcf1f97 296 return r;
1ee306e1 297
9b5ed6fe
LP
298 if (read_network) {
299 size_t i;
300
301 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
302 if (r < 0)
303 return r;
304
305 n_netif /= sizeof(int32_t);
306
307 for (i = 0; i < n_netif; i++) {
308 if (netif[i] <= 0)
309 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
310 }
311 }
312
1ee306e1
LP
313 if (isempty(class))
314 c = _MACHINE_CLASS_INVALID;
315 else {
316 c = machine_class_from_string(class);
317 if (c < 0)
ebcf1f97 318 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
319 }
320
c3350683 321 if (leader == 1)
ebcf1f97 322 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 323
c3350683 324 if (!isempty(root_directory) && !path_is_absolute(root_directory))
ebcf1f97 325 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 326
c3350683 327 if (leader == 0) {
5b12334d
LP
328 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
329
330 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
331 if (r < 0)
332 return r;
333
c3350683 334 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
554604b3 335
5b12334d 336 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c3350683 337 if (r < 0)
ebcf1f97 338 return r;
c3350683 339 }
554604b3 340
1ee306e1 341 if (hashmap_get(manager->machines, name))
ebcf1f97 342 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1
LP
343
344 r = manager_add_machine(manager, name, &m);
345 if (r < 0)
ebcf1f97 346 return r;
1ee306e1
LP
347
348 m->leader = leader;
349 m->class = c;
350 m->id = id;
351
352 if (!isempty(service)) {
353 m->service = strdup(service);
354 if (!m->service) {
ebcf1f97 355 r = -ENOMEM;
1ee306e1
LP
356 goto fail;
357 }
358 }
359
360 if (!isempty(root_directory)) {
361 m->root_directory = strdup(root_directory);
362 if (!m->root_directory) {
ebcf1f97 363 r = -ENOMEM;
1ee306e1
LP
364 goto fail;
365 }
366 }
367
9b5ed6fe
LP
368 if (n_netif > 0) {
369 assert_cc(sizeof(int32_t) == sizeof(int));
370 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
371 if (!m->netif) {
372 r = -ENOMEM;
373 goto fail;
374 }
375
376 m->n_netif = n_netif;
377 }
378
89f7c846
LP
379 *_m = m;
380
381 return 1;
382
383fail:
384 machine_add_to_gc_queue(m);
385 return r;
386}
387
9b5ed6fe 388static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
389 Manager *manager = userdata;
390 Machine *m = NULL;
391 int r;
392
9b5ed6fe 393 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
394 if (r < 0)
395 return r;
396
397 r = sd_bus_message_enter_container(message, 'a', "(sv)");
398 if (r < 0)
399 goto fail;
400
ebcf1f97
LP
401 r = machine_start(m, message, error);
402 if (r < 0)
1ee306e1
LP
403 goto fail;
404
c3350683 405 m->create_message = sd_bus_message_ref(message);
c3350683 406 return 1;
1ee306e1
LP
407
408fail:
a3e7f417 409 machine_add_to_gc_queue(m);
89f7c846
LP
410 return r;
411}
1ee306e1 412
9b5ed6fe
LP
413static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
414 return method_create_machine_internal(bus, message, true, userdata, error);
415}
416
417static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
418 return method_create_machine_internal(bus, message, false, userdata, error);
419}
420
421static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
422 Manager *manager = userdata;
423 _cleanup_free_ char *p = NULL;
424 Machine *m = NULL;
425 int r;
426
9b5ed6fe 427 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
428 if (r < 0)
429 return r;
430
431 r = cg_pid_get_unit(m->leader, &m->unit);
432 if (r < 0) {
433 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
434 goto fail;
435 }
436
437 r = machine_start(m, NULL, error);
438 if (r < 0)
439 goto fail;
440
441 p = machine_bus_path(m);
442 if (!p) {
443 r = -ENOMEM;
444 goto fail;
445 }
446
447 return sd_bus_reply_method_return(message, "o", p);
448
449fail:
450 machine_add_to_gc_queue(m);
1ee306e1
LP
451 return r;
452}
453
9b5ed6fe
LP
454static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
455 return method_register_machine_internal(bus, message, true, userdata, error);
456}
457
458static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
459 return method_register_machine_internal(bus, message, false, userdata, error);
460}
461
ebcf1f97 462static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 463 Manager *m = userdata;
c3350683
LP
464 Machine *machine;
465 const char *name;
1ee306e1
LP
466 int r;
467
c3350683 468 assert(bus);
1ee306e1
LP
469 assert(message);
470 assert(m);
471
c3350683
LP
472 r = sd_bus_message_read(message, "s", &name);
473 if (r < 0)
ebcf1f97 474 return sd_bus_error_set_errno(error, r);
1ee306e1 475
c3350683
LP
476 machine = hashmap_get(m->machines, name);
477 if (!machine)
ebcf1f97 478 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 479
878cd7e9 480 return bus_machine_method_terminate(bus, message, machine, error);
c3350683 481}
1ee306e1 482
ebcf1f97 483static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
484 Manager *m = userdata;
485 Machine *machine;
486 const char *name;
c3350683 487 int r;
1ee306e1 488
c3350683
LP
489 assert(bus);
490 assert(message);
491 assert(m);
1ee306e1 492
878cd7e9 493 r = sd_bus_message_read(message, "s", &name);
c3350683 494 if (r < 0)
ebcf1f97 495 return sd_bus_error_set_errno(error, r);
1ee306e1 496
c3350683
LP
497 machine = hashmap_get(m->machines, name);
498 if (!machine)
ebcf1f97 499 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 500
878cd7e9
LP
501 return bus_machine_method_kill(bus, message, machine, error);
502}
503
504static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
505 Manager *m = userdata;
506 Machine *machine;
507 const char *name;
508 int r;
509
510 assert(bus);
511 assert(message);
512 assert(m);
513
514 r = sd_bus_message_read(message, "s", &name);
c3350683 515 if (r < 0)
ebcf1f97 516 return sd_bus_error_set_errno(error, r);
1ee306e1 517
878cd7e9
LP
518 machine = hashmap_get(m->machines, name);
519 if (!machine)
520 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
521
522 return bus_machine_method_get_addresses(bus, message, machine, error);
c3350683 523}
1ee306e1 524
717603e3
LP
525static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
526 Manager *m = userdata;
527 Machine *machine;
528 const char *name;
529 int r;
530
531 assert(bus);
532 assert(message);
533 assert(m);
534
535 r = sd_bus_message_read(message, "s", &name);
536 if (r < 0)
537 return sd_bus_error_set_errno(error, r);
538
539 machine = hashmap_get(m->machines, name);
540 if (!machine)
541 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
542
543 return bus_machine_method_get_os_release(bus, message, machine, error);
544}
545
cd61c3bf
LP
546static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
547 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
548 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
549 Manager *m = userdata;
550 Image *image;
551 Iterator i;
552 int r;
553
554 assert(bus);
555 assert(message);
556 assert(m);
557
558 images = hashmap_new(&string_hash_ops);
559 if (!images)
560 return -ENOMEM;
561
562 r = image_discover(images);
563 if (r < 0)
564 return r;
565
566 r = sd_bus_message_new_method_return(message, &reply);
567 if (r < 0)
568 return r;
569
b6b18498 570 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
cd61c3bf
LP
571 if (r < 0)
572 return r;
573
574 HASHMAP_FOREACH(image, images, i) {
575 _cleanup_free_ char *p = NULL;
576
577 p = image_bus_path(image->name);
578 if (!p)
579 return -ENOMEM;
580
b6b18498 581 r = sd_bus_message_append(reply, "(ssbttto)",
cd61c3bf
LP
582 image->name,
583 image_type_to_string(image->type),
584 image->read_only,
10f9c755
LP
585 image->crtime,
586 image->mtime,
c19de711 587 image->usage,
cd61c3bf
LP
588 p);
589 if (r < 0)
590 return r;
591 }
592
593 r = sd_bus_message_close_container(reply);
594 if (r < 0)
595 return r;
596
597 return sd_bus_send(bus, reply, NULL);
598}
599
40205d70
LP
600static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
601 Manager *m = userdata;
602 Machine *machine;
603 const char *name;
604 int r;
605
606 assert(bus);
607 assert(message);
608 assert(m);
609
610 r = sd_bus_message_read(message, "s", &name);
611 if (r < 0)
612 return sd_bus_error_set_errno(error, r);
613
614 machine = hashmap_get(m->machines, name);
615 if (!machine)
616 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
617
618 return bus_machine_method_open_pty(bus, message, machine, error);
619}
620
5f8cc96a
LP
621static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
622 Manager *m = userdata;
623 Machine *machine;
624 const char *name;
625 int r;
626
627 assert(bus);
628 assert(message);
629 assert(m);
630
631 r = sd_bus_message_read(message, "s", &name);
632 if (r < 0)
08682124 633 return r;
5f8cc96a
LP
634
635 machine = hashmap_get(m->machines, name);
636 if (!machine)
637 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
638
639 return bus_machine_method_open_login(bus, message, machine, error);
640}
641
90adaa25
LP
642static int method_bind_mount_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
643 Manager *m = userdata;
644 Machine *machine;
645 const char *name;
646 int r;
647
648 assert(bus);
649 assert(message);
650 assert(m);
651
652 r = sd_bus_message_read(message, "s", &name);
653 if (r < 0)
654 return r;
655
656 machine = hashmap_get(m->machines, name);
657 if (!machine)
658 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
659
660 return bus_machine_method_bind_mount(bus, message, machine, error);
661}
662
0370612e
LP
663static int method_copy_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
664 Manager *m = userdata;
665 Machine *machine;
666 const char *name;
667 int r;
668
669 assert(bus);
670 assert(message);
671 assert(m);
672
673 r = sd_bus_message_read(message, "s", &name);
674 if (r < 0)
675 return r;
676
677 machine = hashmap_get(m->machines, name);
678 if (!machine)
679 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
680
681 return bus_machine_method_copy(bus, message, machine, error);
682}
683
08682124
LP
684static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
685 _cleanup_(image_unrefp) Image* i = NULL;
686 const char *name;
687 int r;
688
689 assert(bus);
690 assert(message);
691
692 r = sd_bus_message_read(message, "s", &name);
693 if (r < 0)
694 return r;
695
696 if (!image_name_is_valid(name))
697 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
698
699 r = image_find(name, &i);
700 if (r < 0)
701 return r;
702 if (r == 0)
703 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
704
70244d1d 705 i->userdata = userdata;
1ddb263d 706 return bus_image_method_remove(bus, message, i, error);
08682124
LP
707}
708
ebd93cb6
LP
709static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
710 _cleanup_(image_unrefp) Image* i = NULL;
1ddb263d 711 const char *old_name;
ebd93cb6
LP
712 int r;
713
714 assert(bus);
715 assert(message);
716
1ddb263d 717 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
718 if (r < 0)
719 return r;
720
721 if (!image_name_is_valid(old_name))
722 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
723
724 r = image_find(old_name, &i);
725 if (r < 0)
726 return r;
727 if (r == 0)
728 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
729
70244d1d 730 i->userdata = userdata;
1ddb263d 731 return bus_image_method_rename(bus, message, i, error);
ebd93cb6
LP
732}
733
734static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
735 _cleanup_(image_unrefp) Image *i = NULL;
1ddb263d
LP
736 const char *old_name;
737 int r;
ebd93cb6
LP
738
739 assert(bus);
1ddb263d 740 r = sd_bus_message_read(message, "s", &old_name);
ebd93cb6
LP
741 if (r < 0)
742 return r;
743
744 if (!image_name_is_valid(old_name))
745 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
ebd93cb6
LP
746
747 r = image_find(old_name, &i);
748 if (r < 0)
749 return r;
750 if (r == 0)
751 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
752
70244d1d 753 i->userdata = userdata;
1ddb263d 754 return bus_image_method_clone(bus, message, i, error);
ebd93cb6
LP
755}
756
757static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
758 _cleanup_(image_unrefp) Image *i = NULL;
759 const char *name;
1ddb263d 760 int r;
ebd93cb6
LP
761
762 assert(bus);
1ddb263d 763 r = sd_bus_message_read(message, "s", &name);
ebd93cb6
LP
764 if (r < 0)
765 return r;
766
767 if (!image_name_is_valid(name))
768 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
769
770 r = image_find(name, &i);
771 if (r < 0)
772 return r;
773 if (r == 0)
774 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
775
70244d1d 776 i->userdata = userdata;
1ddb263d 777 return bus_image_method_mark_read_only(bus, message, i, error);
ebd93cb6
LP
778}
779
d6ce17c7
LP
780static int method_set_pool_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
781 Manager *m = userdata;
782 uint64_t limit;
783 int r;
784
785 assert(bus);
786 r = sd_bus_message_read(message, "t", &limit);
787 if (r < 0)
788 return r;
789
790 r = bus_verify_polkit_async(
791 message,
792 CAP_SYS_ADMIN,
793 "org.freedesktop.machine1.manage-machines",
794 false,
795 UID_INVALID,
796 &m->polkit_registry,
797 error);
798 if (r < 0)
799 return r;
800 if (r == 0)
801 return 1; /* Will call us back */
802
4cee5eed
LP
803 /* Set up the machine directory if necessary */
804 r = setup_machine_directory(limit, error);
805 if (r < 0)
806 return r;
807
efe02862
LP
808 r = btrfs_resize_loopback("/var/lib/machines", limit);
809 if (r < 0 && r != -ENODEV)
810 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
811
d6ce17c7
LP
812 r = btrfs_quota_limit("/var/lib/machines", limit);
813 if (r == -ENOTTY)
814 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
815 else if (r < 0)
816 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
817
818 return sd_bus_reply_method_return(message, NULL);
819}
820
821static int method_set_image_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
822 _cleanup_(image_unrefp) Image *i = NULL;
823 const char *name;
824 int r;
825
826 assert(bus);
827 r = sd_bus_message_read(message, "s", &name);
828 if (r < 0)
829 return r;
830
831 if (!image_name_is_valid(name))
832 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
833
834 r = image_find(name, &i);
835 if (r < 0)
836 return r;
837 if (r == 0)
838 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
839
840 i->userdata = userdata;
841 return bus_image_method_set_limit(bus, message, i, error);
842}
843
c3350683
LP
844const sd_bus_vtable manager_vtable[] = {
845 SD_BUS_VTABLE_START(0),
160e3793
LP
846 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
847 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
848 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
adacb957 849 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 850 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
851 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
852 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
b6b18498 853 SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 854 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 855 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 856 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 857 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
70244d1d
LP
858 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
859 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
3a6fb33c 860 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 861 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 862 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
d04c1fb8 863 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
864 SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
865 SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
866 SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
867 SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
868 SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
869 SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
870 SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
d6ce17c7
LP
871 SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
872 SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683
LP
873 SD_BUS_SIGNAL("MachineNew", "so", 0),
874 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
875 SD_BUS_VTABLE_END
876};
1ee306e1 877
ebcf1f97 878int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 879 const char *path, *result, *unit;
1ee306e1 880 Manager *m = userdata;
c3350683
LP
881 Machine *machine;
882 uint32_t id;
883 int r;
1ee306e1 884
c3350683 885 assert(bus);
1ee306e1 886 assert(message);
c3350683 887 assert(m);
1ee306e1 888
c3350683
LP
889 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
890 if (r < 0) {
ebcf1f97
LP
891 bus_log_parse_error(r);
892 return r;
c3350683 893 }
6797c324 894
c3350683
LP
895 machine = hashmap_get(m->machine_units, unit);
896 if (!machine)
897 return 0;
6797c324 898
c3350683
LP
899 if (streq_ptr(path, machine->scope_job)) {
900 free(machine->scope_job);
901 machine->scope_job = NULL;
6797c324 902
c3350683
LP
903 if (machine->started) {
904 if (streq(result, "done"))
905 machine_send_create_reply(machine, NULL);
906 else {
ebcf1f97 907 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 908
ebcf1f97 909 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 910
ebcf1f97 911 machine_send_create_reply(machine, &e);
c3350683
LP
912 }
913 } else
914 machine_save(machine);
1ee306e1
LP
915 }
916
c3350683
LP
917 machine_add_to_gc_queue(machine);
918 return 0;
1ee306e1
LP
919}
920
ebcf1f97 921int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
922 _cleanup_free_ char *unit = NULL;
923 Manager *m = userdata;
924 Machine *machine;
925 const char *path;
ebcf1f97 926 int r;
554604b3 927
c3350683
LP
928 assert(bus);
929 assert(message);
930 assert(m);
554604b3 931
c3350683
LP
932 path = sd_bus_message_get_path(message);
933 if (!path)
554604b3 934 return 0;
554604b3 935
ebcf1f97 936 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
937 if (r == -EINVAL) /* not for a unit */
938 return 0;
ebcf1f97
LP
939 if (r < 0)
940 return r;
554604b3 941
c3350683
LP
942 machine = hashmap_get(m->machine_units, unit);
943 if (machine)
944 machine_add_to_gc_queue(machine);
554604b3 945
c3350683
LP
946 return 0;
947}
554604b3 948
ebcf1f97 949int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
950 const char *path, *unit;
951 Manager *m = userdata;
952 Machine *machine;
953 int r;
554604b3 954
c3350683
LP
955 assert(bus);
956 assert(message);
957 assert(m);
554604b3 958
c3350683
LP
959 r = sd_bus_message_read(message, "so", &unit, &path);
960 if (r < 0) {
ebcf1f97
LP
961 bus_log_parse_error(r);
962 return r;
554604b3
LP
963 }
964
c3350683
LP
965 machine = hashmap_get(m->machine_units, unit);
966 if (machine)
967 machine_add_to_gc_queue(machine);
554604b3 968
c3350683
LP
969 return 0;
970}
554604b3 971
ebcf1f97 972int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 973 Manager *m = userdata;
a658cafa
LP
974 Machine *machine;
975 Iterator i;
c3350683 976 int b, r;
554604b3 977
c3350683 978 assert(bus);
554604b3 979
c3350683
LP
980 r = sd_bus_message_read(message, "b", &b);
981 if (r < 0) {
ebcf1f97
LP
982 bus_log_parse_error(r);
983 return r;
554604b3 984 }
a658cafa
LP
985 if (b)
986 return 0;
554604b3 987
a658cafa
LP
988 /* systemd finished reloading, let's recheck all our machines */
989 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 990
a658cafa
LP
991 HASHMAP_FOREACH(machine, m->machines, i)
992 machine_add_to_gc_queue(machine);
554604b3
LP
993
994 return 0;
995}
996
1ee306e1
LP
997int manager_start_scope(
998 Manager *manager,
999 const char *scope,
1000 pid_t pid,
1001 const char *slice,
1002 const char *description,
c3350683
LP
1003 sd_bus_message *more_properties,
1004 sd_bus_error *error,
1ee306e1
LP
1005 char **job) {
1006
c3350683 1007 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 1008 int r;
1ee306e1
LP
1009
1010 assert(manager);
1011 assert(scope);
1012 assert(pid > 1);
1013
c3350683
LP
1014 r = sd_bus_message_new_method_call(
1015 manager->bus,
151b9b96 1016 &m,
1ee306e1
LP
1017 "org.freedesktop.systemd1",
1018 "/org/freedesktop/systemd1",
1019 "org.freedesktop.systemd1.Manager",
151b9b96 1020 "StartTransientUnit");
c3350683
LP
1021 if (r < 0)
1022 return r;
1ee306e1 1023
a658cafa 1024 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
1025 if (r < 0)
1026 return r;
1ee306e1 1027
c3350683
LP
1028 r = sd_bus_message_open_container(m, 'a', "(sv)");
1029 if (r < 0)
1030 return r;
1ee306e1
LP
1031
1032 if (!isempty(slice)) {
c3350683
LP
1033 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1034 if (r < 0)
1035 return r;
1ee306e1
LP
1036 }
1037
1038 if (!isempty(description)) {
c3350683
LP
1039 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1040 if (r < 0)
1041 return r;
1ee306e1
LP
1042 }
1043
c3350683
LP
1044 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1045 if (r < 0)
1046 return r;
554604b3 1047
a931ad47
LP
1048 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1049 if (r < 0)
1050 return r;
1051
554604b3 1052 if (more_properties) {
c3350683 1053 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
1054 if (r < 0)
1055 return r;
1056 }
1057
c3350683
LP
1058 r = sd_bus_message_close_container(m);
1059 if (r < 0)
1060 return r;
1ee306e1 1061
86b8d289
LP
1062 r = sd_bus_message_append(m, "a(sa(sv))", 0);
1063 if (r < 0)
1064 return r;
1065
c49b30a2 1066 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
1067 if (r < 0)
1068 return r;
1ee306e1
LP
1069
1070 if (job) {
1071 const char *j;
1072 char *copy;
1073
c3350683
LP
1074 r = sd_bus_message_read(reply, "o", &j);
1075 if (r < 0)
1076 return r;
1ee306e1
LP
1077
1078 copy = strdup(j);
1079 if (!copy)
1080 return -ENOMEM;
1081
1082 *job = copy;
1083 }
1084
c3350683 1085 return 1;
1ee306e1
LP
1086}
1087
c3350683
LP
1088int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
1089 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
1090 int r;
1091
1092 assert(manager);
1093 assert(unit);
1094
c3350683 1095 r = sd_bus_call_method(
1ee306e1
LP
1096 manager->bus,
1097 "org.freedesktop.systemd1",
1098 "/org/freedesktop/systemd1",
1099 "org.freedesktop.systemd1.Manager",
1100 "StopUnit",
1ee306e1 1101 error,
c3350683
LP
1102 &reply,
1103 "ss", unit, "fail");
1ee306e1 1104 if (r < 0) {
c3350683
LP
1105 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1106 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
1107
1108 if (job)
1109 *job = NULL;
1110
c3350683 1111 sd_bus_error_free(error);
6797c324
LP
1112 return 0;
1113 }
1114
1ee306e1
LP
1115 return r;
1116 }
1117
1118 if (job) {
1119 const char *j;
1120 char *copy;
1121
c3350683
LP
1122 r = sd_bus_message_read(reply, "o", &j);
1123 if (r < 0)
1124 return r;
1ee306e1
LP
1125
1126 copy = strdup(j);
1127 if (!copy)
1128 return -ENOMEM;
1129
1130 *job = copy;
1131 }
1132
6797c324 1133 return 1;
1ee306e1
LP
1134}
1135
de58a50e 1136int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
1137 assert(manager);
1138 assert(unit);
1139
a658cafa 1140 return sd_bus_call_method(
1ee306e1
LP
1141 manager->bus,
1142 "org.freedesktop.systemd1",
1143 "/org/freedesktop/systemd1",
1144 "org.freedesktop.systemd1.Manager",
1145 "KillUnit",
1ee306e1 1146 error,
a658cafa 1147 NULL,
de58a50e 1148 "ssi", unit, "all", signo);
1ee306e1
LP
1149}
1150
1151int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
1152 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1153 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 1154 _cleanup_free_ char *path = NULL;
1ee306e1 1155 const char *state;
1ee306e1
LP
1156 int r;
1157
1158 assert(manager);
1159 assert(unit);
1160
1ee306e1
LP
1161 path = unit_dbus_path_from_name(unit);
1162 if (!path)
1163 return -ENOMEM;
1164
c3350683 1165 r = sd_bus_get_property(
1ee306e1
LP
1166 manager->bus,
1167 "org.freedesktop.systemd1",
1168 path,
c3350683
LP
1169 "org.freedesktop.systemd1.Unit",
1170 "ActiveState",
1ee306e1 1171 &error,
c3350683
LP
1172 &reply,
1173 "s");
1ee306e1 1174 if (r < 0) {
c3350683
LP
1175 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1176 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 1177 return true;
6797c324 1178
c3350683
LP
1179 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1180 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 1181 return false;
6797c324 1182
1ee306e1
LP
1183 return r;
1184 }
1185
c3350683
LP
1186 r = sd_bus_message_read(reply, "s", &state);
1187 if (r < 0)
1ee306e1 1188 return -EINVAL;
1ee306e1
LP
1189
1190 return !streq(state, "inactive") && !streq(state, "failed");
1191}
bd16acf3 1192
c3350683
LP
1193int manager_job_is_active(Manager *manager, const char *path) {
1194 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1195 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1196 int r;
bd16acf3 1197
c3350683
LP
1198 assert(manager);
1199 assert(path);
bd16acf3 1200
c3350683
LP
1201 r = sd_bus_get_property(
1202 manager->bus,
1203 "org.freedesktop.systemd1",
1204 path,
1205 "org.freedesktop.systemd1.Job",
1206 "State",
1207 &error,
1208 &reply,
1209 "s");
1210 if (r < 0) {
1211 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1212 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1213 return true;
bd16acf3 1214
c3350683
LP
1215 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1216 return false;
bd16acf3 1217
bd16acf3 1218 return r;
c3350683 1219 }
bd16acf3 1220
c3350683
LP
1221 /* We don't actually care about the state really. The fact
1222 * that we could read the job state is enough for us */
bd16acf3 1223
c3350683 1224 return true;
bd16acf3 1225}
ab49725f
KS
1226
1227int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1228 _cleanup_free_ char *unit = NULL;
1229 Machine *mm;
1230 int r;
1231
1232 assert(m);
1233 assert(pid >= 1);
1234 assert(machine);
1235
1236 r = cg_pid_get_unit(pid, &unit);
1237 if (r < 0)
1238 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1239 else
1240 mm = hashmap_get(m->machine_units, unit);
1241
1242 if (!mm)
1243 return 0;
1244
1245 *machine = mm;
1246 return 1;
1247}
1248
1249int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1250 Machine *machine;
1251
1252 assert(m);
1253 assert(name);
1254
1255 machine = hashmap_get(m->machines, name);
1256 if (!machine) {
1257 machine = machine_new(m, name);
1258 if (!machine)
1259 return -ENOMEM;
1260 }
1261
1262 if (_machine)
1263 *_machine = machine;
1264
1265 return 0;
1266}