]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine-dbus.c
b010c909890d755cc5f8605c36e4b86c1579191b
[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;
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 if (!p)
704 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
705
706 utmp_id = path_startswith(pty_name, "/dev/");
707 assert(utmp_id);
708
709 r = container_bus_new(m, error, &allocated_bus);
710 if (r < 0)
711 return r;
712
713 container_bus = allocated_bus ?: m->manager->bus;
714
715 r = sd_bus_message_new_method_call(
716 container_bus,
717 &tm,
718 "org.freedesktop.systemd1",
719 "/org/freedesktop/systemd1",
720 "org.freedesktop.systemd1.Manager",
721 "StartTransientUnit");
722 if (r < 0)
723 return r;
724
725 /* Name and mode */
726 unit = strjoina("container-shell@", p, ".service", NULL);
727 r = sd_bus_message_append(tm, "ss", unit, "fail");
728 if (r < 0)
729 return r;
730
731 /* Properties */
732 r = sd_bus_message_open_container(tm, 'a', "(sv)");
733 if (r < 0)
734 return r;
735
736 description = strjoina("Shell for User ", isempty(user) ? "root" : user);
737 r = sd_bus_message_append(tm,
738 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
739 "Description", "s", description,
740 "StandardInput", "s", "tty",
741 "StandardOutput", "s", "tty",
742 "StandardError", "s", "tty",
743 "TTYPath", "s", pty_name,
744 "SendSIGHUP", "b", true,
745 "IgnoreSIGPIPE", "b", false,
746 "KillMode", "s", "mixed",
747 "TTYVHangup", "b", true,
748 "TTYReset", "b", true,
749 "UtmpIdentifier", "s", utmp_id,
750 "UtmpMode", "s", "user",
751 "PAMName", "s", "login");
752 if (r < 0)
753 return r;
754
755 r = sd_bus_message_append(tm, "(sv)", "User", "s", isempty(user) ? "root" : user);
756 if (r < 0)
757 return r;
758
759 if (!strv_isempty(env)) {
760 r = sd_bus_message_open_container(tm, 'r', "sv");
761 if (r < 0)
762 return r;
763
764 r = sd_bus_message_append(tm, "s", "Environment");
765 if (r < 0)
766 return r;
767
768 r = sd_bus_message_open_container(tm, 'v', "as");
769 if (r < 0)
770 return r;
771
772 r = sd_bus_message_append_strv(tm, env);
773 if (r < 0)
774 return r;
775
776 r = sd_bus_message_close_container(tm);
777 if (r < 0)
778 return r;
779
780 r = sd_bus_message_close_container(tm);
781 if (r < 0)
782 return r;
783 }
784
785 /* Exec container */
786 r = sd_bus_message_open_container(tm, 'r', "sv");
787 if (r < 0)
788 return r;
789
790 r = sd_bus_message_append(tm, "s", "ExecStart");
791 if (r < 0)
792 return r;
793
794 r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
795 if (r < 0)
796 return r;
797
798 r = sd_bus_message_open_container(tm, 'a', "(sasb)");
799 if (r < 0)
800 return r;
801
802 r = sd_bus_message_open_container(tm, 'r', "sasb");
803 if (r < 0)
804 return r;
805
806 r = sd_bus_message_append(tm, "s", path);
807 if (r < 0)
808 return r;
809
810 r = sd_bus_message_append_strv(tm, args);
811 if (r < 0)
812 return r;
813
814 r = sd_bus_message_append(tm, "b", true);
815 if (r < 0)
816 return r;
817
818 r = sd_bus_message_close_container(tm);
819 if (r < 0)
820 return r;
821
822 r = sd_bus_message_close_container(tm);
823 if (r < 0)
824 return r;
825
826 r = sd_bus_message_close_container(tm);
827 if (r < 0)
828 return r;
829
830 r = sd_bus_message_close_container(tm);
831 if (r < 0)
832 return r;
833
834 r = sd_bus_message_close_container(tm);
835 if (r < 0)
836 return r;
837
838 /* Auxiliary units */
839 r = sd_bus_message_append(tm, "a(sa(sv))", 0);
840 if (r < 0)
841 return r;
842
843 r = sd_bus_call(container_bus, tm, 0, error, NULL);
844 if (r < 0)
845 return r;
846
847 r = sd_bus_message_new_method_return(message, &reply);
848 if (r < 0)
849 return r;
850
851 r = sd_bus_message_append(reply, "hs", master, pty_name);
852 if (r < 0)
853 return r;
854
855 return sd_bus_send(NULL, reply, NULL);
856 }
857
858 int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
859 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
860 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
861 bool mount_slave_created = false, mount_slave_mounted = false,
862 mount_tmp_created = false, mount_tmp_mounted = false,
863 mount_outside_created = false, mount_outside_mounted = false;
864 const char *dest, *src;
865 Machine *m = userdata;
866 int read_only, make_directory;
867 pid_t child;
868 siginfo_t si;
869 int r;
870
871 assert(message);
872 assert(m);
873
874 if (m->class != MACHINE_CONTAINER)
875 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
876
877 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
878 if (r < 0)
879 return r;
880
881 if (!path_is_absolute(src) || !path_is_safe(src))
882 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
883
884 if (isempty(dest))
885 dest = src;
886 else if (!path_is_absolute(dest) || !path_is_safe(dest))
887 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
888
889 r = bus_verify_polkit_async(
890 message,
891 CAP_SYS_ADMIN,
892 "org.freedesktop.machine1.manage-machines",
893 NULL,
894 false,
895 UID_INVALID,
896 &m->manager->polkit_registry,
897 error);
898 if (r < 0)
899 return r;
900 if (r == 0)
901 return 1; /* Will call us back */
902
903 /* One day, when bind mounting /proc/self/fd/n works across
904 * namespace boundaries we should rework this logic to make
905 * use of it... */
906
907 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
908 if (laccess(p, F_OK) < 0)
909 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
910
911 /* Our goal is to install a new bind mount into the container,
912 possibly read-only. This is irritatingly complex
913 unfortunately, currently.
914
915 First, we start by creating a private playground in /tmp,
916 that we can mount MS_SLAVE. (Which is necessary, since
917 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
918 mounts.) */
919
920 if (!mkdtemp(mount_slave))
921 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
922
923 mount_slave_created = true;
924
925 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
926 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
927 goto finish;
928 }
929
930 mount_slave_mounted = true;
931
932 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
933 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
934 goto finish;
935 }
936
937 /* Second, we mount the source directory to a directory inside
938 of our MS_SLAVE playground. */
939 mount_tmp = strjoina(mount_slave, "/mount");
940 if (mkdir(mount_tmp, 0700) < 0) {
941 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
942 goto finish;
943 }
944
945 mount_tmp_created = true;
946
947 if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
948 r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
949 goto finish;
950 }
951
952 mount_tmp_mounted = true;
953
954 /* Third, we remount the new bind mount read-only if requested. */
955 if (read_only)
956 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
957 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
958 goto finish;
959 }
960
961 /* Fourth, we move the new bind mount into the propagation
962 * directory. This way it will appear there read-only
963 * right-away. */
964
965 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
966 if (!mkdtemp(mount_outside)) {
967 r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
968 goto finish;
969 }
970
971 mount_outside_created = true;
972
973 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
974 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
975 goto finish;
976 }
977
978 mount_outside_mounted = true;
979 mount_tmp_mounted = false;
980
981 (void) rmdir(mount_tmp);
982 mount_tmp_created = false;
983
984 (void) umount(mount_slave);
985 mount_slave_mounted = false;
986
987 (void) rmdir(mount_slave);
988 mount_slave_created = false;
989
990 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
991 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
992 goto finish;
993 }
994
995 child = fork();
996 if (child < 0) {
997 r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
998 goto finish;
999 }
1000
1001 if (child == 0) {
1002 const char *mount_inside;
1003 int mntfd;
1004 const char *q;
1005
1006 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1007
1008 q = procfs_file_alloca(m->leader, "ns/mnt");
1009 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1010 if (mntfd < 0) {
1011 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1012 goto child_fail;
1013 }
1014
1015 if (setns(mntfd, CLONE_NEWNS) < 0) {
1016 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1017 goto child_fail;
1018 }
1019
1020 if (make_directory)
1021 (void) mkdir_p(dest, 0755);
1022
1023 /* Fifth, move the mount to the right place inside */
1024 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
1025 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
1026 r = log_error_errno(errno, "Failed to mount: %m");
1027 goto child_fail;
1028 }
1029
1030 _exit(EXIT_SUCCESS);
1031
1032 child_fail:
1033 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1034 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1035
1036 _exit(EXIT_FAILURE);
1037 }
1038
1039 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1040
1041 r = wait_for_terminate(child, &si);
1042 if (r < 0) {
1043 r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
1044 goto finish;
1045 }
1046 if (si.si_code != CLD_EXITED) {
1047 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
1048 goto finish;
1049 }
1050 if (si.si_status != EXIT_SUCCESS) {
1051
1052 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
1053 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
1054 else
1055 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed.");
1056 goto finish;
1057 }
1058
1059 r = sd_bus_reply_method_return(message, NULL);
1060
1061 finish:
1062 if (mount_outside_mounted)
1063 umount(mount_outside);
1064 if (mount_outside_created)
1065 rmdir(mount_outside);
1066
1067 if (mount_tmp_mounted)
1068 umount(mount_tmp);
1069 if (mount_tmp_created)
1070 rmdir(mount_tmp);
1071
1072 if (mount_slave_mounted)
1073 umount(mount_slave);
1074 if (mount_slave_created)
1075 rmdir(mount_slave);
1076
1077 return r;
1078 }
1079
1080 static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
1081 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1082 MachineOperation *o = userdata;
1083 int r;
1084
1085 assert(o);
1086 assert(si);
1087
1088 o->pid = 0;
1089
1090 if (si->si_code != CLD_EXITED) {
1091 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
1092 goto fail;
1093 }
1094
1095 if (si->si_status != EXIT_SUCCESS) {
1096 if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
1097 r = sd_bus_error_set_errnof(&error, r, "%m");
1098 else
1099 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
1100
1101 goto fail;
1102 }
1103
1104 r = sd_bus_reply_method_return(o->message, NULL);
1105 if (r < 0)
1106 log_error_errno(r, "Failed to reply to message: %m");
1107
1108 machine_operation_unref(o);
1109 return 0;
1110
1111 fail:
1112 r = sd_bus_reply_method_error(o->message, &error);
1113 if (r < 0)
1114 log_error_errno(r, "Failed to reply to message: %m");
1115
1116 machine_operation_unref(o);
1117 return 0;
1118 }
1119
1120 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1121 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
1122 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
1123 _cleanup_close_ int hostfd = -1;
1124 Machine *m = userdata;
1125 MachineOperation *o;
1126 bool copy_from;
1127 pid_t child;
1128 char *t;
1129 int r;
1130
1131 assert(message);
1132 assert(m);
1133
1134 if (m->n_operations >= MACHINE_OPERATIONS_MAX)
1135 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
1136
1137 if (m->class != MACHINE_CONTAINER)
1138 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
1139
1140 r = sd_bus_message_read(message, "ss", &src, &dest);
1141 if (r < 0)
1142 return r;
1143
1144 if (!path_is_absolute(src))
1145 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
1146
1147 if (isempty(dest))
1148 dest = src;
1149 else if (!path_is_absolute(dest))
1150 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
1151
1152 r = bus_verify_polkit_async(
1153 message,
1154 CAP_SYS_ADMIN,
1155 "org.freedesktop.machine1.manage-machines",
1156 NULL,
1157 false,
1158 UID_INVALID,
1159 &m->manager->polkit_registry,
1160 error);
1161 if (r < 0)
1162 return r;
1163 if (r == 0)
1164 return 1; /* Will call us back */
1165
1166 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
1167
1168 if (copy_from) {
1169 container_path = src;
1170 host_path = dest;
1171 } else {
1172 host_path = src;
1173 container_path = dest;
1174 }
1175
1176 host_basename = basename(host_path);
1177 t = strdupa(host_path);
1178 host_dirname = dirname(t);
1179
1180 container_basename = basename(container_path);
1181 t = strdupa(container_path);
1182 container_dirname = dirname(t);
1183
1184 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1185 if (hostfd < 0)
1186 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
1187
1188 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
1189 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
1190
1191 child = fork();
1192 if (child < 0)
1193 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
1194
1195 if (child == 0) {
1196 int containerfd;
1197 const char *q;
1198 int mntfd;
1199
1200 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1201
1202 q = procfs_file_alloca(m->leader, "ns/mnt");
1203 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1204 if (mntfd < 0) {
1205 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1206 goto child_fail;
1207 }
1208
1209 if (setns(mntfd, CLONE_NEWNS) < 0) {
1210 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1211 goto child_fail;
1212 }
1213
1214 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1215 if (containerfd < 0) {
1216 r = log_error_errno(errno, "Failed top open destination directory: %m");
1217 goto child_fail;
1218 }
1219
1220 if (copy_from)
1221 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
1222 else
1223 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
1224
1225 hostfd = safe_close(hostfd);
1226 containerfd = safe_close(containerfd);
1227
1228 if (r < 0) {
1229 r = log_error_errno(r, "Failed to copy tree: %m");
1230 goto child_fail;
1231 }
1232
1233 _exit(EXIT_SUCCESS);
1234
1235 child_fail:
1236 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1237 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1238
1239 _exit(EXIT_FAILURE);
1240 }
1241
1242 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1243
1244 /* Copying might take a while, hence install a watch the
1245 * child, and return */
1246
1247 o = new0(MachineOperation, 1);
1248 if (!o)
1249 return log_oom();
1250
1251 o->pid = child;
1252 o->message = sd_bus_message_ref(message);
1253 o->errno_fd = errno_pipe_fd[0];
1254 errno_pipe_fd[0] = -1;
1255
1256 r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
1257 if (r < 0) {
1258 machine_operation_unref(o);
1259 return log_oom();
1260 }
1261
1262 LIST_PREPEND(operations, m->operations, o);
1263 m->n_operations++;
1264 o->machine = m;
1265
1266 return 1;
1267 }
1268
1269 const sd_bus_vtable machine_vtable[] = {
1270 SD_BUS_VTABLE_START(0),
1271 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
1272 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1273 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1274 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
1275 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
1276 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1277 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
1278 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
1279 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
1280 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1281 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
1282 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
1283 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
1284 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
1285 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
1286 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED),
1287 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
1288 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED),
1289 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
1290 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
1291 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
1292 SD_BUS_VTABLE_END
1293 };
1294
1295 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
1296 Manager *m = userdata;
1297 Machine *machine;
1298 int r;
1299
1300 assert(bus);
1301 assert(path);
1302 assert(interface);
1303 assert(found);
1304 assert(m);
1305
1306 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
1307 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1308 sd_bus_message *message;
1309 pid_t pid;
1310
1311 message = sd_bus_get_current_message(bus);
1312 if (!message)
1313 return 0;
1314
1315 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1316 if (r < 0)
1317 return r;
1318
1319 r = sd_bus_creds_get_pid(creds, &pid);
1320 if (r < 0)
1321 return r;
1322
1323 r = manager_get_machine_by_pid(m, pid, &machine);
1324 if (r <= 0)
1325 return 0;
1326 } else {
1327 _cleanup_free_ char *e = NULL;
1328 const char *p;
1329
1330 p = startswith(path, "/org/freedesktop/machine1/machine/");
1331 if (!p)
1332 return 0;
1333
1334 e = bus_label_unescape(p);
1335 if (!e)
1336 return -ENOMEM;
1337
1338 machine = hashmap_get(m->machines, e);
1339 if (!machine)
1340 return 0;
1341 }
1342
1343 *found = machine;
1344 return 1;
1345 }
1346
1347 char *machine_bus_path(Machine *m) {
1348 _cleanup_free_ char *e = NULL;
1349
1350 assert(m);
1351
1352 e = bus_label_escape(m->name);
1353 if (!e)
1354 return NULL;
1355
1356 return strappend("/org/freedesktop/machine1/machine/", e);
1357 }
1358
1359 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1360 _cleanup_strv_free_ char **l = NULL;
1361 Machine *machine = NULL;
1362 Manager *m = userdata;
1363 Iterator i;
1364 int r;
1365
1366 assert(bus);
1367 assert(path);
1368 assert(nodes);
1369
1370 HASHMAP_FOREACH(machine, m->machines, i) {
1371 char *p;
1372
1373 p = machine_bus_path(machine);
1374 if (!p)
1375 return -ENOMEM;
1376
1377 r = strv_consume(&l, p);
1378 if (r < 0)
1379 return r;
1380 }
1381
1382 *nodes = l;
1383 l = NULL;
1384
1385 return 1;
1386 }
1387
1388 int machine_send_signal(Machine *m, bool new_machine) {
1389 _cleanup_free_ char *p = NULL;
1390
1391 assert(m);
1392
1393 p = machine_bus_path(m);
1394 if (!p)
1395 return -ENOMEM;
1396
1397 return sd_bus_emit_signal(
1398 m->manager->bus,
1399 "/org/freedesktop/machine1",
1400 "org.freedesktop.machine1.Manager",
1401 new_machine ? "MachineNew" : "MachineRemoved",
1402 "so", m->name, p);
1403 }
1404
1405 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1406 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
1407 _cleanup_free_ char *p = NULL;
1408
1409 assert(m);
1410
1411 if (!m->create_message)
1412 return 0;
1413
1414 c = m->create_message;
1415 m->create_message = NULL;
1416
1417 if (error)
1418 return sd_bus_reply_method_error(c, error);
1419
1420 /* Update the machine state file before we notify the client
1421 * about the result. */
1422 machine_save(m);
1423
1424 p = machine_bus_path(m);
1425 if (!p)
1426 return -ENOMEM;
1427
1428 return sd_bus_reply_method_return(c, "o", p);
1429 }