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