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