1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
26 #include "unit-name.h"
27 #include "dbus-snapshot.h"
28 #include "bus-errors.h"
30 static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
31 [SNAPSHOT_DEAD] = UNIT_INACTIVE,
32 [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
35 static void snapshot_init(Unit *u) {
36 Snapshot *s = SNAPSHOT(u);
39 assert(UNIT(s)->load_state == UNIT_STUB);
41 UNIT(s)->ignore_on_isolate = true;
42 UNIT(s)->ignore_on_snapshot = true;
45 static void snapshot_set_state(Snapshot *s, SnapshotState state) {
46 SnapshotState old_state;
52 if (state != old_state)
53 log_debug("%s changed %s -> %s",
55 snapshot_state_to_string(old_state),
56 snapshot_state_to_string(state));
58 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
61 static int snapshot_load(Unit *u) {
62 Snapshot *s = SNAPSHOT(u);
65 assert(u->load_state == UNIT_STUB);
67 /* Make sure that only snapshots created via snapshot_create()
69 if (!s->by_snapshot_create && UNIT(s)->manager->n_reloading <= 0)
72 u->load_state = UNIT_LOADED;
76 static int snapshot_coldplug(Unit *u) {
77 Snapshot *s = SNAPSHOT(u);
80 assert(s->state == SNAPSHOT_DEAD);
82 if (s->deserialized_state != s->state)
83 snapshot_set_state(s, s->deserialized_state);
88 static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
89 Snapshot *s = SNAPSHOT(u);
95 "%sSnapshot State: %s\n"
97 prefix, snapshot_state_to_string(s->state),
98 prefix, yes_no(s->cleanup));
101 static int snapshot_start(Unit *u) {
102 Snapshot *s = SNAPSHOT(u);
105 assert(s->state == SNAPSHOT_DEAD);
107 snapshot_set_state(s, SNAPSHOT_ACTIVE);
110 unit_add_to_cleanup_queue(u);
115 static int snapshot_stop(Unit *u) {
116 Snapshot *s = SNAPSHOT(u);
119 assert(s->state == SNAPSHOT_ACTIVE);
121 snapshot_set_state(s, SNAPSHOT_DEAD);
125 static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
126 Snapshot *s = SNAPSHOT(u);
134 unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
135 unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
136 SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
137 unit_serialize_item(u, f, "wants", other->id);
142 static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
143 Snapshot *s = SNAPSHOT(u);
151 if (streq(key, "state")) {
154 if ((state = snapshot_state_from_string(value)) < 0)
155 log_debug("Failed to parse state value %s", value);
157 s->deserialized_state = state;
159 } else if (streq(key, "cleanup")) {
161 if ((r = parse_boolean(value)) < 0)
162 log_debug("Failed to parse cleanup value %s", value);
166 } else if (streq(key, "wants")) {
168 if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true)) < 0)
171 log_debug("Unknown serialization key '%s'", key);
176 static UnitActiveState snapshot_active_state(Unit *u) {
179 return state_translation_table[SNAPSHOT(u)->state];
182 static const char *snapshot_sub_state_to_string(Unit *u) {
185 return snapshot_state_to_string(SNAPSHOT(u)->state);
188 int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **_s) {
190 Unit *other, *u = NULL;
199 if (!unit_name_is_valid(name, false)) {
200 dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
204 if (unit_name_to_type(name) != UNIT_SNAPSHOT) {
205 dbus_set_error(e, BUS_ERROR_UNIT_TYPE_MISMATCH, "Unit name %s lacks snapshot suffix.", name);
209 if (manager_get_unit(m, name)) {
210 dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
217 if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
220 if (!manager_get_unit(m, n))
229 r = manager_load_unit_prepare(m, name, NULL, e, &u);
235 SNAPSHOT(u)->by_snapshot_create = true;
236 manager_dispatch_load_queue(m);
237 assert(u->load_state == UNIT_LOADED);
239 HASHMAP_FOREACH_KEY(other, k, m->units, i) {
241 if (other->ignore_on_snapshot)
247 if (UNIT_VTABLE(other)->check_snapshot)
248 if (!UNIT_VTABLE(other)->check_snapshot(other))
251 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
254 if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true)) < 0)
258 SNAPSHOT(u)->cleanup = cleanup;
259 u->allow_isolate = true;
266 unit_add_to_cleanup_queue(u);
271 void snapshot_remove(Snapshot *s) {
274 unit_add_to_cleanup_queue(UNIT(s));
277 static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
278 [SNAPSHOT_DEAD] = "dead",
279 [SNAPSHOT_ACTIVE] = "active"
282 DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
284 const UnitVTable snapshot_vtable = {
285 .object_size = sizeof(Snapshot),
288 .no_instances = true,
291 .init = snapshot_init,
293 .load = snapshot_load,
294 .coldplug = snapshot_coldplug,
296 .dump = snapshot_dump,
298 .start = snapshot_start,
299 .stop = snapshot_stop,
301 .serialize = snapshot_serialize,
302 .deserialize_item = snapshot_deserialize_item,
304 .active_state = snapshot_active_state,
305 .sub_state_to_string = snapshot_sub_state_to_string,
307 .bus_interface = "org.freedesktop.systemd1.Snapshot",
308 .bus_message_handler = bus_snapshot_message_handler