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