]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine-dbus.c
Merge pull request #1527 from keszybz/lz4
[thirdparty/systemd.git] / src / machine / machine-dbus.c
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 <sys/mount.h>
25
26 /* When we include libgen.h because we need dirname() we immediately
27 * undefine basename() since libgen.h defines it as a macro to the POSIX
28 * version which is really broken. We prefer GNU basename(). */
29 #include <libgen.h>
30 #undef basename
31
32 #include "bus-util.h"
33 #include "bus-label.h"
34 #include "strv.h"
35 #include "bus-common-errors.h"
36 #include "copy.h"
37 #include "fileio.h"
38 #include "in-addr-util.h"
39 #include "local-addresses.h"
40 #include "path-util.h"
41 #include "mkdir.h"
42 #include "bus-internal.h"
43 #include "machine.h"
44 #include "machine-dbus.h"
45 #include "formats-util.h"
46 #include "process-util.h"
47 #include "env-util.h"
48 #include "terminal-util.h"
49
50 static int property_get_id(
51 sd_bus *bus,
52 const char *path,
53 const char *interface,
54 const char *property,
55 sd_bus_message *reply,
56 void *userdata,
57 sd_bus_error *error) {
58
59 Machine *m = userdata;
60
61 assert(bus);
62 assert(reply);
63 assert(m);
64
65 return sd_bus_message_append_array(reply, 'y', &m->id, 16);
66 }
67
68 static int property_get_state(
69 sd_bus *bus,
70 const char *path,
71 const char *interface,
72 const char *property,
73 sd_bus_message *reply,
74 void *userdata,
75 sd_bus_error *error) {
76
77 Machine *m = userdata;
78 const char *state;
79 int r;
80
81 assert(bus);
82 assert(reply);
83 assert(m);
84
85 state = machine_state_to_string(machine_get_state(m));
86
87 r = sd_bus_message_append_basic(reply, 's', state);
88 if (r < 0)
89 return r;
90
91 return 1;
92 }
93
94 static int property_get_netif(
95 sd_bus *bus,
96 const char *path,
97 const char *interface,
98 const char *property,
99 sd_bus_message *reply,
100 void *userdata,
101 sd_bus_error *error) {
102
103 Machine *m = userdata;
104
105 assert(bus);
106 assert(reply);
107 assert(m);
108
109 assert_cc(sizeof(int) == sizeof(int32_t));
110
111 return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
112 }
113
114 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
115
116 int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
117 Machine *m = userdata;
118 int r;
119
120 assert(message);
121 assert(m);
122
123 r = bus_verify_polkit_async(
124 message,
125 CAP_KILL,
126 "org.freedesktop.machine1.manage-machines",
127 NULL,
128 false,
129 UID_INVALID,
130 &m->manager->polkit_registry,
131 error);
132 if (r < 0)
133 return r;
134 if (r == 0)
135 return 1; /* Will call us back */
136
137 r = machine_stop(m);
138 if (r < 0)
139 return r;
140
141 return sd_bus_reply_method_return(message, NULL);
142 }
143
144 int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
145 Machine *m = userdata;
146 const char *swho;
147 int32_t signo;
148 KillWho who;
149 int r;
150
151 assert(message);
152 assert(m);
153
154 r = sd_bus_message_read(message, "si", &swho, &signo);
155 if (r < 0)
156 return r;
157
158 if (isempty(swho))
159 who = KILL_ALL;
160 else {
161 who = kill_who_from_string(swho);
162 if (who < 0)
163 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
164 }
165
166 if (signo <= 0 || signo >= _NSIG)
167 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
168
169 r = bus_verify_polkit_async(
170 message,
171 CAP_KILL,
172 "org.freedesktop.machine1.manage-machines",
173 NULL,
174 false,
175 UID_INVALID,
176 &m->manager->polkit_registry,
177 error);
178 if (r < 0)
179 return r;
180 if (r == 0)
181 return 1; /* Will call us back */
182
183 r = machine_kill(m, who, signo);
184 if (r < 0)
185 return r;
186
187 return sd_bus_reply_method_return(message, NULL);
188 }
189
190 int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
191 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
192 Machine *m = userdata;
193 int r;
194
195 assert(message);
196 assert(m);
197
198 r = sd_bus_message_new_method_return(message, &reply);
199 if (r < 0)
200 return r;
201
202 r = sd_bus_message_open_container(reply, 'a', "(iay)");
203 if (r < 0)
204 return r;
205
206 switch (m->class) {
207
208 case MACHINE_HOST: {
209 _cleanup_free_ struct local_address *addresses = NULL;
210 struct local_address *a;
211 int n, i;
212
213 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
214 if (n < 0)
215 return n;
216
217 for (a = addresses, i = 0; i < n; a++, i++) {
218
219 r = sd_bus_message_open_container(reply, 'r', "iay");
220 if (r < 0)
221 return r;
222
223 r = sd_bus_message_append(reply, "i", addresses[i].family);
224 if (r < 0)
225 return r;
226
227 r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family));
228 if (r < 0)
229 return r;
230
231 r = sd_bus_message_close_container(reply);
232 if (r < 0)
233 return r;
234 }
235
236 break;
237 }
238
239 case MACHINE_CONTAINER: {
240 _cleanup_close_pair_ int pair[2] = { -1, -1 };
241 _cleanup_free_ char *us = NULL, *them = NULL;
242 _cleanup_close_ int netns_fd = -1;
243 const char *p;
244 siginfo_t si;
245 pid_t child;
246
247 r = readlink_malloc("/proc/self/ns/net", &us);
248 if (r < 0)
249 return r;
250
251 p = procfs_file_alloca(m->leader, "ns/net");
252 r = readlink_malloc(p, &them);
253 if (r < 0)
254 return r;
255
256 if (streq(us, them))
257 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
258
259 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL, NULL);
260 if (r < 0)
261 return r;
262
263 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
264 return -errno;
265
266 child = fork();
267 if (child < 0)
268 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
269
270 if (child == 0) {
271 _cleanup_free_ struct local_address *addresses = NULL;
272 struct local_address *a;
273 int i, n;
274
275 pair[0] = safe_close(pair[0]);
276
277 r = namespace_enter(-1, -1, netns_fd, -1, -1);
278 if (r < 0)
279 _exit(EXIT_FAILURE);
280
281 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
282 if (n < 0)
283 _exit(EXIT_FAILURE);
284
285 for (a = addresses, i = 0; i < n; a++, i++) {
286 struct iovec iov[2] = {
287 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
288 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
289 };
290
291 r = writev(pair[1], iov, 2);
292 if (r < 0)
293 _exit(EXIT_FAILURE);
294 }
295
296 pair[1] = safe_close(pair[1]);
297
298 _exit(EXIT_SUCCESS);
299 }
300
301 pair[1] = safe_close(pair[1]);
302
303 for (;;) {
304 int family;
305 ssize_t n;
306 union in_addr_union in_addr;
307 struct iovec iov[2];
308 struct msghdr mh = {
309 .msg_iov = iov,
310 .msg_iovlen = 2,
311 };
312
313 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
314 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
315
316 n = recvmsg(pair[0], &mh, 0);
317 if (n < 0)
318 return -errno;
319 if ((size_t) n < sizeof(family))
320 break;
321
322 r = sd_bus_message_open_container(reply, 'r', "iay");
323 if (r < 0)
324 return r;
325
326 r = sd_bus_message_append(reply, "i", family);
327 if (r < 0)
328 return r;
329
330 switch (family) {
331
332 case AF_INET:
333 if (n != sizeof(struct in_addr) + sizeof(family))
334 return -EIO;
335
336 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
337 break;
338
339 case AF_INET6:
340 if (n != sizeof(struct in6_addr) + sizeof(family))
341 return -EIO;
342
343 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
344 break;
345 }
346 if (r < 0)
347 return r;
348
349 r = sd_bus_message_close_container(reply);
350 if (r < 0)
351 return r;
352 }
353
354 r = wait_for_terminate(child, &si);
355 if (r < 0)
356 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
357 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
358 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
359 break;
360 }
361
362 default:
363 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
364 }
365
366 r = sd_bus_message_close_container(reply);
367 if (r < 0)
368 return r;
369
370 return sd_bus_send(NULL, reply, NULL);
371 }
372
373 int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
374 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
375 _cleanup_strv_free_ char **l = NULL;
376 Machine *m = userdata;
377 char **k, **v;
378 int r;
379
380 assert(message);
381 assert(m);
382
383 switch (m->class) {
384
385 case MACHINE_HOST:
386 r = load_env_file_pairs(NULL, "/etc/os-release", NULL, &l);
387 if (r < 0)
388 return r;
389
390 break;
391
392 case MACHINE_CONTAINER: {
393 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
394 _cleanup_close_pair_ int pair[2] = { -1, -1 };
395 _cleanup_fclose_ FILE *f = NULL;
396 siginfo_t si;
397 pid_t child;
398
399 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
400 if (r < 0)
401 return r;
402
403 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
404 return -errno;
405
406 child = fork();
407 if (child < 0)
408 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
409
410 if (child == 0) {
411 _cleanup_close_ int fd = -1;
412
413 pair[0] = safe_close(pair[0]);
414
415 r = namespace_enter(-1, mntns_fd, -1, -1, root_fd);
416 if (r < 0)
417 _exit(EXIT_FAILURE);
418
419 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
420 if (fd < 0) {
421 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
422 if (fd < 0)
423 _exit(EXIT_FAILURE);
424 }
425
426 r = copy_bytes(fd, pair[1], (uint64_t) -1, false);
427 if (r < 0)
428 _exit(EXIT_FAILURE);
429
430 _exit(EXIT_SUCCESS);
431 }
432
433 pair[1] = safe_close(pair[1]);
434
435 f = fdopen(pair[0], "re");
436 if (!f)
437 return -errno;
438
439 pair[0] = -1;
440
441 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
442 if (r < 0)
443 return r;
444
445 r = wait_for_terminate(child, &si);
446 if (r < 0)
447 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
448 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
449 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
450
451 break;
452 }
453
454 default:
455 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
456 }
457
458 r = sd_bus_message_new_method_return(message, &reply);
459 if (r < 0)
460 return r;
461
462 r = sd_bus_message_open_container(reply, 'a', "{ss}");
463 if (r < 0)
464 return r;
465
466 STRV_FOREACH_PAIR(k, v, l) {
467 r = sd_bus_message_append(reply, "{ss}", *k, *v);
468 if (r < 0)
469 return r;
470 }
471
472 r = sd_bus_message_close_container(reply);
473 if (r < 0)
474 return r;
475
476 return sd_bus_send(NULL, reply, NULL);
477 }
478
479 int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
480 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
481 _cleanup_free_ char *pty_name = NULL;
482 _cleanup_close_ int master = -1;
483 Machine *m = userdata;
484 int r;
485
486 assert(message);
487 assert(m);
488
489 r = bus_verify_polkit_async(
490 message,
491 CAP_SYS_ADMIN,
492 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty",
493 NULL,
494 false,
495 UID_INVALID,
496 &m->manager->polkit_registry,
497 error);
498 if (r < 0)
499 return r;
500 if (r == 0)
501 return 1; /* Will call us back */
502
503 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
504 if (master < 0)
505 return master;
506
507 r = ptsname_namespace(master, &pty_name);
508 if (r < 0)
509 return r;
510
511 r = sd_bus_message_new_method_return(message, &reply);
512 if (r < 0)
513 return r;
514
515 r = sd_bus_message_append(reply, "hs", master, pty_name);
516 if (r < 0)
517 return r;
518
519 return sd_bus_send(NULL, reply, NULL);
520 }
521
522 static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) {
523 int r;
524
525 assert(m);
526 assert(ret);
527
528 switch (m->class) {
529
530 case MACHINE_HOST:
531 *ret = NULL;
532 break;
533
534 case MACHINE_CONTAINER: {
535 _cleanup_bus_unref_ sd_bus *bus = NULL;
536 char *address;
537
538 r = sd_bus_new(&bus);
539 if (r < 0)
540 return r;
541
542 if (asprintf(&address, "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI, m->leader) < 0)
543 return -ENOMEM;
544
545 bus->address = address;
546 bus->bus_client = true;
547 bus->trusted = false;
548 bus->is_system = true;
549
550 r = sd_bus_start(bus);
551 if (r == -ENOENT)
552 return sd_bus_error_set_errnof(error, r, "There is no system bus in container %s.", m->name);
553 if (r < 0)
554 return r;
555
556 *ret = bus;
557 bus = NULL;
558 break;
559 }
560
561 default:
562 return -EOPNOTSUPP;
563 }
564
565 return 0;
566 }
567
568 int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
569 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
570 _cleanup_free_ char *pty_name = NULL;
571 _cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL;
572 _cleanup_close_ int master = -1;
573 sd_bus *container_bus = NULL;
574 Machine *m = userdata;
575 const char *p, *getty;
576 int r;
577
578 assert(message);
579 assert(m);
580
581 r = bus_verify_polkit_async(
582 message,
583 CAP_SYS_ADMIN,
584 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
585 NULL,
586 false,
587 UID_INVALID,
588 &m->manager->polkit_registry,
589 error);
590 if (r < 0)
591 return r;
592 if (r == 0)
593 return 1; /* Will call us back */
594
595 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
596 if (master < 0)
597 return master;
598
599 r = ptsname_namespace(master, &pty_name);
600 if (r < 0)
601 return r;
602
603 p = path_startswith(pty_name, "/dev/pts/");
604 if (!p)
605 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
606
607 r = container_bus_new(m, error, &allocated_bus);
608 if (r < 0)
609 return r;
610
611 container_bus = allocated_bus ?: m->manager->bus;
612
613 getty = strjoina("container-getty@", p, ".service");
614
615 r = sd_bus_call_method(
616 container_bus,
617 "org.freedesktop.systemd1",
618 "/org/freedesktop/systemd1",
619 "org.freedesktop.systemd1.Manager",
620 "StartUnit",
621 error, NULL,
622 "ss", getty, "replace");
623 if (r < 0)
624 return r;
625
626 r = sd_bus_message_new_method_return(message, &reply);
627 if (r < 0)
628 return r;
629
630 r = sd_bus_message_append(reply, "hs", master, pty_name);
631 if (r < 0)
632 return r;
633
634 return sd_bus_send(NULL, reply, NULL);
635 }
636
637 int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
638 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *tm = NULL;
639 _cleanup_free_ char *pty_name = NULL;
640 _cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL;
641 sd_bus *container_bus = NULL;
642 _cleanup_close_ int master = -1, slave = -1;
643 _cleanup_strv_free_ char **env = NULL, **args = NULL;
644 Machine *m = userdata;
645 const char *p, *unit, *user, *path, *description, *utmp_id;
646 int r;
647
648 assert(message);
649 assert(m);
650
651 r = sd_bus_message_read(message, "ss", &user, &path);
652 if (r < 0)
653 return r;
654 if (isempty(user))
655 user = NULL;
656 if (isempty(path))
657 path = "/bin/sh";
658 if (!path_is_absolute(path))
659 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path '%s' is not absolute", path);
660
661 r = sd_bus_message_read_strv(message, &args);
662 if (r < 0)
663 return r;
664 if (strv_isempty(args)) {
665 args = strv_free(args);
666
667 args = strv_new(path, NULL);
668 if (!args)
669 return -ENOMEM;
670
671 args[0][0] = '-'; /* Tell /bin/sh that this shall be a login shell */
672 }
673
674 r = sd_bus_message_read_strv(message, &env);
675 if (r < 0)
676 return r;
677 if (!strv_env_is_valid(env))
678 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
679
680 r = bus_verify_polkit_async(
681 message,
682 CAP_SYS_ADMIN,
683 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
684 NULL,
685 false,
686 UID_INVALID,
687 &m->manager->polkit_registry,
688 error);
689 if (r < 0)
690 return r;
691 if (r == 0)
692 return 1; /* Will call us back */
693
694 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
695 if (master < 0)
696 return master;
697
698 r = ptsname_namespace(master, &pty_name);
699 if (r < 0)
700 return r;
701
702 p = path_startswith(pty_name, "/dev/pts/");
703 assert(p);
704
705 slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
706 if (slave < 0)
707 return slave;
708
709 utmp_id = path_startswith(pty_name, "/dev/");
710 assert(utmp_id);
711
712 r = container_bus_new(m, error, &allocated_bus);
713 if (r < 0)
714 return r;
715
716 container_bus = allocated_bus ?: m->manager->bus;
717
718 r = sd_bus_message_new_method_call(
719 container_bus,
720 &tm,
721 "org.freedesktop.systemd1",
722 "/org/freedesktop/systemd1",
723 "org.freedesktop.systemd1.Manager",
724 "StartTransientUnit");
725 if (r < 0)
726 return r;
727
728 /* Name and mode */
729 unit = strjoina("container-shell@", p, ".service", NULL);
730 r = sd_bus_message_append(tm, "ss", unit, "fail");
731 if (r < 0)
732 return r;
733
734 /* Properties */
735 r = sd_bus_message_open_container(tm, 'a', "(sv)");
736 if (r < 0)
737 return r;
738
739 description = strjoina("Shell for User ", isempty(user) ? "root" : user);
740 r = sd_bus_message_append(tm,
741 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
742 "Description", "s", description,
743 "StandardInputFileDescriptor", "h", slave,
744 "StandardOutputFileDescriptor", "h", slave,
745 "StandardErrorFileDescriptor", "h", slave,
746 "SendSIGHUP", "b", true,
747 "IgnoreSIGPIPE", "b", false,
748 "KillMode", "s", "mixed",
749 "TTYReset", "b", true,
750 "UtmpIdentifier", "s", utmp_id,
751 "UtmpMode", "s", "user",
752 "PAMName", "s", "login",
753 "WorkingDirectory", "s", "-~");
754 if (r < 0)
755 return r;
756
757 r = sd_bus_message_append(tm, "(sv)", "User", "s", isempty(user) ? "root" : user);
758 if (r < 0)
759 return r;
760
761 if (!strv_isempty(env)) {
762 r = sd_bus_message_open_container(tm, 'r', "sv");
763 if (r < 0)
764 return r;
765
766 r = sd_bus_message_append(tm, "s", "Environment");
767 if (r < 0)
768 return r;
769
770 r = sd_bus_message_open_container(tm, 'v', "as");
771 if (r < 0)
772 return r;
773
774 r = sd_bus_message_append_strv(tm, env);
775 if (r < 0)
776 return r;
777
778 r = sd_bus_message_close_container(tm);
779 if (r < 0)
780 return r;
781
782 r = sd_bus_message_close_container(tm);
783 if (r < 0)
784 return r;
785 }
786
787 /* Exec container */
788 r = sd_bus_message_open_container(tm, 'r', "sv");
789 if (r < 0)
790 return r;
791
792 r = sd_bus_message_append(tm, "s", "ExecStart");
793 if (r < 0)
794 return r;
795
796 r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
797 if (r < 0)
798 return r;
799
800 r = sd_bus_message_open_container(tm, 'a', "(sasb)");
801 if (r < 0)
802 return r;
803
804 r = sd_bus_message_open_container(tm, 'r', "sasb");
805 if (r < 0)
806 return r;
807
808 r = sd_bus_message_append(tm, "s", path);
809 if (r < 0)
810 return r;
811
812 r = sd_bus_message_append_strv(tm, args);
813 if (r < 0)
814 return r;
815
816 r = sd_bus_message_append(tm, "b", true);
817 if (r < 0)
818 return r;
819
820 r = sd_bus_message_close_container(tm);
821 if (r < 0)
822 return r;
823
824 r = sd_bus_message_close_container(tm);
825 if (r < 0)
826 return r;
827
828 r = sd_bus_message_close_container(tm);
829 if (r < 0)
830 return r;
831
832 r = sd_bus_message_close_container(tm);
833 if (r < 0)
834 return r;
835
836 r = sd_bus_message_close_container(tm);
837 if (r < 0)
838 return r;
839
840 /* Auxiliary units */
841 r = sd_bus_message_append(tm, "a(sa(sv))", 0);
842 if (r < 0)
843 return r;
844
845 r = sd_bus_call(container_bus, tm, 0, error, NULL);
846 if (r < 0)
847 return r;
848
849 slave = safe_close(slave);
850
851 r = sd_bus_message_new_method_return(message, &reply);
852 if (r < 0)
853 return r;
854
855 r = sd_bus_message_append(reply, "hs", master, pty_name);
856 if (r < 0)
857 return r;
858
859 return sd_bus_send(NULL, reply, NULL);
860 }
861
862 int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
863 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
864 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
865 bool mount_slave_created = false, mount_slave_mounted = false,
866 mount_tmp_created = false, mount_tmp_mounted = false,
867 mount_outside_created = false, mount_outside_mounted = false;
868 const char *dest, *src;
869 Machine *m = userdata;
870 int read_only, make_directory;
871 pid_t child;
872 siginfo_t si;
873 int r;
874
875 assert(message);
876 assert(m);
877
878 if (m->class != MACHINE_CONTAINER)
879 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
880
881 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
882 if (r < 0)
883 return r;
884
885 if (!path_is_absolute(src) || !path_is_safe(src))
886 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
887
888 if (isempty(dest))
889 dest = src;
890 else if (!path_is_absolute(dest) || !path_is_safe(dest))
891 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
892
893 r = bus_verify_polkit_async(
894 message,
895 CAP_SYS_ADMIN,
896 "org.freedesktop.machine1.manage-machines",
897 NULL,
898 false,
899 UID_INVALID,
900 &m->manager->polkit_registry,
901 error);
902 if (r < 0)
903 return r;
904 if (r == 0)
905 return 1; /* Will call us back */
906
907 /* One day, when bind mounting /proc/self/fd/n works across
908 * namespace boundaries we should rework this logic to make
909 * use of it... */
910
911 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
912 if (laccess(p, F_OK) < 0)
913 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
914
915 /* Our goal is to install a new bind mount into the container,
916 possibly read-only. This is irritatingly complex
917 unfortunately, currently.
918
919 First, we start by creating a private playground in /tmp,
920 that we can mount MS_SLAVE. (Which is necessary, since
921 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
922 mounts.) */
923
924 if (!mkdtemp(mount_slave))
925 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
926
927 mount_slave_created = true;
928
929 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
930 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
931 goto finish;
932 }
933
934 mount_slave_mounted = true;
935
936 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
937 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
938 goto finish;
939 }
940
941 /* Second, we mount the source directory to a directory inside
942 of our MS_SLAVE playground. */
943 mount_tmp = strjoina(mount_slave, "/mount");
944 if (mkdir(mount_tmp, 0700) < 0) {
945 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
946 goto finish;
947 }
948
949 mount_tmp_created = true;
950
951 if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
952 r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
953 goto finish;
954 }
955
956 mount_tmp_mounted = true;
957
958 /* Third, we remount the new bind mount read-only if requested. */
959 if (read_only)
960 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
961 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
962 goto finish;
963 }
964
965 /* Fourth, we move the new bind mount into the propagation
966 * directory. This way it will appear there read-only
967 * right-away. */
968
969 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
970 if (!mkdtemp(mount_outside)) {
971 r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
972 goto finish;
973 }
974
975 mount_outside_created = true;
976
977 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
978 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
979 goto finish;
980 }
981
982 mount_outside_mounted = true;
983 mount_tmp_mounted = false;
984
985 (void) rmdir(mount_tmp);
986 mount_tmp_created = false;
987
988 (void) umount(mount_slave);
989 mount_slave_mounted = false;
990
991 (void) rmdir(mount_slave);
992 mount_slave_created = false;
993
994 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
995 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
996 goto finish;
997 }
998
999 child = fork();
1000 if (child < 0) {
1001 r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
1002 goto finish;
1003 }
1004
1005 if (child == 0) {
1006 const char *mount_inside;
1007 int mntfd;
1008 const char *q;
1009
1010 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1011
1012 q = procfs_file_alloca(m->leader, "ns/mnt");
1013 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1014 if (mntfd < 0) {
1015 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1016 goto child_fail;
1017 }
1018
1019 if (setns(mntfd, CLONE_NEWNS) < 0) {
1020 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1021 goto child_fail;
1022 }
1023
1024 if (make_directory)
1025 (void) mkdir_p(dest, 0755);
1026
1027 /* Fifth, move the mount to the right place inside */
1028 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
1029 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
1030 r = log_error_errno(errno, "Failed to mount: %m");
1031 goto child_fail;
1032 }
1033
1034 _exit(EXIT_SUCCESS);
1035
1036 child_fail:
1037 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1038 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1039
1040 _exit(EXIT_FAILURE);
1041 }
1042
1043 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1044
1045 r = wait_for_terminate(child, &si);
1046 if (r < 0) {
1047 r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
1048 goto finish;
1049 }
1050 if (si.si_code != CLD_EXITED) {
1051 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
1052 goto finish;
1053 }
1054 if (si.si_status != EXIT_SUCCESS) {
1055
1056 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
1057 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
1058 else
1059 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed.");
1060 goto finish;
1061 }
1062
1063 r = sd_bus_reply_method_return(message, NULL);
1064
1065 finish:
1066 if (mount_outside_mounted)
1067 umount(mount_outside);
1068 if (mount_outside_created)
1069 rmdir(mount_outside);
1070
1071 if (mount_tmp_mounted)
1072 umount(mount_tmp);
1073 if (mount_tmp_created)
1074 rmdir(mount_tmp);
1075
1076 if (mount_slave_mounted)
1077 umount(mount_slave);
1078 if (mount_slave_created)
1079 rmdir(mount_slave);
1080
1081 return r;
1082 }
1083
1084 static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
1085 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1086 MachineOperation *o = userdata;
1087 int r;
1088
1089 assert(o);
1090 assert(si);
1091
1092 o->pid = 0;
1093
1094 if (si->si_code != CLD_EXITED) {
1095 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
1096 goto fail;
1097 }
1098
1099 if (si->si_status != EXIT_SUCCESS) {
1100 if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
1101 r = sd_bus_error_set_errnof(&error, r, "%m");
1102 else
1103 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
1104
1105 goto fail;
1106 }
1107
1108 r = sd_bus_reply_method_return(o->message, NULL);
1109 if (r < 0)
1110 log_error_errno(r, "Failed to reply to message: %m");
1111
1112 machine_operation_unref(o);
1113 return 0;
1114
1115 fail:
1116 r = sd_bus_reply_method_error(o->message, &error);
1117 if (r < 0)
1118 log_error_errno(r, "Failed to reply to message: %m");
1119
1120 machine_operation_unref(o);
1121 return 0;
1122 }
1123
1124 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1125 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
1126 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
1127 _cleanup_close_ int hostfd = -1;
1128 Machine *m = userdata;
1129 MachineOperation *o;
1130 bool copy_from;
1131 pid_t child;
1132 char *t;
1133 int r;
1134
1135 assert(message);
1136 assert(m);
1137
1138 if (m->n_operations >= MACHINE_OPERATIONS_MAX)
1139 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
1140
1141 if (m->class != MACHINE_CONTAINER)
1142 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
1143
1144 r = sd_bus_message_read(message, "ss", &src, &dest);
1145 if (r < 0)
1146 return r;
1147
1148 if (!path_is_absolute(src))
1149 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
1150
1151 if (isempty(dest))
1152 dest = src;
1153 else if (!path_is_absolute(dest))
1154 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
1155
1156 r = bus_verify_polkit_async(
1157 message,
1158 CAP_SYS_ADMIN,
1159 "org.freedesktop.machine1.manage-machines",
1160 NULL,
1161 false,
1162 UID_INVALID,
1163 &m->manager->polkit_registry,
1164 error);
1165 if (r < 0)
1166 return r;
1167 if (r == 0)
1168 return 1; /* Will call us back */
1169
1170 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
1171
1172 if (copy_from) {
1173 container_path = src;
1174 host_path = dest;
1175 } else {
1176 host_path = src;
1177 container_path = dest;
1178 }
1179
1180 host_basename = basename(host_path);
1181 t = strdupa(host_path);
1182 host_dirname = dirname(t);
1183
1184 container_basename = basename(container_path);
1185 t = strdupa(container_path);
1186 container_dirname = dirname(t);
1187
1188 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1189 if (hostfd < 0)
1190 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
1191
1192 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
1193 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
1194
1195 child = fork();
1196 if (child < 0)
1197 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
1198
1199 if (child == 0) {
1200 int containerfd;
1201 const char *q;
1202 int mntfd;
1203
1204 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1205
1206 q = procfs_file_alloca(m->leader, "ns/mnt");
1207 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1208 if (mntfd < 0) {
1209 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1210 goto child_fail;
1211 }
1212
1213 if (setns(mntfd, CLONE_NEWNS) < 0) {
1214 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1215 goto child_fail;
1216 }
1217
1218 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1219 if (containerfd < 0) {
1220 r = log_error_errno(errno, "Failed top open destination directory: %m");
1221 goto child_fail;
1222 }
1223
1224 if (copy_from)
1225 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
1226 else
1227 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
1228
1229 hostfd = safe_close(hostfd);
1230 containerfd = safe_close(containerfd);
1231
1232 if (r < 0) {
1233 r = log_error_errno(r, "Failed to copy tree: %m");
1234 goto child_fail;
1235 }
1236
1237 _exit(EXIT_SUCCESS);
1238
1239 child_fail:
1240 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1241 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1242
1243 _exit(EXIT_FAILURE);
1244 }
1245
1246 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1247
1248 /* Copying might take a while, hence install a watch the
1249 * child, and return */
1250
1251 o = new0(MachineOperation, 1);
1252 if (!o)
1253 return log_oom();
1254
1255 o->pid = child;
1256 o->message = sd_bus_message_ref(message);
1257 o->errno_fd = errno_pipe_fd[0];
1258 errno_pipe_fd[0] = -1;
1259
1260 r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
1261 if (r < 0) {
1262 machine_operation_unref(o);
1263 return log_oom();
1264 }
1265
1266 LIST_PREPEND(operations, m->operations, o);
1267 m->n_operations++;
1268 o->machine = m;
1269
1270 return 1;
1271 }
1272
1273 const sd_bus_vtable machine_vtable[] = {
1274 SD_BUS_VTABLE_START(0),
1275 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
1276 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1277 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1278 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
1279 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
1280 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1281 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
1282 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
1283 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
1284 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1285 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
1286 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
1287 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
1288 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
1289 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
1290 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED),
1291 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
1292 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED),
1293 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
1294 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
1295 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
1296 SD_BUS_VTABLE_END
1297 };
1298
1299 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
1300 Manager *m = userdata;
1301 Machine *machine;
1302 int r;
1303
1304 assert(bus);
1305 assert(path);
1306 assert(interface);
1307 assert(found);
1308 assert(m);
1309
1310 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
1311 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1312 sd_bus_message *message;
1313 pid_t pid;
1314
1315 message = sd_bus_get_current_message(bus);
1316 if (!message)
1317 return 0;
1318
1319 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1320 if (r < 0)
1321 return r;
1322
1323 r = sd_bus_creds_get_pid(creds, &pid);
1324 if (r < 0)
1325 return r;
1326
1327 r = manager_get_machine_by_pid(m, pid, &machine);
1328 if (r <= 0)
1329 return 0;
1330 } else {
1331 _cleanup_free_ char *e = NULL;
1332 const char *p;
1333
1334 p = startswith(path, "/org/freedesktop/machine1/machine/");
1335 if (!p)
1336 return 0;
1337
1338 e = bus_label_unescape(p);
1339 if (!e)
1340 return -ENOMEM;
1341
1342 machine = hashmap_get(m->machines, e);
1343 if (!machine)
1344 return 0;
1345 }
1346
1347 *found = machine;
1348 return 1;
1349 }
1350
1351 char *machine_bus_path(Machine *m) {
1352 _cleanup_free_ char *e = NULL;
1353
1354 assert(m);
1355
1356 e = bus_label_escape(m->name);
1357 if (!e)
1358 return NULL;
1359
1360 return strappend("/org/freedesktop/machine1/machine/", e);
1361 }
1362
1363 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1364 _cleanup_strv_free_ char **l = NULL;
1365 Machine *machine = NULL;
1366 Manager *m = userdata;
1367 Iterator i;
1368 int r;
1369
1370 assert(bus);
1371 assert(path);
1372 assert(nodes);
1373
1374 HASHMAP_FOREACH(machine, m->machines, i) {
1375 char *p;
1376
1377 p = machine_bus_path(machine);
1378 if (!p)
1379 return -ENOMEM;
1380
1381 r = strv_consume(&l, p);
1382 if (r < 0)
1383 return r;
1384 }
1385
1386 *nodes = l;
1387 l = NULL;
1388
1389 return 1;
1390 }
1391
1392 int machine_send_signal(Machine *m, bool new_machine) {
1393 _cleanup_free_ char *p = NULL;
1394
1395 assert(m);
1396
1397 p = machine_bus_path(m);
1398 if (!p)
1399 return -ENOMEM;
1400
1401 return sd_bus_emit_signal(
1402 m->manager->bus,
1403 "/org/freedesktop/machine1",
1404 "org.freedesktop.machine1.Manager",
1405 new_machine ? "MachineNew" : "MachineRemoved",
1406 "so", m->name, p);
1407 }
1408
1409 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1410 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
1411 _cleanup_free_ char *p = NULL;
1412
1413 assert(m);
1414
1415 if (!m->create_message)
1416 return 0;
1417
1418 c = m->create_message;
1419 m->create_message = NULL;
1420
1421 if (error)
1422 return sd_bus_reply_method_error(c, error);
1423
1424 /* Update the machine state file before we notify the client
1425 * about the result. */
1426 machine_save(m);
1427
1428 p = machine_bus_path(m);
1429 if (!p)
1430 return -ENOMEM;
1431
1432 return sd_bus_reply_method_return(c, "o", p);
1433 }