LCOV - code coverage report
Current view: top level - machine - machined-dbus.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 820 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 44 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 <unistd.h>
      25             : 
      26             : #include "sd-id128.h"
      27             : #include "strv.h"
      28             : #include "path-util.h"
      29             : #include "unit-name.h"
      30             : #include "bus-util.h"
      31             : #include "bus-common-errors.h"
      32             : #include "cgroup-util.h"
      33             : #include "btrfs-util.h"
      34             : #include "formats-util.h"
      35             : #include "process-util.h"
      36             : #include "machine-image.h"
      37             : #include "machine-pool.h"
      38             : #include "image-dbus.h"
      39             : #include "machined.h"
      40             : #include "machine-dbus.h"
      41             : 
      42           0 : static int property_get_pool_path(
      43             :                 sd_bus *bus,
      44             :                 const char *path,
      45             :                 const char *interface,
      46             :                 const char *property,
      47             :                 sd_bus_message *reply,
      48             :                 void *userdata,
      49             :                 sd_bus_error *error) {
      50             : 
      51           0 :         assert(bus);
      52           0 :         assert(reply);
      53             : 
      54           0 :         return sd_bus_message_append(reply, "s", "/var/lib/machines");
      55             : }
      56             : 
      57           0 : static int property_get_pool_usage(
      58             :                 sd_bus *bus,
      59             :                 const char *path,
      60             :                 const char *interface,
      61             :                 const char *property,
      62             :                 sd_bus_message *reply,
      63             :                 void *userdata,
      64             :                 sd_bus_error *error) {
      65             : 
      66           0 :         _cleanup_close_ int fd = -1;
      67           0 :         uint64_t usage = (uint64_t) -1;
      68             :         struct stat st;
      69             : 
      70           0 :         assert(bus);
      71           0 :         assert(reply);
      72             : 
      73             :         /* We try to read the quota info from /var/lib/machines, as
      74             :          * well as the usage of the loopback file
      75             :          * /var/lib/machines.raw, and pick the larger value. */
      76             : 
      77           0 :         fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
      78           0 :         if (fd >= 0) {
      79             :                 BtrfsQuotaInfo q;
      80             : 
      81           0 :                 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
      82           0 :                         usage = q.referenced;
      83             :         }
      84             : 
      85           0 :         if (stat("/var/lib/machines.raw", &st) >= 0) {
      86           0 :                 if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
      87           0 :                         usage = st.st_blocks * 512ULL;
      88             :         }
      89             : 
      90           0 :         return sd_bus_message_append(reply, "t", usage);
      91             : }
      92             : 
      93           0 : static int property_get_pool_limit(
      94             :                 sd_bus *bus,
      95             :                 const char *path,
      96             :                 const char *interface,
      97             :                 const char *property,
      98             :                 sd_bus_message *reply,
      99             :                 void *userdata,
     100             :                 sd_bus_error *error) {
     101             : 
     102           0 :         _cleanup_close_ int fd = -1;
     103           0 :         uint64_t size = (uint64_t) -1;
     104             :         struct stat st;
     105             : 
     106           0 :         assert(bus);
     107           0 :         assert(reply);
     108             : 
     109             :         /* We try to read the quota limit from /var/lib/machines, as
     110             :          * well as the size of the loopback file
     111             :          * /var/lib/machines.raw, and pick the smaller value. */
     112             : 
     113           0 :         fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
     114           0 :         if (fd >= 0) {
     115             :                 BtrfsQuotaInfo q;
     116             : 
     117           0 :                 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
     118           0 :                         size = q.referenced_max;
     119             :         }
     120             : 
     121           0 :         if (stat("/var/lib/machines.raw", &st) >= 0) {
     122           0 :                 if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
     123           0 :                         size = st.st_size;
     124             :         }
     125             : 
     126           0 :         return sd_bus_message_append(reply, "t", size);
     127             : }
     128             : 
     129           0 : static int method_get_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     130           0 :         _cleanup_free_ char *p = NULL;
     131           0 :         Manager *m = userdata;
     132             :         Machine *machine;
     133             :         const char *name;
     134             :         int r;
     135             : 
     136           0 :         assert(message);
     137           0 :         assert(m);
     138             : 
     139           0 :         r = sd_bus_message_read(message, "s", &name);
     140           0 :         if (r < 0)
     141           0 :                 return r;
     142             : 
     143           0 :         machine = hashmap_get(m->machines, name);
     144           0 :         if (!machine)
     145           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     146             : 
     147           0 :         p = machine_bus_path(machine);
     148           0 :         if (!p)
     149           0 :                 return -ENOMEM;
     150             : 
     151           0 :         return sd_bus_reply_method_return(message, "o", p);
     152             : }
     153             : 
     154           0 : static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     155           0 :         _cleanup_free_ char *p = NULL;
     156           0 :         Manager *m = userdata;
     157             :         const char *name;
     158             :         int r;
     159             : 
     160           0 :         assert(message);
     161           0 :         assert(m);
     162             : 
     163           0 :         r = sd_bus_message_read(message, "s", &name);
     164           0 :         if (r < 0)
     165           0 :                 return r;
     166             : 
     167           0 :         r = image_find(name, NULL);
     168           0 :         if (r == 0)
     169           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
     170           0 :         if (r < 0)
     171           0 :                 return r;
     172             : 
     173           0 :         p = image_bus_path(name);
     174           0 :         if (!p)
     175           0 :                 return -ENOMEM;
     176             : 
     177           0 :         return sd_bus_reply_method_return(message, "o", p);
     178             : }
     179             : 
     180           0 : static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     181           0 :         _cleanup_free_ char *p = NULL;
     182           0 :         Manager *m = userdata;
     183           0 :         Machine *machine = NULL;
     184             :         pid_t pid;
     185             :         int r;
     186             : 
     187           0 :         assert(message);
     188           0 :         assert(m);
     189             : 
     190             :         assert_cc(sizeof(pid_t) == sizeof(uint32_t));
     191             : 
     192           0 :         r = sd_bus_message_read(message, "u", &pid);
     193           0 :         if (r < 0)
     194           0 :                 return r;
     195             : 
     196           0 :         if (pid == 0) {
     197           0 :                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
     198             : 
     199           0 :                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
     200           0 :                 if (r < 0)
     201           0 :                         return r;
     202             : 
     203           0 :                 r = sd_bus_creds_get_pid(creds, &pid);
     204           0 :                 if (r < 0)
     205           0 :                         return r;
     206             :         }
     207             : 
     208           0 :         r = manager_get_machine_by_pid(m, pid, &machine);
     209           0 :         if (r < 0)
     210           0 :                 return r;
     211           0 :         if (!machine)
     212           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
     213             : 
     214           0 :         p = machine_bus_path(machine);
     215           0 :         if (!p)
     216           0 :                 return -ENOMEM;
     217             : 
     218           0 :         return sd_bus_reply_method_return(message, "o", p);
     219             : }
     220             : 
     221           0 : static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     222           0 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
     223           0 :         Manager *m = userdata;
     224             :         Machine *machine;
     225             :         Iterator i;
     226             :         int r;
     227             : 
     228           0 :         assert(message);
     229           0 :         assert(m);
     230             : 
     231           0 :         r = sd_bus_message_new_method_return(message, &reply);
     232           0 :         if (r < 0)
     233           0 :                 return sd_bus_error_set_errno(error, r);
     234             : 
     235           0 :         r = sd_bus_message_open_container(reply, 'a', "(ssso)");
     236           0 :         if (r < 0)
     237           0 :                 return sd_bus_error_set_errno(error, r);
     238             : 
     239           0 :         HASHMAP_FOREACH(machine, m->machines, i) {
     240           0 :                 _cleanup_free_ char *p = NULL;
     241             : 
     242           0 :                 p = machine_bus_path(machine);
     243           0 :                 if (!p)
     244           0 :                         return -ENOMEM;
     245             : 
     246           0 :                 r = sd_bus_message_append(reply, "(ssso)",
     247           0 :                                           machine->name,
     248           0 :                                           strempty(machine_class_to_string(machine->class)),
     249           0 :                                           machine->service,
     250             :                                           p);
     251           0 :                 if (r < 0)
     252           0 :                         return sd_bus_error_set_errno(error, r);
     253             :         }
     254             : 
     255           0 :         r = sd_bus_message_close_container(reply);
     256           0 :         if (r < 0)
     257           0 :                 return sd_bus_error_set_errno(error, r);
     258             : 
     259           0 :         return sd_bus_send(NULL, reply, NULL);
     260             : }
     261             : 
     262           0 : static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
     263             :         const char *name, *service, *class, *root_directory;
     264           0 :         const int32_t *netif = NULL;
     265             :         MachineClass c;
     266             :         uint32_t leader;
     267             :         sd_id128_t id;
     268             :         const void *v;
     269             :         Machine *m;
     270           0 :         size_t n, n_netif = 0;
     271             :         int r;
     272             : 
     273           0 :         assert(manager);
     274           0 :         assert(message);
     275           0 :         assert(_m);
     276             : 
     277           0 :         r = sd_bus_message_read(message, "s", &name);
     278           0 :         if (r < 0)
     279           0 :                 return r;
     280           0 :         if (!machine_name_is_valid(name))
     281           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
     282             : 
     283           0 :         r = sd_bus_message_read_array(message, 'y', &v, &n);
     284           0 :         if (r < 0)
     285           0 :                 return r;
     286           0 :         if (n == 0)
     287           0 :                 id = SD_ID128_NULL;
     288           0 :         else if (n == 16)
     289           0 :                 memcpy(&id, v, n);
     290             :         else
     291           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
     292             : 
     293           0 :         r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
     294           0 :         if (r < 0)
     295           0 :                 return r;
     296             : 
     297           0 :         if (read_network) {
     298             :                 size_t i;
     299             : 
     300           0 :                 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
     301           0 :                 if (r < 0)
     302           0 :                         return r;
     303             : 
     304           0 :                 n_netif /= sizeof(int32_t);
     305             : 
     306           0 :                 for (i = 0; i < n_netif; i++) {
     307           0 :                         if (netif[i] <= 0)
     308           0 :                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
     309             :                 }
     310             :         }
     311             : 
     312           0 :         if (isempty(class))
     313           0 :                 c = _MACHINE_CLASS_INVALID;
     314             :         else {
     315           0 :                 c = machine_class_from_string(class);
     316           0 :                 if (c < 0)
     317           0 :                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
     318             :         }
     319             : 
     320           0 :         if (leader == 1)
     321           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
     322             : 
     323           0 :         if (!isempty(root_directory) && !path_is_absolute(root_directory))
     324           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
     325             : 
     326           0 :         if (leader == 0) {
     327           0 :                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
     328             : 
     329           0 :                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
     330           0 :                 if (r < 0)
     331           0 :                         return r;
     332             : 
     333             :                 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
     334             : 
     335           0 :                 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
     336           0 :                 if (r < 0)
     337           0 :                         return r;
     338             :         }
     339             : 
     340           0 :         if (hashmap_get(manager->machines, name))
     341           0 :                 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
     342             : 
     343           0 :         r = manager_add_machine(manager, name, &m);
     344           0 :         if (r < 0)
     345           0 :                 return r;
     346             : 
     347           0 :         m->leader = leader;
     348           0 :         m->class = c;
     349           0 :         m->id = id;
     350             : 
     351           0 :         if (!isempty(service)) {
     352           0 :                 m->service = strdup(service);
     353           0 :                 if (!m->service) {
     354           0 :                         r = -ENOMEM;
     355           0 :                         goto fail;
     356             :                 }
     357             :         }
     358             : 
     359           0 :         if (!isempty(root_directory)) {
     360           0 :                 m->root_directory = strdup(root_directory);
     361           0 :                 if (!m->root_directory) {
     362           0 :                         r = -ENOMEM;
     363           0 :                         goto fail;
     364             :                 }
     365             :         }
     366             : 
     367           0 :         if (n_netif > 0) {
     368             :                 assert_cc(sizeof(int32_t) == sizeof(int));
     369           0 :                 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
     370           0 :                 if (!m->netif) {
     371           0 :                         r = -ENOMEM;
     372           0 :                         goto fail;
     373             :                 }
     374             : 
     375           0 :                 m->n_netif = n_netif;
     376             :         }
     377             : 
     378           0 :         *_m = m;
     379             : 
     380           0 :         return 1;
     381             : 
     382             : fail:
     383           0 :         machine_add_to_gc_queue(m);
     384           0 :         return r;
     385             : }
     386             : 
     387           0 : static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
     388           0 :         Manager *manager = userdata;
     389           0 :         Machine *m = NULL;
     390             :         int r;
     391             : 
     392           0 :         assert(message);
     393           0 :         assert(manager);
     394             : 
     395           0 :         r = method_create_or_register_machine(manager, message, read_network, &m, error);
     396           0 :         if (r < 0)
     397           0 :                 return r;
     398             : 
     399           0 :         r = sd_bus_message_enter_container(message, 'a', "(sv)");
     400           0 :         if (r < 0)
     401           0 :                 goto fail;
     402             : 
     403           0 :         r = machine_start(m, message, error);
     404           0 :         if (r < 0)
     405           0 :                 goto fail;
     406             : 
     407           0 :         m->create_message = sd_bus_message_ref(message);
     408           0 :         return 1;
     409             : 
     410             : fail:
     411           0 :         machine_add_to_gc_queue(m);
     412           0 :         return r;
     413             : }
     414             : 
     415           0 : static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     416           0 :         return method_create_machine_internal(message, true, userdata, error);
     417             : }
     418             : 
     419           0 : static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     420           0 :         return method_create_machine_internal(message, false, userdata, error);
     421             : }
     422             : 
     423           0 : static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
     424           0 :         Manager *manager = userdata;
     425           0 :         _cleanup_free_ char *p = NULL;
     426           0 :         Machine *m = NULL;
     427             :         int r;
     428             : 
     429           0 :         assert(message);
     430           0 :         assert(manager);
     431             : 
     432           0 :         r = method_create_or_register_machine(manager, message, read_network, &m, error);
     433           0 :         if (r < 0)
     434           0 :                 return r;
     435             : 
     436           0 :         r = cg_pid_get_unit(m->leader, &m->unit);
     437           0 :         if (r < 0) {
     438           0 :                 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
     439           0 :                 goto fail;
     440             :         }
     441             : 
     442           0 :         r = machine_start(m, NULL, error);
     443           0 :         if (r < 0)
     444           0 :                 goto fail;
     445             : 
     446           0 :         p = machine_bus_path(m);
     447           0 :         if (!p) {
     448           0 :                 r = -ENOMEM;
     449           0 :                 goto fail;
     450             :         }
     451             : 
     452           0 :         return sd_bus_reply_method_return(message, "o", p);
     453             : 
     454             : fail:
     455           0 :         machine_add_to_gc_queue(m);
     456           0 :         return r;
     457             : }
     458             : 
     459           0 : static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     460           0 :         return method_register_machine_internal(message, true, userdata, error);
     461             : }
     462             : 
     463           0 : static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     464           0 :         return method_register_machine_internal(message, false, userdata, error);
     465             : }
     466             : 
     467           0 : static int method_terminate_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     468           0 :         Manager *m = userdata;
     469             :         Machine *machine;
     470             :         const char *name;
     471             :         int r;
     472             : 
     473           0 :         assert(message);
     474           0 :         assert(m);
     475             : 
     476           0 :         r = sd_bus_message_read(message, "s", &name);
     477           0 :         if (r < 0)
     478           0 :                 return sd_bus_error_set_errno(error, r);
     479             : 
     480           0 :         machine = hashmap_get(m->machines, name);
     481           0 :         if (!machine)
     482           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     483             : 
     484           0 :         return bus_machine_method_terminate(message, machine, error);
     485             : }
     486             : 
     487           0 : static int method_kill_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     488           0 :         Manager *m = userdata;
     489             :         Machine *machine;
     490             :         const char *name;
     491             :         int r;
     492             : 
     493           0 :         assert(message);
     494           0 :         assert(m);
     495             : 
     496           0 :         r = sd_bus_message_read(message, "s", &name);
     497           0 :         if (r < 0)
     498           0 :                 return sd_bus_error_set_errno(error, r);
     499             : 
     500           0 :         machine = hashmap_get(m->machines, name);
     501           0 :         if (!machine)
     502           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     503             : 
     504           0 :         return bus_machine_method_kill(message, machine, error);
     505             : }
     506             : 
     507           0 : static int method_get_machine_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     508           0 :         Manager *m = userdata;
     509             :         Machine *machine;
     510             :         const char *name;
     511             :         int r;
     512             : 
     513           0 :         assert(message);
     514           0 :         assert(m);
     515             : 
     516           0 :         r = sd_bus_message_read(message, "s", &name);
     517           0 :         if (r < 0)
     518           0 :                 return sd_bus_error_set_errno(error, r);
     519             : 
     520           0 :         machine = hashmap_get(m->machines, name);
     521           0 :         if (!machine)
     522           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     523             : 
     524           0 :         return bus_machine_method_get_addresses(message, machine, error);
     525             : }
     526             : 
     527           0 : static int method_get_machine_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     528           0 :         Manager *m = userdata;
     529             :         Machine *machine;
     530             :         const char *name;
     531             :         int r;
     532             : 
     533           0 :         assert(message);
     534           0 :         assert(m);
     535             : 
     536           0 :         r = sd_bus_message_read(message, "s", &name);
     537           0 :         if (r < 0)
     538           0 :                 return sd_bus_error_set_errno(error, r);
     539             : 
     540           0 :         machine = hashmap_get(m->machines, name);
     541           0 :         if (!machine)
     542           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     543             : 
     544           0 :         return bus_machine_method_get_os_release(message, machine, error);
     545             : }
     546             : 
     547           0 : static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     548           0 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
     549           0 :         _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
     550           0 :         Manager *m = userdata;
     551             :         Image *image;
     552             :         Iterator i;
     553             :         int r;
     554             : 
     555           0 :         assert(message);
     556           0 :         assert(m);
     557             : 
     558           0 :         images = hashmap_new(&string_hash_ops);
     559           0 :         if (!images)
     560           0 :                 return -ENOMEM;
     561             : 
     562           0 :         r = image_discover(images);
     563           0 :         if (r < 0)
     564           0 :                 return r;
     565             : 
     566           0 :         r = sd_bus_message_new_method_return(message, &reply);
     567           0 :         if (r < 0)
     568           0 :                 return r;
     569             : 
     570           0 :         r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
     571           0 :         if (r < 0)
     572           0 :                 return r;
     573             : 
     574           0 :         HASHMAP_FOREACH(image, images, i) {
     575           0 :                 _cleanup_free_ char *p = NULL;
     576             : 
     577           0 :                 p = image_bus_path(image->name);
     578           0 :                 if (!p)
     579           0 :                         return -ENOMEM;
     580             : 
     581           0 :                 r = sd_bus_message_append(reply, "(ssbttto)",
     582           0 :                                           image->name,
     583           0 :                                           image_type_to_string(image->type),
     584           0 :                                           image->read_only,
     585           0 :                                           image->crtime,
     586           0 :                                           image->mtime,
     587           0 :                                           image->usage,
     588             :                                           p);
     589           0 :                 if (r < 0)
     590           0 :                         return r;
     591             :         }
     592             : 
     593           0 :         r = sd_bus_message_close_container(reply);
     594           0 :         if (r < 0)
     595           0 :                 return r;
     596             : 
     597           0 :         return sd_bus_send(NULL, reply, NULL);
     598             : }
     599             : 
     600           0 : static int method_open_machine_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     601           0 :         Manager *m = userdata;
     602             :         Machine *machine;
     603             :         const char *name;
     604             :         int r;
     605             : 
     606           0 :         assert(message);
     607           0 :         assert(m);
     608             : 
     609           0 :         r = sd_bus_message_read(message, "s", &name);
     610           0 :         if (r < 0)
     611           0 :                 return sd_bus_error_set_errno(error, r);
     612             : 
     613           0 :         machine = hashmap_get(m->machines, name);
     614           0 :         if (!machine)
     615           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     616             : 
     617           0 :         return bus_machine_method_open_pty(message, machine, error);
     618             : }
     619             : 
     620           0 : static int method_open_machine_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     621           0 :         Manager *m = userdata;
     622             :         Machine *machine;
     623             :         const char *name;
     624             :         int r;
     625             : 
     626           0 :         assert(message);
     627           0 :         assert(m);
     628             : 
     629           0 :         r = sd_bus_message_read(message, "s", &name);
     630           0 :         if (r < 0)
     631           0 :                 return r;
     632             : 
     633           0 :         machine = hashmap_get(m->machines, name);
     634           0 :         if (!machine)
     635           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     636             : 
     637           0 :         return bus_machine_method_open_login(message, machine, error);
     638             : }
     639             : 
     640           0 : static int method_bind_mount_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     641           0 :         Manager *m = userdata;
     642             :         Machine *machine;
     643             :         const char *name;
     644             :         int r;
     645             : 
     646           0 :         assert(message);
     647           0 :         assert(m);
     648             : 
     649           0 :         r = sd_bus_message_read(message, "s", &name);
     650           0 :         if (r < 0)
     651           0 :                 return r;
     652             : 
     653           0 :         machine = hashmap_get(m->machines, name);
     654           0 :         if (!machine)
     655           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     656             : 
     657           0 :         return bus_machine_method_bind_mount(message, machine, error);
     658             : }
     659             : 
     660           0 : static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     661           0 :         Manager *m = userdata;
     662             :         Machine *machine;
     663             :         const char *name;
     664             :         int r;
     665             : 
     666           0 :         assert(message);
     667           0 :         assert(m);
     668             : 
     669           0 :         r = sd_bus_message_read(message, "s", &name);
     670           0 :         if (r < 0)
     671           0 :                 return r;
     672             : 
     673           0 :         machine = hashmap_get(m->machines, name);
     674           0 :         if (!machine)
     675           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     676             : 
     677           0 :         return bus_machine_method_copy(message, machine, error);
     678             : }
     679             : 
     680           0 : static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     681           0 :         _cleanup_(image_unrefp) Image* i = NULL;
     682             :         const char *name;
     683             :         int r;
     684             : 
     685           0 :         assert(message);
     686             : 
     687           0 :         r = sd_bus_message_read(message, "s", &name);
     688           0 :         if (r < 0)
     689           0 :                 return r;
     690             : 
     691           0 :         if (!image_name_is_valid(name))
     692           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
     693             : 
     694           0 :         r = image_find(name, &i);
     695           0 :         if (r < 0)
     696           0 :                 return r;
     697           0 :         if (r == 0)
     698           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
     699             : 
     700           0 :         i->userdata = userdata;
     701           0 :         return bus_image_method_remove(message, i, error);
     702             : }
     703             : 
     704           0 : static int method_rename_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     705           0 :         _cleanup_(image_unrefp) Image* i = NULL;
     706             :         const char *old_name;
     707             :         int r;
     708             : 
     709           0 :         assert(message);
     710             : 
     711           0 :         r = sd_bus_message_read(message, "s", &old_name);
     712           0 :         if (r < 0)
     713           0 :                 return r;
     714             : 
     715           0 :         if (!image_name_is_valid(old_name))
     716           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
     717             : 
     718           0 :         r = image_find(old_name, &i);
     719           0 :         if (r < 0)
     720           0 :                 return r;
     721           0 :         if (r == 0)
     722           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
     723             : 
     724           0 :         i->userdata = userdata;
     725           0 :         return bus_image_method_rename(message, i, error);
     726             : }
     727             : 
     728           0 : static int method_clone_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     729           0 :         _cleanup_(image_unrefp) Image *i = NULL;
     730             :         const char *old_name;
     731             :         int r;
     732             : 
     733           0 :         assert(message);
     734             : 
     735           0 :         r = sd_bus_message_read(message, "s", &old_name);
     736           0 :         if (r < 0)
     737           0 :                 return r;
     738             : 
     739           0 :         if (!image_name_is_valid(old_name))
     740           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
     741             : 
     742           0 :         r = image_find(old_name, &i);
     743           0 :         if (r < 0)
     744           0 :                 return r;
     745           0 :         if (r == 0)
     746           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
     747             : 
     748           0 :         i->userdata = userdata;
     749           0 :         return bus_image_method_clone(message, i, error);
     750             : }
     751             : 
     752           0 : static int method_mark_image_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     753           0 :         _cleanup_(image_unrefp) Image *i = NULL;
     754             :         const char *name;
     755             :         int r;
     756             : 
     757           0 :         assert(message);
     758             : 
     759           0 :         r = sd_bus_message_read(message, "s", &name);
     760           0 :         if (r < 0)
     761           0 :                 return r;
     762             : 
     763           0 :         if (!image_name_is_valid(name))
     764           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
     765             : 
     766           0 :         r = image_find(name, &i);
     767           0 :         if (r < 0)
     768           0 :                 return r;
     769           0 :         if (r == 0)
     770           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
     771             : 
     772           0 :         i->userdata = userdata;
     773           0 :         return bus_image_method_mark_read_only(message, i, error);
     774             : }
     775             : 
     776           0 : static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     777           0 :         Manager *m = userdata;
     778             :         uint64_t limit;
     779             :         int r;
     780             : 
     781           0 :         assert(message);
     782             : 
     783           0 :         r = sd_bus_message_read(message, "t", &limit);
     784           0 :         if (r < 0)
     785           0 :                 return r;
     786             : 
     787           0 :         r = bus_verify_polkit_async(
     788             :                         message,
     789             :                         CAP_SYS_ADMIN,
     790             :                         "org.freedesktop.machine1.manage-machines",
     791             :                         false,
     792             :                         UID_INVALID,
     793             :                         &m->polkit_registry,
     794             :                         error);
     795           0 :         if (r < 0)
     796           0 :                 return r;
     797           0 :         if (r == 0)
     798           0 :                 return 1; /* Will call us back */
     799             : 
     800             :         /* Set up the machine directory if necessary */
     801           0 :         r = setup_machine_directory(limit, error);
     802           0 :         if (r < 0)
     803           0 :                 return r;
     804             : 
     805           0 :         r = btrfs_resize_loopback("/var/lib/machines", limit, false);
     806           0 :         if (r == -ENOTTY)
     807           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
     808           0 :         if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
     809           0 :                 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
     810             : 
     811           0 :         r = btrfs_quota_limit("/var/lib/machines", limit);
     812           0 :         if (r == -ENOTTY)
     813           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
     814           0 :         if (r < 0)
     815           0 :                 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
     816             : 
     817           0 :         return sd_bus_reply_method_return(message, NULL);
     818             : }
     819             : 
     820           0 : static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     821           0 :         _cleanup_(image_unrefp) Image *i = NULL;
     822             :         const char *name;
     823             :         int r;
     824             : 
     825           0 :         assert(message);
     826             : 
     827           0 :         r = sd_bus_message_read(message, "s", &name);
     828           0 :         if (r < 0)
     829           0 :                 return r;
     830             : 
     831           0 :         if (!image_name_is_valid(name))
     832           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
     833             : 
     834           0 :         r = image_find(name, &i);
     835           0 :         if (r < 0)
     836           0 :                 return r;
     837           0 :         if (r == 0)
     838           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
     839             : 
     840           0 :         i->userdata = userdata;
     841           0 :         return bus_image_method_set_limit(message, i, error);
     842             : }
     843             : 
     844           0 : static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     845           0 :         _cleanup_fclose_ FILE *f = NULL;
     846           0 :         Manager *m = userdata;
     847             :         const char *name, *p;
     848             :         Machine *machine;
     849             :         uint32_t uid;
     850             :         int r;
     851             : 
     852           0 :         r = sd_bus_message_read(message, "su", &name, &uid);
     853           0 :         if (r < 0)
     854           0 :                 return r;
     855             : 
     856           0 :         if (UID_IS_INVALID(uid))
     857           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
     858             : 
     859           0 :         machine = hashmap_get(m->machines, name);
     860           0 :         if (!machine)
     861           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     862             : 
     863           0 :         p = procfs_file_alloca(machine->leader, "uid_map");
     864           0 :         f = fopen(p, "re");
     865           0 :         if (!f)
     866           0 :                 return -errno;
     867             : 
     868             :         for (;;) {
     869             :                 uid_t uid_base, uid_shift, uid_range, converted;
     870             :                 int k;
     871             : 
     872           0 :                 errno = 0;
     873           0 :                 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
     874           0 :                 if (k < 0 && feof(f))
     875           0 :                         break;
     876           0 :                 if (k != 3) {
     877           0 :                         if (ferror(f) && errno != 0)
     878           0 :                                 return -errno;
     879             : 
     880           0 :                         return -EIO;
     881             :                 }
     882             : 
     883           0 :                 if (uid < uid_base || uid >= uid_base + uid_range)
     884           0 :                         continue;
     885             : 
     886           0 :                 converted = uid - uid_base + uid_shift;
     887           0 :                 if (UID_IS_INVALID(converted))
     888           0 :                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
     889             : 
     890           0 :                 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
     891           0 :         }
     892             : 
     893           0 :         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
     894             : }
     895             : 
     896           0 : static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
     897           0 :         Manager *m = userdata;
     898             :         Machine *machine;
     899             :         uid_t uid;
     900             :         Iterator i;
     901             :         int r;
     902             : 
     903           0 :         r = sd_bus_message_read(message, "u", &uid);
     904           0 :         if (r < 0)
     905           0 :                 return r;
     906           0 :         if (UID_IS_INVALID(uid))
     907           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
     908           0 :         if (uid < 0x10000)
     909           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
     910             : 
     911           0 :         HASHMAP_FOREACH(machine, m->machines, i) {
     912           0 :                 _cleanup_fclose_ FILE *f = NULL;
     913           0 :                 char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
     914             : 
     915           0 :                 xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
     916           0 :                 f = fopen(p, "re");
     917           0 :                 if (!f) {
     918           0 :                         log_warning_errno(errno, "Failed top open %s, ignoring,", p);
     919           0 :                         continue;
     920             :                 }
     921             : 
     922             :                 for (;;) {
     923           0 :                         _cleanup_free_ char *o = NULL;
     924             :                         uid_t uid_base, uid_shift, uid_range, converted;
     925             :                         int k;
     926             : 
     927           0 :                         errno = 0;
     928           0 :                         k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
     929           0 :                         if (k < 0 && feof(f))
     930           0 :                                 break;
     931           0 :                         if (k != 3) {
     932           0 :                                 if (ferror(f) && errno != 0)
     933           0 :                                         return -errno;
     934             : 
     935           0 :                                 return -EIO;
     936             :                         }
     937             : 
     938           0 :                         if (uid < uid_shift || uid >= uid_shift + uid_range)
     939           0 :                                 continue;
     940             : 
     941           0 :                         converted = (uid - uid_shift + uid_base);
     942           0 :                         if (UID_IS_INVALID(converted))
     943           0 :                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
     944             : 
     945           0 :                         o = machine_bus_path(machine);
     946           0 :                         if (!o)
     947           0 :                                 return -ENOMEM;
     948             : 
     949           0 :                         return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
     950           0 :                 }
     951             :         }
     952             : 
     953           0 :         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
     954             : }
     955             : 
     956           0 : static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
     957           0 :         _cleanup_fclose_ FILE *f = NULL;
     958           0 :         Manager *m = groupdata;
     959             :         const char *name, *p;
     960             :         Machine *machine;
     961             :         uint32_t gid;
     962             :         int r;
     963             : 
     964           0 :         r = sd_bus_message_read(message, "su", &name, &gid);
     965           0 :         if (r < 0)
     966           0 :                 return r;
     967             : 
     968           0 :         if (GID_IS_INVALID(gid))
     969           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
     970             : 
     971           0 :         machine = hashmap_get(m->machines, name);
     972           0 :         if (!machine)
     973           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
     974             : 
     975           0 :         p = procfs_file_alloca(machine->leader, "gid_map");
     976           0 :         f = fopen(p, "re");
     977           0 :         if (!f)
     978           0 :                 return -errno;
     979             : 
     980             :         for (;;) {
     981             :                 gid_t gid_base, gid_shift, gid_range, converted;
     982             :                 int k;
     983             : 
     984           0 :                 errno = 0;
     985           0 :                 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
     986           0 :                 if (k < 0 && feof(f))
     987           0 :                         break;
     988           0 :                 if (k != 3) {
     989           0 :                         if (ferror(f) && errno != 0)
     990           0 :                                 return -errno;
     991             : 
     992           0 :                         return -EIO;
     993             :                 }
     994             : 
     995           0 :                 if (gid < gid_base || gid >= gid_base + gid_range)
     996           0 :                         continue;
     997             : 
     998           0 :                 converted = gid - gid_base + gid_shift;
     999           0 :                 if (GID_IS_INVALID(converted))
    1000           0 :                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
    1001             : 
    1002           0 :                 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
    1003           0 :         }
    1004             : 
    1005           0 :         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
    1006             : }
    1007             : 
    1008           0 : static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
    1009           0 :         Manager *m = groupdata;
    1010             :         Machine *machine;
    1011             :         gid_t gid;
    1012             :         Iterator i;
    1013             :         int r;
    1014             : 
    1015           0 :         r = sd_bus_message_read(message, "u", &gid);
    1016           0 :         if (r < 0)
    1017           0 :                 return r;
    1018           0 :         if (GID_IS_INVALID(gid))
    1019           0 :                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
    1020           0 :         if (gid < 0x10000)
    1021           0 :                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
    1022             : 
    1023           0 :         HASHMAP_FOREACH(machine, m->machines, i) {
    1024           0 :                 _cleanup_fclose_ FILE *f = NULL;
    1025           0 :                 char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
    1026             : 
    1027           0 :                 xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
    1028           0 :                 f = fopen(p, "re");
    1029           0 :                 if (!f) {
    1030           0 :                         log_warning_errno(errno, "Failed top open %s, ignoring,", p);
    1031           0 :                         continue;
    1032             :                 }
    1033             : 
    1034             :                 for (;;) {
    1035           0 :                         _cleanup_free_ char *o = NULL;
    1036             :                         gid_t gid_base, gid_shift, gid_range, converted;
    1037             :                         int k;
    1038             : 
    1039           0 :                         errno = 0;
    1040           0 :                         k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
    1041           0 :                         if (k < 0 && feof(f))
    1042           0 :                                 break;
    1043           0 :                         if (k != 3) {
    1044           0 :                                 if (ferror(f) && errno != 0)
    1045           0 :                                         return -errno;
    1046             : 
    1047           0 :                                 return -EIO;
    1048             :                         }
    1049             : 
    1050           0 :                         if (gid < gid_shift || gid >= gid_shift + gid_range)
    1051           0 :                                 continue;
    1052             : 
    1053           0 :                         converted = (gid - gid_shift + gid_base);
    1054           0 :                         if (GID_IS_INVALID(converted))
    1055           0 :                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
    1056             : 
    1057           0 :                         o = machine_bus_path(machine);
    1058           0 :                         if (!o)
    1059           0 :                                 return -ENOMEM;
    1060             : 
    1061           0 :                         return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
    1062           0 :                 }
    1063             :         }
    1064             : 
    1065           0 :         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
    1066             : }
    1067             : 
    1068             : const sd_bus_vtable manager_vtable[] = {
    1069             :         SD_BUS_VTABLE_START(0),
    1070             :         SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
    1071             :         SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
    1072             :         SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
    1073             :         SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
    1074             :         SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
    1075             :         SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
    1076             :         SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
    1077             :         SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
    1078             :         SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
    1079             :         SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
    1080             :         SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
    1081             :         SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
    1082             :         SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
    1083             :         SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
    1084             :         SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
    1085             :         SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
    1086             :         SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
    1087             :         SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
    1088             :         SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
    1089             :         SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
    1090             :         SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
    1091             :         SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
    1092             :         SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
    1093             :         SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
    1094             :         SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
    1095             :         SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
    1096             :         SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
    1097             :         SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
    1098             :         SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
    1099             :         SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
    1100             :         SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
    1101             :         SD_BUS_SIGNAL("MachineNew", "so", 0),
    1102             :         SD_BUS_SIGNAL("MachineRemoved", "so", 0),
    1103             :         SD_BUS_VTABLE_END
    1104             : };
    1105             : 
    1106           0 : int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
    1107             :         const char *path, *result, *unit;
    1108           0 :         Manager *m = userdata;
    1109             :         Machine *machine;
    1110             :         uint32_t id;
    1111             :         int r;
    1112             : 
    1113           0 :         assert(message);
    1114           0 :         assert(m);
    1115             : 
    1116           0 :         r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
    1117           0 :         if (r < 0) {
    1118           0 :                 bus_log_parse_error(r);
    1119           0 :                 return r;
    1120             :         }
    1121             : 
    1122           0 :         machine = hashmap_get(m->machine_units, unit);
    1123           0 :         if (!machine)
    1124           0 :                 return 0;
    1125             : 
    1126           0 :         if (streq_ptr(path, machine->scope_job)) {
    1127           0 :                 free(machine->scope_job);
    1128           0 :                 machine->scope_job = NULL;
    1129             : 
    1130           0 :                 if (machine->started) {
    1131           0 :                         if (streq(result, "done"))
    1132           0 :                                 machine_send_create_reply(machine, NULL);
    1133             :                         else {
    1134           0 :                                 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
    1135             : 
    1136           0 :                                 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
    1137             : 
    1138           0 :                                 machine_send_create_reply(machine, &e);
    1139             :                         }
    1140             :                 } else
    1141           0 :                         machine_save(machine);
    1142             :         }
    1143             : 
    1144           0 :         machine_add_to_gc_queue(machine);
    1145           0 :         return 0;
    1146             : }
    1147             : 
    1148           0 : int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
    1149           0 :         _cleanup_free_ char *unit = NULL;
    1150             :         const char *path, *interface;
    1151           0 :         Manager *m = userdata;
    1152             :         Machine *machine;
    1153             :         int r;
    1154             : 
    1155           0 :         assert(message);
    1156           0 :         assert(m);
    1157             : 
    1158           0 :         path = sd_bus_message_get_path(message);
    1159           0 :         if (!path)
    1160           0 :                 return 0;
    1161             : 
    1162           0 :         r = unit_name_from_dbus_path(path, &unit);
    1163           0 :         if (r == -EINVAL) /* not for a unit */
    1164           0 :                 return 0;
    1165           0 :         if (r < 0){
    1166           0 :                 log_oom();
    1167           0 :                 return 0;
    1168             :         }
    1169             : 
    1170           0 :         machine = hashmap_get(m->machine_units, unit);
    1171           0 :         if (!machine)
    1172           0 :                 return 0;
    1173             : 
    1174           0 :         r = sd_bus_message_read(message, "s", &interface);
    1175           0 :         if (r < 0) {
    1176           0 :                 bus_log_parse_error(r);
    1177           0 :                 return 0;
    1178             :         }
    1179             : 
    1180           0 :         if (streq(interface, "org.freedesktop.systemd1.Unit")) {
    1181             :                 struct properties {
    1182             :                         char *active_state;
    1183             :                         char *sub_state;
    1184           0 :                 } properties = {};
    1185             : 
    1186           0 :                 const struct bus_properties_map map[] = {
    1187             :                         { "ActiveState", "s", NULL, offsetof(struct properties, active_state) },
    1188             :                         { "SubState",    "s", NULL, offsetof(struct properties, sub_state)    },
    1189             :                         {}
    1190             :                 };
    1191             : 
    1192           0 :                 r = bus_message_map_properties_changed(message, map, &properties);
    1193           0 :                 if (r < 0)
    1194           0 :                         bus_log_parse_error(r);
    1195           0 :                 else if (streq_ptr(properties.active_state, "inactive") ||
    1196           0 :                          streq_ptr(properties.active_state, "failed") ||
    1197           0 :                          streq_ptr(properties.sub_state, "auto-restart"))
    1198           0 :                         machine_release_unit(machine);
    1199             : 
    1200           0 :                 free(properties.active_state);
    1201           0 :                 free(properties.sub_state);
    1202             :         }
    1203             : 
    1204           0 :         machine_add_to_gc_queue(machine);
    1205           0 :         return 0;
    1206             : }
    1207             : 
    1208           0 : int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
    1209             :         const char *path, *unit;
    1210           0 :         Manager *m = userdata;
    1211             :         Machine *machine;
    1212             :         int r;
    1213             : 
    1214           0 :         assert(message);
    1215           0 :         assert(m);
    1216             : 
    1217           0 :         r = sd_bus_message_read(message, "so", &unit, &path);
    1218           0 :         if (r < 0) {
    1219           0 :                 bus_log_parse_error(r);
    1220           0 :                 return 0;
    1221             :         }
    1222             : 
    1223           0 :         machine = hashmap_get(m->machine_units, unit);
    1224           0 :         if (!machine)
    1225           0 :                 return 0;
    1226             : 
    1227           0 :         machine_release_unit(machine);
    1228           0 :         machine_add_to_gc_queue(machine);
    1229             : 
    1230           0 :         return 0;
    1231             : }
    1232             : 
    1233           0 : int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
    1234           0 :         Manager *m = userdata;
    1235             :         Machine *machine;
    1236             :         Iterator i;
    1237             :         int b, r;
    1238             : 
    1239           0 :         assert(message);
    1240           0 :         assert(m);
    1241             : 
    1242           0 :         r = sd_bus_message_read(message, "b", &b);
    1243           0 :         if (r < 0) {
    1244           0 :                 bus_log_parse_error(r);
    1245           0 :                 return r;
    1246             :         }
    1247           0 :         if (b)
    1248           0 :                 return 0;
    1249             : 
    1250             :         /* systemd finished reloading, let's recheck all our machines */
    1251           0 :         log_debug("System manager has been reloaded, rechecking machines...");
    1252             : 
    1253           0 :         HASHMAP_FOREACH(machine, m->machines, i)
    1254           0 :                 machine_add_to_gc_queue(machine);
    1255             : 
    1256           0 :         return 0;
    1257             : }
    1258             : 
    1259           0 : int manager_start_scope(
    1260             :                 Manager *manager,
    1261             :                 const char *scope,
    1262             :                 pid_t pid,
    1263             :                 const char *slice,
    1264             :                 const char *description,
    1265             :                 sd_bus_message *more_properties,
    1266             :                 sd_bus_error *error,
    1267             :                 char **job) {
    1268             : 
    1269           0 :         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
    1270             :         int r;
    1271             : 
    1272           0 :         assert(manager);
    1273           0 :         assert(scope);
    1274           0 :         assert(pid > 1);
    1275             : 
    1276           0 :         r = sd_bus_message_new_method_call(
    1277             :                         manager->bus,
    1278             :                         &m,
    1279             :                         "org.freedesktop.systemd1",
    1280             :                         "/org/freedesktop/systemd1",
    1281             :                         "org.freedesktop.systemd1.Manager",
    1282             :                         "StartTransientUnit");
    1283           0 :         if (r < 0)
    1284           0 :                 return r;
    1285             : 
    1286           0 :         r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
    1287           0 :         if (r < 0)
    1288           0 :                 return r;
    1289             : 
    1290           0 :         r = sd_bus_message_open_container(m, 'a', "(sv)");
    1291           0 :         if (r < 0)
    1292           0 :                 return r;
    1293             : 
    1294           0 :         if (!isempty(slice)) {
    1295           0 :                 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
    1296           0 :                 if (r < 0)
    1297           0 :                         return r;
    1298             :         }
    1299             : 
    1300           0 :         if (!isempty(description)) {
    1301           0 :                 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
    1302           0 :                 if (r < 0)
    1303           0 :                         return r;
    1304             :         }
    1305             : 
    1306           0 :         r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
    1307           0 :         if (r < 0)
    1308           0 :                 return r;
    1309             : 
    1310           0 :         r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
    1311           0 :         if (r < 0)
    1312           0 :                 return r;
    1313             : 
    1314           0 :         if (more_properties) {
    1315           0 :                 r = sd_bus_message_copy(m, more_properties, true);
    1316           0 :                 if (r < 0)
    1317           0 :                         return r;
    1318             :         }
    1319             : 
    1320           0 :         r = sd_bus_message_close_container(m);
    1321           0 :         if (r < 0)
    1322           0 :                 return r;
    1323             : 
    1324           0 :         r = sd_bus_message_append(m, "a(sa(sv))", 0);
    1325           0 :         if (r < 0)
    1326           0 :                 return r;
    1327             : 
    1328           0 :         r = sd_bus_call(manager->bus, m, 0, error, &reply);
    1329           0 :         if (r < 0)
    1330           0 :                 return r;
    1331             : 
    1332           0 :         if (job) {
    1333             :                 const char *j;
    1334             :                 char *copy;
    1335             : 
    1336           0 :                 r = sd_bus_message_read(reply, "o", &j);
    1337           0 :                 if (r < 0)
    1338           0 :                         return r;
    1339             : 
    1340           0 :                 copy = strdup(j);
    1341           0 :                 if (!copy)
    1342           0 :                         return -ENOMEM;
    1343             : 
    1344           0 :                 *job = copy;
    1345             :         }
    1346             : 
    1347           0 :         return 1;
    1348             : }
    1349             : 
    1350           0 : int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
    1351           0 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
    1352             :         int r;
    1353             : 
    1354           0 :         assert(manager);
    1355           0 :         assert(unit);
    1356             : 
    1357           0 :         r = sd_bus_call_method(
    1358             :                         manager->bus,
    1359             :                         "org.freedesktop.systemd1",
    1360             :                         "/org/freedesktop/systemd1",
    1361             :                         "org.freedesktop.systemd1.Manager",
    1362             :                         "StopUnit",
    1363             :                         error,
    1364             :                         &reply,
    1365             :                         "ss", unit, "fail");
    1366           0 :         if (r < 0) {
    1367           0 :                 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
    1368           0 :                     sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
    1369             : 
    1370           0 :                         if (job)
    1371           0 :                                 *job = NULL;
    1372             : 
    1373           0 :                         sd_bus_error_free(error);
    1374           0 :                         return 0;
    1375             :                 }
    1376             : 
    1377           0 :                 return r;
    1378             :         }
    1379             : 
    1380           0 :         if (job) {
    1381             :                 const char *j;
    1382             :                 char *copy;
    1383             : 
    1384           0 :                 r = sd_bus_message_read(reply, "o", &j);
    1385           0 :                 if (r < 0)
    1386           0 :                         return r;
    1387             : 
    1388           0 :                 copy = strdup(j);
    1389           0 :                 if (!copy)
    1390           0 :                         return -ENOMEM;
    1391             : 
    1392           0 :                 *job = copy;
    1393             :         }
    1394             : 
    1395           0 :         return 1;
    1396             : }
    1397             : 
    1398           0 : int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
    1399           0 :         assert(manager);
    1400           0 :         assert(unit);
    1401             : 
    1402           0 :         return sd_bus_call_method(
    1403             :                         manager->bus,
    1404             :                         "org.freedesktop.systemd1",
    1405             :                         "/org/freedesktop/systemd1",
    1406             :                         "org.freedesktop.systemd1.Manager",
    1407             :                         "KillUnit",
    1408             :                         error,
    1409             :                         NULL,
    1410             :                         "ssi", unit, "all", signo);
    1411             : }
    1412             : 
    1413           0 : int manager_unit_is_active(Manager *manager, const char *unit) {
    1414           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    1415           0 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
    1416           0 :         _cleanup_free_ char *path = NULL;
    1417             :         const char *state;
    1418             :         int r;
    1419             : 
    1420           0 :         assert(manager);
    1421           0 :         assert(unit);
    1422             : 
    1423           0 :         path = unit_dbus_path_from_name(unit);
    1424           0 :         if (!path)
    1425           0 :                 return -ENOMEM;
    1426             : 
    1427           0 :         r = sd_bus_get_property(
    1428             :                         manager->bus,
    1429             :                         "org.freedesktop.systemd1",
    1430             :                         path,
    1431             :                         "org.freedesktop.systemd1.Unit",
    1432             :                         "ActiveState",
    1433             :                         &error,
    1434             :                         &reply,
    1435             :                         "s");
    1436           0 :         if (r < 0) {
    1437           0 :                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
    1438           0 :                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
    1439           0 :                         return true;
    1440             : 
    1441           0 :                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
    1442           0 :                     sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
    1443           0 :                         return false;
    1444             : 
    1445           0 :                 return r;
    1446             :         }
    1447             : 
    1448           0 :         r = sd_bus_message_read(reply, "s", &state);
    1449           0 :         if (r < 0)
    1450           0 :                 return -EINVAL;
    1451             : 
    1452           0 :         return !STR_IN_SET(state, "inactive", "failed");
    1453             : }
    1454             : 
    1455           0 : int manager_job_is_active(Manager *manager, const char *path) {
    1456           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    1457           0 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
    1458             :         int r;
    1459             : 
    1460           0 :         assert(manager);
    1461           0 :         assert(path);
    1462             : 
    1463           0 :         r = sd_bus_get_property(
    1464             :                         manager->bus,
    1465             :                         "org.freedesktop.systemd1",
    1466             :                         path,
    1467             :                         "org.freedesktop.systemd1.Job",
    1468             :                         "State",
    1469             :                         &error,
    1470             :                         &reply,
    1471             :                         "s");
    1472           0 :         if (r < 0) {
    1473           0 :                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
    1474           0 :                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
    1475           0 :                         return true;
    1476             : 
    1477           0 :                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
    1478           0 :                         return false;
    1479             : 
    1480           0 :                 return r;
    1481             :         }
    1482             : 
    1483             :         /* We don't actually care about the state really. The fact
    1484             :          * that we could read the job state is enough for us */
    1485             : 
    1486           0 :         return true;
    1487             : }
    1488             : 
    1489           0 : int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
    1490           0 :         _cleanup_free_ char *unit = NULL;
    1491             :         Machine *mm;
    1492             :         int r;
    1493             : 
    1494           0 :         assert(m);
    1495           0 :         assert(pid >= 1);
    1496           0 :         assert(machine);
    1497             : 
    1498           0 :         r = cg_pid_get_unit(pid, &unit);
    1499           0 :         if (r < 0)
    1500           0 :                 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
    1501             :         else
    1502           0 :                 mm = hashmap_get(m->machine_units, unit);
    1503             : 
    1504           0 :         if (!mm)
    1505           0 :                 return 0;
    1506             : 
    1507           0 :         *machine = mm;
    1508           0 :         return 1;
    1509             : }
    1510             : 
    1511           0 : int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
    1512             :         Machine *machine;
    1513             : 
    1514           0 :         assert(m);
    1515           0 :         assert(name);
    1516             : 
    1517           0 :         machine = hashmap_get(m->machines, name);
    1518           0 :         if (!machine) {
    1519           0 :                 machine = machine_new(m, name);
    1520           0 :                 if (!machine)
    1521           0 :                         return -ENOMEM;
    1522             :         }
    1523             : 
    1524           0 :         if (_machine)
    1525           0 :                 *_machine = machine;
    1526             : 
    1527           0 :         return 0;
    1528             : }

Generated by: LCOV version 1.11