LCOV - code coverage report
Current view: top level - core - snapshot.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 1 143 0.7 %
Date: 2015-07-29 18:47:03 Functions: 2 15 13.3 %

          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 2010 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             : 
      24             : #include "unit.h"
      25             : #include "snapshot.h"
      26             : #include "unit-name.h"
      27             : #include "dbus-snapshot.h"
      28             : #include "bus-common-errors.h"
      29             : 
      30             : static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
      31             :         [SNAPSHOT_DEAD] = UNIT_INACTIVE,
      32             :         [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
      33             : };
      34             : 
      35           0 : static void snapshot_init(Unit *u) {
      36           0 :         Snapshot *s = SNAPSHOT(u);
      37             : 
      38           0 :         assert(s);
      39           0 :         assert(UNIT(s)->load_state == UNIT_STUB);
      40             : 
      41           0 :         UNIT(s)->ignore_on_isolate = true;
      42           0 :         UNIT(s)->ignore_on_snapshot = true;
      43           0 :         UNIT(s)->allow_isolate = true;
      44           0 : }
      45             : 
      46           0 : static void snapshot_set_state(Snapshot *s, SnapshotState state) {
      47             :         SnapshotState old_state;
      48           0 :         assert(s);
      49             : 
      50           0 :         old_state = s->state;
      51           0 :         s->state = state;
      52             : 
      53           0 :         if (state != old_state)
      54           0 :                 log_unit_debug(UNIT(s), "Changed %s -> %s", snapshot_state_to_string(old_state), snapshot_state_to_string(state));
      55             : 
      56           0 :         unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
      57           0 : }
      58             : 
      59           0 : static int snapshot_load(Unit *u) {
      60           0 :         Snapshot *s = SNAPSHOT(u);
      61             : 
      62           0 :         assert(u);
      63           0 :         assert(u->load_state == UNIT_STUB);
      64             : 
      65             :         /* Make sure that only snapshots created via snapshot_create()
      66             :          * can be loaded */
      67           0 :         if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
      68           0 :                 return -ENOENT;
      69             : 
      70           0 :         u->load_state = UNIT_LOADED;
      71           0 :         return 0;
      72             : }
      73             : 
      74           0 : static int snapshot_coldplug(Unit *u) {
      75           0 :         Snapshot *s = SNAPSHOT(u);
      76             : 
      77           0 :         assert(s);
      78           0 :         assert(s->state == SNAPSHOT_DEAD);
      79             : 
      80           0 :         if (s->deserialized_state != s->state)
      81           0 :                 snapshot_set_state(s, s->deserialized_state);
      82             : 
      83           0 :         return 0;
      84             : }
      85             : 
      86           0 : static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
      87           0 :         Snapshot *s = SNAPSHOT(u);
      88             : 
      89           0 :         assert(s);
      90           0 :         assert(f);
      91             : 
      92           0 :         fprintf(f,
      93             :                 "%sSnapshot State: %s\n"
      94             :                 "%sClean Up: %s\n",
      95             :                 prefix, snapshot_state_to_string(s->state),
      96           0 :                 prefix, yes_no(s->cleanup));
      97           0 : }
      98             : 
      99           0 : static int snapshot_start(Unit *u) {
     100           0 :         Snapshot *s = SNAPSHOT(u);
     101             : 
     102           0 :         assert(s);
     103           0 :         assert(s->state == SNAPSHOT_DEAD);
     104             : 
     105           0 :         snapshot_set_state(s, SNAPSHOT_ACTIVE);
     106             : 
     107           0 :         if (s->cleanup)
     108           0 :                 unit_add_to_cleanup_queue(u);
     109             : 
     110           0 :         return 1;
     111             : }
     112             : 
     113           0 : static int snapshot_stop(Unit *u) {
     114           0 :         Snapshot *s = SNAPSHOT(u);
     115             : 
     116           0 :         assert(s);
     117           0 :         assert(s->state == SNAPSHOT_ACTIVE);
     118             : 
     119           0 :         snapshot_set_state(s, SNAPSHOT_DEAD);
     120           0 :         return 1;
     121             : }
     122             : 
     123           0 : static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
     124           0 :         Snapshot *s = SNAPSHOT(u);
     125             :         Unit *other;
     126             :         Iterator i;
     127             : 
     128           0 :         assert(s);
     129           0 :         assert(f);
     130           0 :         assert(fds);
     131             : 
     132           0 :         unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
     133           0 :         unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
     134           0 :         SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
     135           0 :                 unit_serialize_item(u, f, "wants", other->id);
     136             : 
     137           0 :         return 0;
     138             : }
     139             : 
     140           0 : static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
     141           0 :         Snapshot *s = SNAPSHOT(u);
     142             :         int r;
     143             : 
     144           0 :         assert(u);
     145           0 :         assert(key);
     146           0 :         assert(value);
     147           0 :         assert(fds);
     148             : 
     149           0 :         if (streq(key, "state")) {
     150             :                 SnapshotState state;
     151             : 
     152           0 :                 state = snapshot_state_from_string(value);
     153           0 :                 if (state < 0)
     154           0 :                         log_unit_debug(u, "Failed to parse state value: %s", value);
     155             :                 else
     156           0 :                         s->deserialized_state = state;
     157             : 
     158           0 :         } else if (streq(key, "cleanup")) {
     159             : 
     160           0 :                 r = parse_boolean(value);
     161           0 :                 if (r < 0)
     162           0 :                         log_unit_debug(u, "Failed to parse cleanup value: %s", value);
     163             :                 else
     164           0 :                         s->cleanup = r;
     165             : 
     166           0 :         } else if (streq(key, "wants")) {
     167             : 
     168           0 :                 r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true);
     169           0 :                 if (r < 0)
     170           0 :                         return r;
     171             :         } else
     172           0 :                 log_unit_debug(u, "Unknown serialization key: %s", key);
     173             : 
     174           0 :         return 0;
     175             : }
     176             : 
     177           0 : _pure_ static UnitActiveState snapshot_active_state(Unit *u) {
     178           0 :         assert(u);
     179             : 
     180           0 :         return state_translation_table[SNAPSHOT(u)->state];
     181             : }
     182             : 
     183           0 : _pure_ static const char *snapshot_sub_state_to_string(Unit *u) {
     184           0 :         assert(u);
     185             : 
     186           0 :         return snapshot_state_to_string(SNAPSHOT(u)->state);
     187             : }
     188             : 
     189           0 : int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) {
     190           0 :         _cleanup_free_ char *n = NULL;
     191           0 :         Unit *other, *u = NULL;
     192             :         Iterator i;
     193             :         int r;
     194             :         const char *k;
     195             : 
     196           0 :         assert(m);
     197           0 :         assert(_s);
     198             : 
     199           0 :         if (name) {
     200           0 :                 if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
     201           0 :                         return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
     202             : 
     203           0 :                 if (!endswith(name, ".snapshot"))
     204           0 :                         return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
     205             : 
     206           0 :                 if (manager_get_unit(m, name))
     207           0 :                         return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
     208             : 
     209             :         } else {
     210             : 
     211             :                 for (;;) {
     212           0 :                         if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
     213           0 :                                 return -ENOMEM;
     214             : 
     215           0 :                         if (!manager_get_unit(m, n)) {
     216           0 :                                 name = n;
     217           0 :                                 break;
     218             :                         }
     219             : 
     220           0 :                         free(n);
     221           0 :                         n = NULL;
     222           0 :                 }
     223             :         }
     224             : 
     225           0 :         r = manager_load_unit_prepare(m, name, NULL, e, &u);
     226           0 :         if (r < 0)
     227           0 :                 goto fail;
     228             : 
     229           0 :         u->transient = true;
     230           0 :         manager_dispatch_load_queue(m);
     231           0 :         assert(u->load_state == UNIT_LOADED);
     232             : 
     233           0 :         HASHMAP_FOREACH_KEY(other, k, m->units, i) {
     234             : 
     235           0 :                 if (other->ignore_on_snapshot ||
     236           0 :                     other->transient)
     237           0 :                         continue;
     238             : 
     239           0 :                 if (k != other->id)
     240           0 :                         continue;
     241             : 
     242           0 :                 if (UNIT_VTABLE(other)->check_snapshot)
     243           0 :                         if (!UNIT_VTABLE(other)->check_snapshot(other))
     244           0 :                             continue;
     245             : 
     246           0 :                 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
     247           0 :                         continue;
     248             : 
     249           0 :                 r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true);
     250           0 :                 if (r < 0)
     251           0 :                         goto fail;
     252             :         }
     253             : 
     254           0 :         SNAPSHOT(u)->cleanup = cleanup;
     255           0 :         *_s = SNAPSHOT(u);
     256             : 
     257           0 :         log_unit_info(u, "Created snapshot.");
     258             : 
     259           0 :         return 0;
     260             : 
     261             : fail:
     262           0 :         if (u)
     263           0 :                 unit_add_to_cleanup_queue(u);
     264             : 
     265           0 :         return r;
     266             : }
     267             : 
     268           0 : void snapshot_remove(Snapshot *s) {
     269           0 :         assert(s);
     270             : 
     271           0 :         log_unit_info(UNIT(s), "Removing snapshot.");
     272             : 
     273           0 :         unit_add_to_cleanup_queue(UNIT(s));
     274           0 : }
     275             : 
     276             : static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
     277             :         [SNAPSHOT_DEAD] = "dead",
     278             :         [SNAPSHOT_ACTIVE] = "active"
     279             : };
     280             : 
     281           8 : DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
     282             : 
     283             : const UnitVTable snapshot_vtable = {
     284             :         .object_size = sizeof(Snapshot),
     285             : 
     286             :         .no_alias = true,
     287             :         .no_instances = true,
     288             :         .no_gc = true,
     289             : 
     290             :         .init = snapshot_init,
     291             :         .load = snapshot_load,
     292             : 
     293             :         .coldplug = snapshot_coldplug,
     294             : 
     295             :         .dump = snapshot_dump,
     296             : 
     297             :         .start = snapshot_start,
     298             :         .stop = snapshot_stop,
     299             : 
     300             :         .serialize = snapshot_serialize,
     301             :         .deserialize_item = snapshot_deserialize_item,
     302             : 
     303             :         .active_state = snapshot_active_state,
     304             :         .sub_state_to_string = snapshot_sub_state_to_string,
     305             : 
     306             :         .bus_interface = "org.freedesktop.systemd1.Snapshot",
     307             :         .bus_vtable = bus_snapshot_vtable
     308             : };

Generated by: LCOV version 1.11