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