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