LCOV - code coverage report
Current view: top level - machine - machine-dbus.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 600 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 18 0.0 %

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

Generated by: LCOV version 1.11