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