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