LCOV - code coverage report
Current view: top level - machine - machine.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 3 277 1.1 %
Date: 2015-07-29 18:47:03 Functions: 6 21 28.6 %

          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 <string.h>
      23             : #include <unistd.h>
      24             : #include <errno.h>
      25             : 
      26             : #include "sd-messages.h"
      27             : 
      28             : #include "util.h"
      29             : #include "mkdir.h"
      30             : #include "hashmap.h"
      31             : #include "fileio.h"
      32             : #include "special.h"
      33             : #include "unit-name.h"
      34             : #include "bus-util.h"
      35             : #include "bus-error.h"
      36             : #include "machine.h"
      37             : #include "machine-dbus.h"
      38             : #include "formats-util.h"
      39             : 
      40           0 : Machine* machine_new(Manager *manager, const char *name) {
      41             :         Machine *m;
      42             : 
      43           0 :         assert(manager);
      44           0 :         assert(name);
      45             : 
      46           0 :         m = new0(Machine, 1);
      47           0 :         if (!m)
      48           0 :                 return NULL;
      49             : 
      50           0 :         m->name = strdup(name);
      51           0 :         if (!m->name)
      52           0 :                 goto fail;
      53             : 
      54           0 :         m->state_file = strappend("/run/systemd/machines/", m->name);
      55           0 :         if (!m->state_file)
      56           0 :                 goto fail;
      57             : 
      58           0 :         if (hashmap_put(manager->machines, m->name, m) < 0)
      59           0 :                 goto fail;
      60             : 
      61           0 :         m->class = _MACHINE_CLASS_INVALID;
      62           0 :         m->manager = manager;
      63             : 
      64           0 :         return m;
      65             : 
      66             : fail:
      67           0 :         free(m->state_file);
      68           0 :         free(m->name);
      69           0 :         free(m);
      70             : 
      71           0 :         return NULL;
      72             : }
      73             : 
      74           0 : void machine_free(Machine *m) {
      75           0 :         assert(m);
      76             : 
      77           0 :         while (m->operations)
      78           0 :                 machine_operation_unref(m->operations);
      79             : 
      80           0 :         if (m->in_gc_queue)
      81           0 :                 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
      82             : 
      83           0 :         machine_release_unit(m);
      84             : 
      85           0 :         free(m->scope_job);
      86             : 
      87           0 :         (void) hashmap_remove(m->manager->machines, m->name);
      88             : 
      89           0 :         if (m->leader > 0)
      90           0 :                 (void) hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
      91             : 
      92           0 :         sd_bus_message_unref(m->create_message);
      93             : 
      94           0 :         free(m->name);
      95           0 :         free(m->state_file);
      96           0 :         free(m->service);
      97           0 :         free(m->root_directory);
      98           0 :         free(m->netif);
      99           0 :         free(m);
     100           0 : }
     101             : 
     102           0 : int machine_save(Machine *m) {
     103           0 :         _cleanup_free_ char *temp_path = NULL;
     104           0 :         _cleanup_fclose_ FILE *f = NULL;
     105             :         int r;
     106             : 
     107           0 :         assert(m);
     108           0 :         assert(m->state_file);
     109             : 
     110           0 :         if (!m->started)
     111           0 :                 return 0;
     112             : 
     113           0 :         r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
     114           0 :         if (r < 0)
     115           0 :                 goto finish;
     116             : 
     117           0 :         r = fopen_temporary(m->state_file, &f, &temp_path);
     118           0 :         if (r < 0)
     119           0 :                 goto finish;
     120             : 
     121           0 :         fchmod(fileno(f), 0644);
     122             : 
     123           0 :         fprintf(f,
     124             :                 "# This is private data. Do not parse.\n"
     125             :                 "NAME=%s\n",
     126             :                 m->name);
     127             : 
     128           0 :         if (m->unit) {
     129           0 :                 _cleanup_free_ char *escaped;
     130             : 
     131           0 :                 escaped = cescape(m->unit);
     132           0 :                 if (!escaped) {
     133           0 :                         r = -ENOMEM;
     134           0 :                         goto finish;
     135             :                 }
     136             : 
     137           0 :                 fprintf(f, "SCOPE=%s\n", escaped); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
     138             :         }
     139             : 
     140           0 :         if (m->scope_job)
     141           0 :                 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
     142             : 
     143           0 :         if (m->service) {
     144           0 :                 _cleanup_free_ char *escaped;
     145             : 
     146           0 :                 escaped = cescape(m->service);
     147           0 :                 if (!escaped) {
     148           0 :                         r = -ENOMEM;
     149           0 :                         goto finish;
     150             :                 }
     151           0 :                 fprintf(f, "SERVICE=%s\n", escaped);
     152             :         }
     153             : 
     154           0 :         if (m->root_directory) {
     155           0 :                 _cleanup_free_ char *escaped;
     156             : 
     157           0 :                 escaped = cescape(m->root_directory);
     158           0 :                 if (!escaped) {
     159           0 :                         r = -ENOMEM;
     160           0 :                         goto finish;
     161             :                 }
     162           0 :                 fprintf(f, "ROOT=%s\n", escaped);
     163             :         }
     164             : 
     165           0 :         if (!sd_id128_equal(m->id, SD_ID128_NULL))
     166           0 :                 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
     167             : 
     168           0 :         if (m->leader != 0)
     169           0 :                 fprintf(f, "LEADER="PID_FMT"\n", m->leader);
     170             : 
     171           0 :         if (m->class != _MACHINE_CLASS_INVALID)
     172           0 :                 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
     173             : 
     174           0 :         if (dual_timestamp_is_set(&m->timestamp))
     175           0 :                 fprintf(f,
     176             :                         "REALTIME="USEC_FMT"\n"
     177             :                         "MONOTONIC="USEC_FMT"\n",
     178             :                         m->timestamp.realtime,
     179             :                         m->timestamp.monotonic);
     180             : 
     181           0 :         if (m->n_netif > 0) {
     182             :                 unsigned i;
     183             : 
     184           0 :                 fputs("NETIF=", f);
     185             : 
     186           0 :                 for (i = 0; i < m->n_netif; i++) {
     187           0 :                         if (i != 0)
     188           0 :                                 fputc(' ', f);
     189             : 
     190           0 :                         fprintf(f, "%i", m->netif[i]);
     191             :                 }
     192             : 
     193           0 :                 fputc('\n', f);
     194             :         }
     195             : 
     196           0 :         r = fflush_and_check(f);
     197           0 :         if (r < 0)
     198           0 :                 goto finish;
     199             : 
     200           0 :         if (rename(temp_path, m->state_file) < 0) {
     201           0 :                 r = -errno;
     202           0 :                 goto finish;
     203             :         }
     204             : 
     205           0 :         free(temp_path);
     206           0 :         temp_path = NULL;
     207             : 
     208           0 :         if (m->unit) {
     209             :                 char *sl;
     210             : 
     211             :                 /* Create a symlink from the unit name to the machine
     212             :                  * name, so that we can quickly find the machine for
     213             :                  * each given unit. Ignore error. */
     214           0 :                 sl = strjoina("/run/systemd/machines/unit:", m->unit);
     215           0 :                 (void) symlink(m->name, sl);
     216             :         }
     217             : 
     218             : finish:
     219           0 :         if (temp_path)
     220           0 :                 unlink(temp_path);
     221             : 
     222           0 :         if (r < 0)
     223           0 :                 log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
     224             : 
     225           0 :         return r;
     226             : }
     227             : 
     228           0 : static void machine_unlink(Machine *m) {
     229           0 :         assert(m);
     230             : 
     231           0 :         if (m->unit) {
     232             : 
     233             :                 char *sl;
     234             : 
     235           0 :                 sl = strjoina("/run/systemd/machines/unit:", m->unit);
     236           0 :                 unlink(sl);
     237             :         }
     238             : 
     239           0 :         if (m->state_file)
     240           0 :                 unlink(m->state_file);
     241           0 : }
     242             : 
     243           0 : int machine_load(Machine *m) {
     244           0 :         _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
     245             :         int r;
     246             : 
     247           0 :         assert(m);
     248             : 
     249           0 :         r = parse_env_file(m->state_file, NEWLINE,
     250             :                            "SCOPE",     &m->unit,
     251             :                            "SCOPE_JOB", &m->scope_job,
     252             :                            "SERVICE",   &m->service,
     253             :                            "ROOT",      &m->root_directory,
     254             :                            "ID",        &id,
     255             :                            "LEADER",    &leader,
     256             :                            "CLASS",     &class,
     257             :                            "REALTIME",  &realtime,
     258             :                            "MONOTONIC", &monotonic,
     259             :                            "NETIF",     &netif,
     260             :                            NULL);
     261           0 :         if (r < 0) {
     262           0 :                 if (r == -ENOENT)
     263           0 :                         return 0;
     264             : 
     265           0 :                 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
     266             :         }
     267             : 
     268           0 :         if (id)
     269           0 :                 sd_id128_from_string(id, &m->id);
     270             : 
     271           0 :         if (leader)
     272           0 :                 parse_pid(leader, &m->leader);
     273             : 
     274           0 :         if (class) {
     275             :                 MachineClass c;
     276             : 
     277           0 :                 c = machine_class_from_string(class);
     278           0 :                 if (c >= 0)
     279           0 :                         m->class = c;
     280             :         }
     281             : 
     282           0 :         if (realtime) {
     283             :                 unsigned long long l;
     284           0 :                 if (sscanf(realtime, "%llu", &l) > 0)
     285           0 :                         m->timestamp.realtime = l;
     286             :         }
     287             : 
     288           0 :         if (monotonic) {
     289             :                 unsigned long long l;
     290           0 :                 if (sscanf(monotonic, "%llu", &l) > 0)
     291           0 :                         m->timestamp.monotonic = l;
     292             :         }
     293             : 
     294           0 :         if (netif) {
     295           0 :                 size_t l, allocated = 0, nr = 0;
     296             :                 const char *word, *state;
     297           0 :                 int *ni = NULL;
     298             : 
     299           0 :                 FOREACH_WORD(word, l, netif, state) {
     300           0 :                         char buf[l+1];
     301             :                         int ifi;
     302             : 
     303           0 :                         *(char*) (mempcpy(buf, word, l)) = 0;
     304             : 
     305           0 :                         if (safe_atoi(buf, &ifi) < 0)
     306           0 :                                 continue;
     307           0 :                         if (ifi <= 0)
     308           0 :                                 continue;
     309             : 
     310           0 :                         if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
     311           0 :                                 free(ni);
     312           0 :                                 return log_oom();
     313             :                         }
     314             : 
     315           0 :                         ni[nr++] = ifi;
     316             :                 }
     317             : 
     318           0 :                 free(m->netif);
     319           0 :                 m->netif = ni;
     320           0 :                 m->n_netif = nr;
     321             :         }
     322             : 
     323           0 :         return r;
     324             : }
     325             : 
     326           0 : static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
     327           0 :         int r = 0;
     328             : 
     329           0 :         assert(m);
     330             : 
     331           0 :         if (!m->unit) {
     332           0 :                 _cleanup_free_ char *escaped = NULL;
     333           0 :                 char *scope, *description, *job = NULL;
     334             : 
     335           0 :                 escaped = unit_name_escape(m->name);
     336           0 :                 if (!escaped)
     337           0 :                         return log_oom();
     338             : 
     339           0 :                 scope = strjoin("machine-", escaped, ".scope", NULL);
     340           0 :                 if (!scope)
     341           0 :                         return log_oom();
     342             : 
     343           0 :                 description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
     344             : 
     345           0 :                 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
     346           0 :                 if (r < 0) {
     347           0 :                         log_error("Failed to start machine scope: %s", bus_error_message(error, r));
     348           0 :                         free(scope);
     349           0 :                         return r;
     350             :                 } else {
     351           0 :                         m->unit = scope;
     352             : 
     353           0 :                         free(m->scope_job);
     354           0 :                         m->scope_job = job;
     355             :                 }
     356             :         }
     357             : 
     358           0 :         if (m->unit)
     359           0 :                 hashmap_put(m->manager->machine_units, m->unit, m);
     360             : 
     361           0 :         return r;
     362             : }
     363             : 
     364           0 : int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
     365             :         int r;
     366             : 
     367           0 :         assert(m);
     368             : 
     369           0 :         if (m->started)
     370           0 :                 return 0;
     371             : 
     372           0 :         r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
     373           0 :         if (r < 0)
     374           0 :                 return r;
     375             : 
     376             :         /* Create cgroup */
     377           0 :         r = machine_start_scope(m, properties, error);
     378           0 :         if (r < 0)
     379           0 :                 return r;
     380             : 
     381           0 :         log_struct(LOG_INFO,
     382             :                    LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START),
     383             :                    "NAME=%s", m->name,
     384             :                    "LEADER="PID_FMT, m->leader,
     385             :                    LOG_MESSAGE("New machine %s.", m->name),
     386             :                    NULL);
     387             : 
     388           0 :         if (!dual_timestamp_is_set(&m->timestamp))
     389           0 :                 dual_timestamp_get(&m->timestamp);
     390             : 
     391           0 :         m->started = true;
     392             : 
     393             :         /* Save new machine data */
     394           0 :         machine_save(m);
     395             : 
     396           0 :         machine_send_signal(m, true);
     397             : 
     398           0 :         return 0;
     399             : }
     400             : 
     401           0 : static int machine_stop_scope(Machine *m) {
     402           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     403           0 :         char *job = NULL;
     404             :         int r;
     405             : 
     406           0 :         assert(m);
     407             : 
     408           0 :         if (!m->unit)
     409           0 :                 return 0;
     410             : 
     411           0 :         r = manager_stop_unit(m->manager, m->unit, &error, &job);
     412           0 :         if (r < 0) {
     413           0 :                 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
     414           0 :                 return r;
     415             :         }
     416             : 
     417           0 :         free(m->scope_job);
     418           0 :         m->scope_job = job;
     419             : 
     420           0 :         return 0;
     421             : }
     422             : 
     423           0 : int machine_stop(Machine *m) {
     424           0 :         int r = 0, k;
     425           0 :         assert(m);
     426             : 
     427           0 :         if (m->started)
     428           0 :                 log_struct(LOG_INFO,
     429             :                            LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
     430             :                            "NAME=%s", m->name,
     431             :                            "LEADER="PID_FMT, m->leader,
     432             :                            LOG_MESSAGE("Machine %s terminated.", m->name),
     433             :                            NULL);
     434             : 
     435             :         /* Kill cgroup */
     436           0 :         k = machine_stop_scope(m);
     437           0 :         if (k < 0)
     438           0 :                 r = k;
     439             : 
     440           0 :         machine_unlink(m);
     441           0 :         machine_add_to_gc_queue(m);
     442             : 
     443           0 :         if (m->started)
     444           0 :                 machine_send_signal(m, false);
     445             : 
     446           0 :         m->started = false;
     447             : 
     448           0 :         return r;
     449             : }
     450             : 
     451           0 : bool machine_check_gc(Machine *m, bool drop_not_started) {
     452           0 :         assert(m);
     453             : 
     454           0 :         if (drop_not_started && !m->started)
     455           0 :                 return false;
     456             : 
     457           0 :         if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
     458           0 :                 return true;
     459             : 
     460           0 :         if (m->unit && manager_unit_is_active(m->manager, m->unit))
     461           0 :                 return true;
     462             : 
     463           0 :         return false;
     464             : }
     465             : 
     466           0 : void machine_add_to_gc_queue(Machine *m) {
     467           0 :         assert(m);
     468             : 
     469           0 :         if (m->in_gc_queue)
     470           0 :                 return;
     471             : 
     472           0 :         LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
     473           0 :         m->in_gc_queue = true;
     474             : }
     475             : 
     476           0 : MachineState machine_get_state(Machine *s) {
     477           0 :         assert(s);
     478             : 
     479           0 :         if (s->scope_job)
     480           0 :                 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
     481             : 
     482           0 :         return MACHINE_RUNNING;
     483             : }
     484             : 
     485           0 : int machine_kill(Machine *m, KillWho who, int signo) {
     486           0 :         assert(m);
     487             : 
     488           0 :         if (!m->unit)
     489           0 :                 return -ESRCH;
     490             : 
     491           0 :         if (who == KILL_LEADER) {
     492             :                 /* If we shall simply kill the leader, do so directly */
     493             : 
     494           0 :                 if (kill(m->leader, signo) < 0)
     495           0 :                         return -errno;
     496             : 
     497           0 :                 return 0;
     498             :         }
     499             : 
     500             :         /* Otherwise make PID 1 do it for us, for the entire cgroup */
     501           0 :         return manager_kill_unit(m->manager, m->unit, signo, NULL);
     502             : }
     503             : 
     504           0 : MachineOperation *machine_operation_unref(MachineOperation *o) {
     505           0 :         if (!o)
     506           0 :                 return NULL;
     507             : 
     508           0 :         sd_event_source_unref(o->event_source);
     509             : 
     510           0 :         safe_close(o->errno_fd);
     511             : 
     512           0 :         if (o->pid > 1)
     513           0 :                 (void) kill(o->pid, SIGKILL);
     514             : 
     515           0 :         sd_bus_message_unref(o->message);
     516             : 
     517           0 :         if (o->machine) {
     518           0 :                 LIST_REMOVE(operations, o->machine->operations, o);
     519           0 :                 o->machine->n_operations--;
     520             :         }
     521             : 
     522           0 :         free(o);
     523           0 :         return NULL;
     524             : }
     525             : 
     526           0 : void machine_release_unit(Machine *m) {
     527           0 :         assert(m);
     528             : 
     529           0 :         if (!m->unit)
     530           0 :                 return;
     531             : 
     532           0 :         (void) hashmap_remove(m->manager->machine_units, m->unit);
     533           0 :         free(m->unit);
     534           0 :         m->unit = NULL;
     535             : }
     536             : 
     537             : static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
     538             :         [MACHINE_CONTAINER] = "container",
     539             :         [MACHINE_VM] = "vm"
     540             : };
     541             : 
     542           8 : DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
     543             : 
     544             : static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
     545             :         [MACHINE_OPENING] = "opening",
     546             :         [MACHINE_RUNNING] = "running",
     547             :         [MACHINE_CLOSING] = "closing"
     548             : };
     549             : 
     550          10 : DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
     551             : 
     552             : static const char* const kill_who_table[_KILL_WHO_MAX] = {
     553             :         [KILL_LEADER] = "leader",
     554             :         [KILL_ALL] = "all"
     555             : };
     556             : 
     557           8 : DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);

Generated by: LCOV version 1.11