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