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