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