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