LCOV - code coverage report
Current view: top level - machine - machined.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 189 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 13 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 166 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : #include <string.h>
       5                 :            : #include <sys/stat.h>
       6                 :            : #include <sys/types.h>
       7                 :            : #include <unistd.h>
       8                 :            : 
       9                 :            : #include "sd-daemon.h"
      10                 :            : 
      11                 :            : #include "alloc-util.h"
      12                 :            : #include "bus-error.h"
      13                 :            : #include "bus-util.h"
      14                 :            : #include "cgroup-util.h"
      15                 :            : #include "dirent-util.h"
      16                 :            : #include "fd-util.h"
      17                 :            : #include "format-util.h"
      18                 :            : #include "hostname-util.h"
      19                 :            : #include "label.h"
      20                 :            : #include "machine-image.h"
      21                 :            : #include "machined.h"
      22                 :            : #include "main-func.h"
      23                 :            : #include "process-util.h"
      24                 :            : #include "signal-util.h"
      25                 :            : #include "special.h"
      26                 :            : 
      27                 :            : static Manager* manager_unref(Manager *m);
      28         [ #  # ]:          0 : DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
      29                 :            : 
      30                 :          0 : DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(machine_hash_ops, char, string_hash_func, string_compare_func, Machine, machine_free);
      31                 :            : 
      32                 :          0 : static int manager_new(Manager **ret) {
      33                 :          0 :         _cleanup_(manager_unrefp) Manager *m = NULL;
      34                 :            :         int r;
      35                 :            : 
      36         [ #  # ]:          0 :         assert(ret);
      37                 :            : 
      38                 :          0 :         m = new0(Manager, 1);
      39         [ #  # ]:          0 :         if (!m)
      40                 :          0 :                 return -ENOMEM;
      41                 :            : 
      42                 :          0 :         m->machines = hashmap_new(&machine_hash_ops);
      43                 :          0 :         m->machine_units = hashmap_new(&string_hash_ops);
      44                 :          0 :         m->machine_leaders = hashmap_new(NULL);
      45                 :            : 
      46   [ #  #  #  #  :          0 :         if (!m->machines || !m->machine_units || !m->machine_leaders)
                   #  # ]
      47                 :          0 :                 return -ENOMEM;
      48                 :            : 
      49                 :          0 :         r = sd_event_default(&m->event);
      50         [ #  # ]:          0 :         if (r < 0)
      51                 :          0 :                 return r;
      52                 :            : 
      53                 :          0 :         r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
      54         [ #  # ]:          0 :         if (r < 0)
      55                 :          0 :                 return r;
      56                 :            : 
      57                 :          0 :         r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
      58         [ #  # ]:          0 :         if (r < 0)
      59                 :          0 :                 return r;
      60                 :            : 
      61                 :          0 :         (void) sd_event_set_watchdog(m->event, true);
      62                 :            : 
      63                 :          0 :         *ret = TAKE_PTR(m);
      64                 :          0 :         return 0;
      65                 :            : }
      66                 :            : 
      67                 :          0 : static Manager* manager_unref(Manager *m) {
      68         [ #  # ]:          0 :         if (!m)
      69                 :          0 :                 return NULL;
      70                 :            : 
      71         [ #  # ]:          0 :         while (m->operations)
      72                 :          0 :                 operation_free(m->operations);
      73                 :            : 
      74         [ #  # ]:          0 :         assert(m->n_operations == 0);
      75                 :            : 
      76                 :          0 :         hashmap_free(m->machines); /* This will free all machines, so that the machine_units/machine_leaders is empty */
      77                 :          0 :         hashmap_free(m->machine_units);
      78                 :          0 :         hashmap_free(m->machine_leaders);
      79                 :          0 :         hashmap_free(m->image_cache);
      80                 :            : 
      81                 :          0 :         sd_event_source_unref(m->image_cache_defer_event);
      82                 :          0 :         sd_event_source_unref(m->nscd_cache_flush_event);
      83                 :            : 
      84                 :          0 :         bus_verify_polkit_async_registry_free(m->polkit_registry);
      85                 :            : 
      86                 :          0 :         sd_bus_flush_close_unref(m->bus);
      87                 :          0 :         sd_event_unref(m->event);
      88                 :            : 
      89                 :          0 :         return mfree(m);
      90                 :            : }
      91                 :            : 
      92                 :          0 : static int manager_add_host_machine(Manager *m) {
      93                 :          0 :         _cleanup_free_ char *rd = NULL, *unit = NULL;
      94                 :            :         sd_id128_t mid;
      95                 :            :         Machine *t;
      96                 :            :         int r;
      97                 :            : 
      98         [ #  # ]:          0 :         if (m->host_machine)
      99                 :          0 :                 return 0;
     100                 :            : 
     101                 :          0 :         r = sd_id128_get_machine(&mid);
     102         [ #  # ]:          0 :         if (r < 0)
     103         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get machine ID: %m");
     104                 :            : 
     105                 :          0 :         rd = strdup("/");
     106         [ #  # ]:          0 :         if (!rd)
     107                 :          0 :                 return log_oom();
     108                 :            : 
     109                 :          0 :         unit = strdup(SPECIAL_ROOT_SLICE);
     110         [ #  # ]:          0 :         if (!unit)
     111                 :          0 :                 return log_oom();
     112                 :            : 
     113                 :          0 :         t = machine_new(m, MACHINE_HOST, ".host");
     114         [ #  # ]:          0 :         if (!t)
     115                 :          0 :                 return log_oom();
     116                 :            : 
     117                 :          0 :         t->leader = 1;
     118                 :          0 :         t->id = mid;
     119                 :            : 
     120                 :          0 :         t->root_directory = TAKE_PTR(rd);
     121                 :          0 :         t->unit = TAKE_PTR(unit);
     122                 :            : 
     123                 :          0 :         dual_timestamp_from_boottime_or_monotonic(&t->timestamp, 0);
     124                 :            : 
     125                 :          0 :         m->host_machine = t;
     126                 :            : 
     127                 :          0 :         return 0;
     128                 :            : }
     129                 :            : 
     130                 :          0 : static int manager_enumerate_machines(Manager *m) {
     131                 :          0 :         _cleanup_closedir_ DIR *d = NULL;
     132                 :            :         struct dirent *de;
     133                 :          0 :         int r = 0;
     134                 :            : 
     135         [ #  # ]:          0 :         assert(m);
     136                 :            : 
     137                 :          0 :         r = manager_add_host_machine(m);
     138         [ #  # ]:          0 :         if (r < 0)
     139                 :          0 :                 return r;
     140                 :            : 
     141                 :            :         /* Read in machine data stored on disk */
     142                 :          0 :         d = opendir("/run/systemd/machines");
     143         [ #  # ]:          0 :         if (!d) {
     144         [ #  # ]:          0 :                 if (errno == ENOENT)
     145                 :          0 :                         return 0;
     146                 :            : 
     147         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
     148                 :            :         }
     149                 :            : 
     150   [ #  #  #  #  :          0 :         FOREACH_DIRENT(de, d, return -errno) {
                   #  # ]
     151                 :            :                 struct Machine *machine;
     152                 :            :                 int k;
     153                 :            : 
     154         [ #  # ]:          0 :                 if (!dirent_is_file(de))
     155                 :          0 :                         continue;
     156                 :            : 
     157                 :            :                 /* Ignore symlinks that map the unit name to the machine */
     158         [ #  # ]:          0 :                 if (startswith(de->d_name, "unit:"))
     159                 :          0 :                         continue;
     160                 :            : 
     161         [ #  # ]:          0 :                 if (!machine_name_is_valid(de->d_name))
     162                 :          0 :                         continue;
     163                 :            : 
     164                 :          0 :                 k = manager_add_machine(m, de->d_name, &machine);
     165         [ #  # ]:          0 :                 if (k < 0) {
     166         [ #  # ]:          0 :                         r = log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
     167                 :          0 :                         continue;
     168                 :            :                 }
     169                 :            : 
     170                 :          0 :                 machine_add_to_gc_queue(machine);
     171                 :            : 
     172                 :          0 :                 k = machine_load(machine);
     173         [ #  # ]:          0 :                 if (k < 0)
     174                 :          0 :                         r = k;
     175                 :            :         }
     176                 :            : 
     177                 :          0 :         return r;
     178                 :            : }
     179                 :            : 
     180                 :          0 : static int manager_connect_bus(Manager *m) {
     181                 :            :         int r;
     182                 :            : 
     183         [ #  # ]:          0 :         assert(m);
     184         [ #  # ]:          0 :         assert(!m->bus);
     185                 :            : 
     186                 :          0 :         r = sd_bus_default_system(&m->bus);
     187         [ #  # ]:          0 :         if (r < 0)
     188         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to connect to system bus: %m");
     189                 :            : 
     190                 :          0 :         r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
     191         [ #  # ]:          0 :         if (r < 0)
     192         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add manager object vtable: %m");
     193                 :            : 
     194                 :          0 :         r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
     195         [ #  # ]:          0 :         if (r < 0)
     196         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add machine object vtable: %m");
     197                 :            : 
     198                 :          0 :         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
     199         [ #  # ]:          0 :         if (r < 0)
     200         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add machine enumerator: %m");
     201                 :            : 
     202                 :          0 :         r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m);
     203         [ #  # ]:          0 :         if (r < 0)
     204         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add image object vtable: %m");
     205                 :            : 
     206                 :          0 :         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m);
     207         [ #  # ]:          0 :         if (r < 0)
     208         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add image enumerator: %m");
     209                 :            : 
     210                 :          0 :         r = sd_bus_match_signal_async(
     211                 :            :                         m->bus,
     212                 :            :                         NULL,
     213                 :            :                         "org.freedesktop.systemd1",
     214                 :            :                         "/org/freedesktop/systemd1",
     215                 :            :                         "org.freedesktop.systemd1.Manager",
     216                 :            :                         "JobRemoved",
     217                 :            :                         match_job_removed, NULL, m);
     218         [ #  # ]:          0 :         if (r < 0)
     219         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
     220                 :            : 
     221                 :          0 :         r = sd_bus_match_signal_async(
     222                 :            :                         m->bus,
     223                 :            :                         NULL,
     224                 :            :                         "org.freedesktop.systemd1",
     225                 :            :                         "/org/freedesktop/systemd1",
     226                 :            :                         "org.freedesktop.systemd1.Manager",
     227                 :            :                         "UnitRemoved",
     228                 :            :                         match_unit_removed, NULL, m);
     229         [ #  # ]:          0 :         if (r < 0)
     230         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to request match for UnitRemoved: %m");
     231                 :            : 
     232                 :          0 :         r = sd_bus_match_signal_async(
     233                 :            :                         m->bus,
     234                 :            :                         NULL,
     235                 :            :                         "org.freedesktop.systemd1",
     236                 :            :                         NULL,
     237                 :            :                         "org.freedesktop.DBus.Properties",
     238                 :            :                         "PropertiesChanged",
     239                 :            :                         match_properties_changed, NULL, m);
     240         [ #  # ]:          0 :         if (r < 0)
     241         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to request match for PropertiesChanged: %m");
     242                 :            : 
     243                 :          0 :         r = sd_bus_match_signal_async(
     244                 :            :                         m->bus,
     245                 :            :                         NULL,
     246                 :            :                         "org.freedesktop.systemd1",
     247                 :            :                         "/org/freedesktop/systemd1",
     248                 :            :                         "org.freedesktop.systemd1.Manager",
     249                 :            :                         "Reloading",
     250                 :            :                         match_reloading, NULL, m);
     251         [ #  # ]:          0 :         if (r < 0)
     252         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to request match for Reloading: %m");
     253                 :            : 
     254                 :          0 :         r = sd_bus_call_method_async(
     255                 :            :                         m->bus,
     256                 :            :                         NULL,
     257                 :            :                         "org.freedesktop.systemd1",
     258                 :            :                         "/org/freedesktop/systemd1",
     259                 :            :                         "org.freedesktop.systemd1.Manager",
     260                 :            :                         "Subscribe",
     261                 :            :                         NULL, NULL,
     262                 :            :                         NULL);
     263         [ #  # ]:          0 :         if (r < 0)
     264         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to enable subscription: %m");
     265                 :            : 
     266                 :          0 :         r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.machine1", 0, NULL, NULL);
     267         [ #  # ]:          0 :         if (r < 0)
     268         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to request name: %m");
     269                 :            : 
     270                 :          0 :         r = sd_bus_attach_event(m->bus, m->event, 0);
     271         [ #  # ]:          0 :         if (r < 0)
     272         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
     273                 :            : 
     274                 :          0 :         return 0;
     275                 :            : }
     276                 :            : 
     277                 :          0 : static void manager_gc(Manager *m, bool drop_not_started) {
     278                 :            :         Machine *machine;
     279                 :            : 
     280         [ #  # ]:          0 :         assert(m);
     281                 :            : 
     282         [ #  # ]:          0 :         while ((machine = m->machine_gc_queue)) {
     283   [ #  #  #  #  :          0 :                 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
             #  #  #  # ]
     284                 :          0 :                 machine->in_gc_queue = false;
     285                 :            : 
     286                 :            :                 /* First, if we are not closing yet, initiate stopping */
     287   [ #  #  #  # ]:          0 :                 if (machine_may_gc(machine, drop_not_started) &&
     288                 :          0 :                     machine_get_state(machine) != MACHINE_CLOSING)
     289                 :          0 :                         machine_stop(machine);
     290                 :            : 
     291                 :            :                 /* Now, the stop probably made this referenced
     292                 :            :                  * again, but if it didn't, then it's time to let it
     293                 :            :                  * go entirely. */
     294         [ #  # ]:          0 :                 if (machine_may_gc(machine, drop_not_started)) {
     295                 :          0 :                         machine_finalize(machine);
     296                 :          0 :                         machine_free(machine);
     297                 :            :                 }
     298                 :            :         }
     299                 :          0 : }
     300                 :            : 
     301                 :          0 : static int manager_startup(Manager *m) {
     302                 :            :         Machine *machine;
     303                 :            :         Iterator i;
     304                 :            :         int r;
     305                 :            : 
     306         [ #  # ]:          0 :         assert(m);
     307                 :            : 
     308                 :            :         /* Connect to the bus */
     309                 :          0 :         r = manager_connect_bus(m);
     310         [ #  # ]:          0 :         if (r < 0)
     311                 :          0 :                 return r;
     312                 :            : 
     313                 :            :         /* Deserialize state */
     314                 :          0 :         manager_enumerate_machines(m);
     315                 :            : 
     316                 :            :         /* Remove stale objects before we start them */
     317                 :          0 :         manager_gc(m, false);
     318                 :            : 
     319                 :            :         /* And start everything */
     320         [ #  # ]:          0 :         HASHMAP_FOREACH(machine, m->machines, i)
     321                 :          0 :                 machine_start(machine, NULL, NULL);
     322                 :            : 
     323                 :          0 :         return 0;
     324                 :            : }
     325                 :            : 
     326                 :          0 : static bool check_idle(void *userdata) {
     327                 :          0 :         Manager *m = userdata;
     328                 :            : 
     329         [ #  # ]:          0 :         if (m->operations)
     330                 :          0 :                 return false;
     331                 :            : 
     332                 :          0 :         manager_gc(m, true);
     333                 :            : 
     334                 :          0 :         return hashmap_isempty(m->machines);
     335                 :            : }
     336                 :            : 
     337                 :          0 : static int manager_run(Manager *m) {
     338         [ #  # ]:          0 :         assert(m);
     339                 :            : 
     340                 :          0 :         return bus_event_loop_with_idle(
     341                 :            :                         m->event,
     342                 :            :                         m->bus,
     343                 :            :                         "org.freedesktop.machine1",
     344                 :            :                         DEFAULT_EXIT_USEC,
     345                 :            :                         check_idle, m);
     346                 :            : }
     347                 :            : 
     348                 :          0 : static int run(int argc, char *argv[]) {
     349                 :          0 :         _cleanup_(manager_unrefp) Manager *m = NULL;
     350                 :            :         int r;
     351                 :            : 
     352                 :          0 :         log_set_facility(LOG_AUTH);
     353                 :          0 :         log_setup_service();
     354                 :            : 
     355                 :          0 :         umask(0022);
     356                 :            : 
     357         [ #  # ]:          0 :         if (argc != 1) {
     358         [ #  # ]:          0 :                 log_error("This program takes no arguments.");
     359                 :          0 :                 return -EINVAL;
     360                 :            :         }
     361                 :            : 
     362                 :            :         /* Always create the directories people can create inotify watches in. Note that some applications might check
     363                 :            :          * for the existence of /run/systemd/machines/ to determine whether machined is available, so please always
     364                 :            :          * make sure this check stays in. */
     365                 :          0 :         (void) mkdir_label("/run/systemd/machines", 0755);
     366                 :            : 
     367         [ #  # ]:          0 :         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, -1) >= 0);
     368                 :            : 
     369                 :          0 :         r = manager_new(&m);
     370         [ #  # ]:          0 :         if (r < 0)
     371         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to allocate manager object: %m");
     372                 :            : 
     373                 :          0 :         r = manager_startup(m);
     374         [ #  # ]:          0 :         if (r < 0)
     375         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to fully start up daemon: %m");
     376                 :            : 
     377         [ #  # ]:          0 :         log_debug("systemd-machined running as pid "PID_FMT, getpid_cached());
     378                 :          0 :         (void) sd_notify(false,
     379                 :            :                          "READY=1\n"
     380                 :            :                          "STATUS=Processing requests...");
     381                 :            : 
     382                 :          0 :         r = manager_run(m);
     383                 :            : 
     384         [ #  # ]:          0 :         log_debug("systemd-machined stopped as pid "PID_FMT, getpid_cached());
     385                 :          0 :         (void) sd_notify(false,
     386                 :            :                          "STOPPING=1\n"
     387                 :            :                          "STATUS=Shutting down...");
     388                 :            : 
     389                 :          0 :         return r;
     390                 :            : }
     391                 :            : 
     392                 :          0 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14