]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machine-dbus.c
bus: sync with kdbus
[thirdparty/systemd.git] / src / machine / machine-dbus.c
CommitLineData
9444b1f2
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>
878cd7e9 24#include <arpa/inet.h>
90adaa25 25#include <sys/mount.h>
9444b1f2 26
c3350683 27#include "bus-util.h"
a6278b88 28#include "bus-label.h"
927b1649 29#include "strv.h"
96aad8d1 30#include "bus-common-errors.h"
717603e3
LP
31#include "copy.h"
32#include "fileio.h"
3b653205 33#include "in-addr-util.h"
496a5a69 34#include "local-addresses.h"
5f8cc96a 35#include "path-util.h"
90adaa25 36#include "mkdir.h"
5f8cc96a 37#include "bus-internal.h"
717603e3 38#include "machine.h"
003dffde 39#include "machine-dbus.h"
9444b1f2 40
c3350683
LP
41static int property_get_id(
42 sd_bus *bus,
43 const char *path,
44 const char *interface,
45 const char *property,
46 sd_bus_message *reply,
ebcf1f97
LP
47 void *userdata,
48 sd_bus_error *error) {
9444b1f2 49
c3350683
LP
50 Machine *m = userdata;
51 int r;
9444b1f2 52
c3350683
LP
53 assert(bus);
54 assert(reply);
55 assert(m);
56
57 r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
58 if (r < 0)
59 return r;
9444b1f2 60
c3350683 61 return 1;
9444b1f2
LP
62}
63
c3350683
LP
64static int property_get_state(
65 sd_bus *bus,
66 const char *path,
67 const char *interface,
68 const char *property,
69 sd_bus_message *reply,
ebcf1f97
LP
70 void *userdata,
71 sd_bus_error *error) {
c3350683
LP
72
73 Machine *m = userdata;
fb6becb4 74 const char *state;
c3350683 75 int r;
fb6becb4 76
c3350683
LP
77 assert(bus);
78 assert(reply);
fb6becb4
LP
79 assert(m);
80
81 state = machine_state_to_string(machine_get_state(m));
82
c3350683
LP
83 r = sd_bus_message_append_basic(reply, 's', state);
84 if (r < 0)
85 return r;
fb6becb4 86
c3350683 87 return 1;
fb6becb4
LP
88}
89
9b5ed6fe
LP
90static int property_get_netif(
91 sd_bus *bus,
92 const char *path,
93 const char *interface,
94 const char *property,
95 sd_bus_message *reply,
96 void *userdata,
97 sd_bus_error *error) {
98
99 Machine *m = userdata;
100 int r;
101
102 assert(bus);
103 assert(reply);
104 assert(m);
105
106 assert_cc(sizeof(int) == sizeof(int32_t));
107
108 r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
109 if (r < 0)
110 return r;
111
112 return 1;
113}
114
c3350683 115static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
9444b1f2 116
878cd7e9 117int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
118 Machine *m = userdata;
119 int r;
9444b1f2 120
c3350683
LP
121 assert(bus);
122 assert(message);
123 assert(m);
9444b1f2 124
c3350683
LP
125 r = machine_stop(m);
126 if (r < 0)
ebcf1f97 127 return r;
9444b1f2 128
df2d202e 129 return sd_bus_reply_method_return(message, NULL);
9444b1f2
LP
130}
131
878cd7e9 132int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
133 Machine *m = userdata;
134 const char *swho;
135 int32_t signo;
136 KillWho who;
9444b1f2
LP
137 int r;
138
c3350683 139 assert(bus);
9444b1f2 140 assert(message);
c3350683 141 assert(m);
9444b1f2 142
c3350683
LP
143 r = sd_bus_message_read(message, "si", &swho, &signo);
144 if (r < 0)
ebcf1f97 145 return r;
9444b1f2 146
c3350683
LP
147 if (isempty(swho))
148 who = KILL_ALL;
149 else {
150 who = kill_who_from_string(swho);
151 if (who < 0)
ebcf1f97 152 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
9444b1f2
LP
153 }
154
c3350683 155 if (signo <= 0 || signo >= _NSIG)
ebcf1f97 156 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
9444b1f2 157
c3350683
LP
158 r = machine_kill(m, who, signo);
159 if (r < 0)
ebcf1f97 160 return r;
9444b1f2 161
df2d202e 162 return sd_bus_reply_method_return(message, NULL);
9444b1f2
LP
163}
164
878cd7e9
LP
165int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
166 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
167 _cleanup_close_pair_ int pair[2] = { -1, -1 };
168 _cleanup_free_ char *us = NULL, *them = NULL;
169 _cleanup_close_ int netns_fd = -1;
170 Machine *m = userdata;
171 const char *p;
172 siginfo_t si;
173 pid_t child;
174 int r;
175
176 assert(bus);
177 assert(message);
178 assert(m);
179
b4d8ef7c
LP
180 if (m->class != MACHINE_CONTAINER)
181 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
182
878cd7e9
LP
183 r = readlink_malloc("/proc/self/ns/net", &us);
184 if (r < 0)
185 return sd_bus_error_set_errno(error, r);
186
187 p = procfs_file_alloca(m->leader, "ns/net");
188 r = readlink_malloc(p, &them);
189 if (r < 0)
190 return sd_bus_error_set_errno(error, r);
191
192 if (streq(us, them))
193 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
194
195 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
196 if (r < 0)
197 return sd_bus_error_set_errno(error, r);
198
199 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
200 return sd_bus_error_set_errno(error, -errno);
201
202 child = fork();
203 if (child < 0)
204 return sd_bus_error_set_errno(error, -errno);
205
206 if (child == 0) {
496a5a69
LP
207 _cleanup_free_ struct local_address *addresses = NULL;
208 struct local_address *a;
209 int i, n;
878cd7e9
LP
210
211 pair[0] = safe_close(pair[0]);
212
213 r = namespace_enter(-1, -1, netns_fd, -1);
214 if (r < 0)
215 _exit(EXIT_FAILURE);
216
1d050e1e 217 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
496a5a69 218 if (n < 0)
878cd7e9
LP
219 _exit(EXIT_FAILURE);
220
496a5a69
LP
221 for (a = addresses, i = 0; i < n; a++, i++) {
222 struct iovec iov[2] = {
223 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
9d485985 224 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
496a5a69 225 };
878cd7e9
LP
226
227 r = writev(pair[1], iov, 2);
228 if (r < 0)
229 _exit(EXIT_FAILURE);
230 }
231
496a5a69
LP
232 pair[1] = safe_close(pair[1]);
233
878cd7e9
LP
234 _exit(EXIT_SUCCESS);
235 }
236
237 pair[1] = safe_close(pair[1]);
238
239 r = sd_bus_message_new_method_return(message, &reply);
240 if (r < 0)
241 return sd_bus_error_set_errno(error, r);
242
0dd25fb9 243 r = sd_bus_message_open_container(reply, 'a', "(iay)");
878cd7e9
LP
244 if (r < 0)
245 return sd_bus_error_set_errno(error, r);
246
247 for (;;) {
0dd25fb9 248 int family;
878cd7e9 249 ssize_t n;
bb62fb68 250 union in_addr_union in_addr;
878cd7e9
LP
251 struct iovec iov[2];
252 struct msghdr mh = {
253 .msg_iov = iov,
254 .msg_iovlen = 2,
255 };
256
257 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
258 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
259
a38d9945 260 n = recvmsg(pair[0], &mh, 0);
878cd7e9
LP
261 if (n < 0)
262 return sd_bus_error_set_errno(error, -errno);
263 if ((size_t) n < sizeof(family))
264 break;
265
0dd25fb9 266 r = sd_bus_message_open_container(reply, 'r', "iay");
878cd7e9
LP
267 if (r < 0)
268 return sd_bus_error_set_errno(error, r);
269
0dd25fb9 270 r = sd_bus_message_append(reply, "i", family);
878cd7e9
LP
271 if (r < 0)
272 return sd_bus_error_set_errno(error, r);
273
274 switch (family) {
275
276 case AF_INET:
277 if (n != sizeof(struct in_addr) + sizeof(family))
278 return sd_bus_error_set_errno(error, EIO);
279
280 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
281 break;
282
283 case AF_INET6:
284 if (n != sizeof(struct in6_addr) + sizeof(family))
285 return sd_bus_error_set_errno(error, EIO);
286
287 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
288 break;
289 }
290 if (r < 0)
291 return sd_bus_error_set_errno(error, r);
292
293 r = sd_bus_message_close_container(reply);
294 if (r < 0)
295 return sd_bus_error_set_errno(error, r);
296 }
297
298 r = wait_for_terminate(child, &si);
299 if (r < 0)
300 return sd_bus_error_set_errno(error, r);
301 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
302 return sd_bus_error_set_errno(error, EIO);
303
304 r = sd_bus_message_close_container(reply);
305 if (r < 0)
306 return sd_bus_error_set_errno(error, r);
307
308 return sd_bus_send(bus, reply, NULL);
309}
310
717603e3
LP
311int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
312 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
313 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
314 _cleanup_close_pair_ int pair[2] = { -1, -1 };
315 _cleanup_strv_free_ char **l = NULL;
316 _cleanup_fclose_ FILE *f = NULL;
317 Machine *m = userdata;
318 char **k, **v;
319 siginfo_t si;
320 pid_t child;
321 int r;
322
323 assert(bus);
324 assert(message);
325 assert(m);
326
b4d8ef7c
LP
327 if (m->class != MACHINE_CONTAINER)
328 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
329
717603e3
LP
330 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
331 if (r < 0)
40205d70 332 return r;
717603e3
LP
333
334 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
40205d70 335 return -errno;
717603e3
LP
336
337 child = fork();
338 if (child < 0)
40205d70 339 return -errno;
717603e3
LP
340
341 if (child == 0) {
342 _cleanup_close_ int fd = -1;
343
344 pair[0] = safe_close(pair[0]);
345
346 r = namespace_enter(-1, mntns_fd, -1, root_fd);
347 if (r < 0)
348 _exit(EXIT_FAILURE);
349
350 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
351 if (fd < 0) {
352 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
353 if (fd < 0)
354 _exit(EXIT_FAILURE);
355 }
356
7430ec6a 357 r = copy_bytes(fd, pair[1], (off_t) -1, false);
717603e3
LP
358 if (r < 0)
359 _exit(EXIT_FAILURE);
360
361 _exit(EXIT_SUCCESS);
362 }
363
364 pair[1] = safe_close(pair[1]);
365
366 f = fdopen(pair[0], "re");
367 if (!f)
40205d70 368 return -errno;
717603e3
LP
369
370 pair[0] = -1;
371
372 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
373 if (r < 0)
40205d70 374 return r;
717603e3
LP
375
376 r = wait_for_terminate(child, &si);
377 if (r < 0)
40205d70 378 return r;
717603e3 379 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
40205d70 380 return -EIO;
717603e3
LP
381
382 r = sd_bus_message_new_method_return(message, &reply);
383 if (r < 0)
40205d70 384 return r;
717603e3
LP
385
386 r = sd_bus_message_open_container(reply, 'a', "{ss}");
387 if (r < 0)
40205d70 388 return r;
717603e3
LP
389
390 STRV_FOREACH_PAIR(k, v, l) {
391 r = sd_bus_message_append(reply, "{ss}", *k, *v);
392 if (r < 0)
40205d70 393 return r;
717603e3
LP
394 }
395
396 r = sd_bus_message_close_container(reply);
397 if (r < 0)
40205d70
LP
398 return r;
399
400 return sd_bus_send(bus, reply, NULL);
401}
402
403int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
40205d70 404 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
5f8cc96a 405 _cleanup_free_ char *pty_name = NULL;
40205d70 406 _cleanup_close_ int master = -1;
40205d70 407 Machine *m = userdata;
40205d70
LP
408 int r;
409
410 assert(bus);
411 assert(message);
412 assert(m);
413
b4d8ef7c
LP
414 if (m->class != MACHINE_CONTAINER)
415 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening pseudo TTYs is only supported on container machines.");
416
5f8cc96a
LP
417 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
418 if (master < 0)
419 return master;
420
421 r = ptsname_malloc(master, &pty_name);
40205d70
LP
422 if (r < 0)
423 return r;
424
5f8cc96a
LP
425 r = sd_bus_message_new_method_return(message, &reply);
426 if (r < 0)
427 return r;
40205d70 428
5f8cc96a
LP
429 r = sd_bus_message_append(reply, "hs", master, pty_name);
430 if (r < 0)
431 return r;
40205d70 432
5f8cc96a
LP
433 return sd_bus_send(bus, reply, NULL);
434}
40205d70 435
5f8cc96a
LP
436int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
437 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
438 _cleanup_free_ char *pty_name = NULL, *getty = NULL;
439 _cleanup_bus_unref_ sd_bus *container_bus = NULL;
440 _cleanup_close_ int master = -1;
441 Machine *m = userdata;
442 const char *p;
443 int r;
40205d70 444
b4d8ef7c
LP
445 if (m->class != MACHINE_CONTAINER)
446 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening logins is only supported on container machines.");
447
d04c1fb8
LP
448 r = bus_verify_polkit_async(
449 message,
450 CAP_SYS_ADMIN,
451 "org.freedesktop.machine1.login",
452 false,
453 &m->manager->polkit_registry,
454 error);
455 if (r < 0)
456 return r;
457 if (r == 0)
458 return 1; /* Will call us back */
459
5f8cc96a
LP
460 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
461 if (master < 0)
462 return master;
40205d70 463
5f8cc96a 464 r = ptsname_malloc(master, &pty_name);
40205d70
LP
465 if (r < 0)
466 return r;
40205d70 467
5f8cc96a
LP
468 p = path_startswith(pty_name, "/dev/pts/");
469 if (!p)
470 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
40205d70 471
5f8cc96a
LP
472 if (unlockpt(master) < 0)
473 return -errno;
40205d70 474
5f8cc96a
LP
475 r = sd_bus_new(&container_bus);
476 if (r < 0)
477 return r;
40205d70 478
5f8cc96a 479#ifdef ENABLE_KDBUS
146d4773 480 asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT ";x-machine-unix:pid=" PID_FMT, m->leader, m->leader);
5f8cc96a 481#else
146d4773 482 asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT, m->leader);
5f8cc96a
LP
483#endif
484 if (!container_bus->address)
485 return -ENOMEM;
40205d70 486
5f8cc96a
LP
487 container_bus->bus_client = true;
488 container_bus->trusted = false;
489 container_bus->is_system = true;
40205d70 490
5f8cc96a
LP
491 r = sd_bus_start(container_bus);
492 if (r < 0)
493 return r;
40205d70 494
5f8cc96a
LP
495 getty = strjoin("container-getty@", p, ".service", NULL);
496 if (!getty)
497 return -ENOMEM;
498
499 r = sd_bus_call_method(
500 container_bus,
501 "org.freedesktop.systemd1",
502 "/org/freedesktop/systemd1",
503 "org.freedesktop.systemd1.Manager",
504 "StartUnit",
505 error, NULL,
506 "ss", getty, "replace");
ee451d76
LP
507 if (r < 0)
508 return r;
509
5f8cc96a
LP
510 container_bus = sd_bus_unref(container_bus);
511
40205d70
LP
512 r = sd_bus_message_new_method_return(message, &reply);
513 if (r < 0)
514 return r;
515
ee451d76 516 r = sd_bus_message_append(reply, "hs", master, pty_name);
40205d70
LP
517 if (r < 0)
518 return r;
717603e3
LP
519
520 return sd_bus_send(bus, reply, NULL);
521}
522
90adaa25
LP
523int bus_machine_method_bind_mount(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
524 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
525 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
526 bool mount_slave_created = false, mount_slave_mounted = false,
527 mount_tmp_created = false, mount_tmp_mounted = false,
528 mount_outside_created = false, mount_outside_mounted = false;
529 const char *dest, *src;
530 Machine *m = userdata;
531 int read_only, make_directory;
532 pid_t child;
533 siginfo_t si;
534 int r;
535
536 if (m->class != MACHINE_CONTAINER)
537 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
538
539 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
540 if (r < 0)
541 return r;
542
543 if (!path_is_absolute(src) || !path_is_safe(src))
544 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
545
546 if (isempty(dest))
547 dest = src;
548 else if (!path_is_absolute(dest) || !path_is_safe(dest))
549 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
550
551 /* One day, when bind mounting /proc/self/fd/n works across
552 * namespace boundaries we should rework this logic to make
553 * use of it... */
554
555 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
556 if (laccess(p, F_OK) < 0)
557 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
558
559 /* Our goal is to install a new bind mount into the container,
560 possibly read-only. This is irritatingly complex
561 unfortunately, currently.
562
563 First, we start by creating a private playground in /tmp,
564 that we can mount MS_SLAVE. (Which is necessary, since
565 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
566 mounts.) */
567
568 if (!mkdtemp(mount_slave))
569 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
570
571 mount_slave_created = true;
572
573 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
574 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
575 goto finish;
576 }
577
578 mount_slave_mounted = true;
579
580 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
581 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
582 goto finish;
583 }
584
585 /* Second, we mount the source directory to a directory inside
586 of our MS_SLAVE playground. */
587 mount_tmp = strjoina(mount_slave, "/mount");
588 if (mkdir(mount_tmp, 0700) < 0) {
589 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
590 goto finish;
591 }
592
593 mount_tmp_created = true;
594
595 if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
596 r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
597 goto finish;
598 }
599
600 mount_tmp_mounted = true;
601
602 /* Third, we remount the new bind mount read-only if requested. */
603 if (read_only)
604 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
605 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
606 goto finish;
607 }
608
609 /* Fourth, we move the new bind mount into the propagation
610 * directory. This way it will appear there read-only
611 * right-away. */
612
613 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
614 if (!mkdtemp(mount_outside)) {
615 r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
616 goto finish;
617 }
618
619 mount_outside_created = true;
620
621 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
622 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
623 goto finish;
624 }
625
626 mount_outside_mounted = true;
627 mount_tmp_mounted = false;
628
629 (void) rmdir(mount_tmp);
630 mount_tmp_created = false;
631
632 (void) umount(mount_slave);
633 mount_slave_mounted = false;
634
635 (void) rmdir(mount_slave);
636 mount_slave_created = false;
637
638 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
639 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
640 goto finish;
641 }
642
643 child = fork();
644 if (child < 0) {
645 r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
646 goto finish;
647 }
648
649 if (child == 0) {
650 const char *mount_inside;
651 int mntfd;
652 const char *q;
653
654 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
655
656 q = procfs_file_alloca(m->leader, "ns/mnt");
657 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
658 if (mntfd < 0) {
659 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
660 goto child_fail;
661 }
662
663 if (setns(mntfd, CLONE_NEWNS) < 0) {
664 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
665 goto child_fail;
666 }
667
668 if (make_directory)
669 (void) mkdir_p(dest, 0755);
670
671 /* Fifth, move the mount to the right place inside */
672 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
673 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
674 r = log_error_errno(errno, "Failed to mount: %m");
675 goto child_fail;
676 }
677
678 _exit(EXIT_SUCCESS);
679
680 child_fail:
681 (void) write(errno_pipe_fd[1], &r, sizeof(r));
682 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
683
684 _exit(EXIT_FAILURE);
685 }
686
687 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
688
689 r = wait_for_terminate(child, &si);
690 if (r < 0) {
691 r = sd_bus_error_set_errnof(error, errno, "Failed to wait for client: %m");
692 goto finish;
693 }
694 if (si.si_code != CLD_EXITED) {
695 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
696 goto finish;
697 }
698 if (si.si_status != EXIT_SUCCESS) {
699
700 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
701 r = sd_bus_error_set_errnof(error, r, "Failed to mount in container: %m");
702 else
703 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client failed.");
704 goto finish;
705 }
706
707 r = sd_bus_reply_method_return(message, NULL);
708
709finish:
710 if (mount_outside_mounted)
711 umount(mount_outside);
712 if (mount_outside_created)
713 rmdir(mount_outside);
714
715 if (mount_tmp_mounted)
716 umount(mount_tmp);
717 if (mount_tmp_created)
718 rmdir(mount_tmp);
719
720 if (mount_slave_mounted)
721 umount(mount_slave);
722 if (mount_slave_created)
723 rmdir(mount_slave);
724
725 return r;
726}
727
c3350683
LP
728const sd_bus_vtable machine_vtable[] = {
729 SD_BUS_VTABLE_START(0),
556089dc
LP
730 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
731 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
732 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
733 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
89f7c846
LP
734 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
735 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
556089dc
LP
736 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
737 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
738 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
9b5ed6fe 739 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c3350683 740 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
878cd7e9
LP
741 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
742 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
0dd25fb9 743 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 744 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 745 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
d04c1fb8 746 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
90adaa25 747 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, 0),
717603e3 748 SD_BUS_VTABLE_END
c3350683 749};
9444b1f2 750
f00c3121 751int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
c3350683
LP
752 Manager *m = userdata;
753 Machine *machine;
927b1649 754 int r;
9444b1f2 755
c3350683
LP
756 assert(bus);
757 assert(path);
758 assert(interface);
759 assert(found);
760 assert(m);
9444b1f2 761
927b1649 762 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
5b12334d 763 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
927b1649
LP
764 sd_bus_message *message;
765 pid_t pid;
9444b1f2 766
19befb2d 767 message = sd_bus_get_current_message(bus);
927b1649
LP
768 if (!message)
769 return 0;
770
5b12334d 771 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
927b1649 772 if (r < 0)
5b12334d
LP
773 return r;
774
775 r = sd_bus_creds_get_pid(creds, &pid);
776 if (r < 0)
777 return r;
9444b1f2 778
927b1649
LP
779 r = manager_get_machine_by_pid(m, pid, &machine);
780 if (r <= 0)
781 return 0;
782 } else {
783 _cleanup_free_ char *e = NULL;
784 const char *p;
785
786 p = startswith(path, "/org/freedesktop/machine1/machine/");
787 if (!p)
788 return 0;
789
a6278b88 790 e = bus_label_unescape(p);
927b1649
LP
791 if (!e)
792 return -ENOMEM;
793
794 machine = hashmap_get(m->machines, e);
795 if (!machine)
796 return 0;
797 }
9444b1f2 798
c3350683
LP
799 *found = machine;
800 return 1;
9444b1f2
LP
801}
802
9444b1f2
LP
803char *machine_bus_path(Machine *m) {
804 _cleanup_free_ char *e = NULL;
805
806 assert(m);
807
a6278b88 808 e = bus_label_escape(m->name);
9444b1f2
LP
809 if (!e)
810 return NULL;
811
1ee306e1 812 return strappend("/org/freedesktop/machine1/machine/", e);
9444b1f2
LP
813}
814
f00c3121 815int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
927b1649
LP
816 _cleanup_strv_free_ char **l = NULL;
817 Machine *machine = NULL;
818 Manager *m = userdata;
819 Iterator i;
820 int r;
821
822 assert(bus);
823 assert(path);
824 assert(nodes);
825
826 HASHMAP_FOREACH(machine, m->machines, i) {
827 char *p;
828
829 p = machine_bus_path(machine);
830 if (!p)
831 return -ENOMEM;
832
6e18964d
ZJS
833 r = strv_consume(&l, p);
834 if (r < 0)
927b1649 835 return r;
927b1649
LP
836 }
837
838 *nodes = l;
839 l = NULL;
840
841 return 1;
842}
843
9444b1f2 844int machine_send_signal(Machine *m, bool new_machine) {
9444b1f2
LP
845 _cleanup_free_ char *p = NULL;
846
847 assert(m);
848
9444b1f2
LP
849 p = machine_bus_path(m);
850 if (!p)
851 return -ENOMEM;
852
c3350683
LP
853 return sd_bus_emit_signal(
854 m->manager->bus,
855 "/org/freedesktop/machine1",
856 "org.freedesktop.machine1.Manager",
857 new_machine ? "MachineNew" : "MachineRemoved",
858 "so", m->name, p);
9444b1f2
LP
859}
860
c3350683
LP
861int machine_send_create_reply(Machine *m, sd_bus_error *error) {
862 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
9444b1f2
LP
863 _cleanup_free_ char *p = NULL;
864
865 assert(m);
866
fb6becb4
LP
867 if (!m->create_message)
868 return 0;
869
c3350683
LP
870 c = m->create_message;
871 m->create_message = NULL;
fb6becb4 872
a658cafa 873 if (error)
df2d202e 874 return sd_bus_reply_method_error(c, error);
a658cafa 875
76e66585
LP
876 /* Update the machine state file before we notify the client
877 * about the result. */
878 machine_save(m);
879
c3350683
LP
880 p = machine_bus_path(m);
881 if (!p)
882 return -ENOMEM;
fb6becb4 883
df2d202e 884 return sd_bus_reply_method_return(c, "o", p);
fb6becb4 885}