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