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-common-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;
43 UNIT(s)->allow_isolate = true;
46 static void snapshot_set_state(Snapshot *s, SnapshotState state) {
47 SnapshotState old_state;
53 if (state != old_state)
54 log_unit_debug(UNIT(s)->id,
55 "%s changed %s -> %s",
57 snapshot_state_to_string(old_state),
58 snapshot_state_to_string(state));
60 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
63 static int snapshot_load(Unit *u) {
64 Snapshot *s = SNAPSHOT(u);
67 assert(u->load_state == UNIT_STUB);
69 /* Make sure that only snapshots created via snapshot_create()
71 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
74 u->load_state = UNIT_LOADED;
78 static int snapshot_coldplug(Unit *u, Hashmap *deferred_work) {
79 Snapshot *s = SNAPSHOT(u);
82 assert(s->state == SNAPSHOT_DEAD);
84 if (s->deserialized_state != s->state)
85 snapshot_set_state(s, s->deserialized_state);
90 static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
91 Snapshot *s = SNAPSHOT(u);
97 "%sSnapshot State: %s\n"
99 prefix, snapshot_state_to_string(s->state),
100 prefix, yes_no(s->cleanup));
103 static int snapshot_start(Unit *u) {
104 Snapshot *s = SNAPSHOT(u);
107 assert(s->state == SNAPSHOT_DEAD);
109 snapshot_set_state(s, SNAPSHOT_ACTIVE);
112 unit_add_to_cleanup_queue(u);
117 static int snapshot_stop(Unit *u) {
118 Snapshot *s = SNAPSHOT(u);
121 assert(s->state == SNAPSHOT_ACTIVE);
123 snapshot_set_state(s, SNAPSHOT_DEAD);
127 static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
128 Snapshot *s = SNAPSHOT(u);
136 unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
137 unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
138 SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
139 unit_serialize_item(u, f, "wants", other->id);
144 static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
145 Snapshot *s = SNAPSHOT(u);
153 if (streq(key, "state")) {
156 state = snapshot_state_from_string(value);
158 log_unit_debug(u->id, "Failed to parse state value %s", value);
160 s->deserialized_state = state;
162 } else if (streq(key, "cleanup")) {
164 r = parse_boolean(value);
166 log_unit_debug(u->id, "Failed to parse cleanup value %s", value);
170 } else if (streq(key, "wants")) {
172 r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true);
176 log_unit_debug(u->id, "Unknown serialization key '%s'", key);
181 _pure_ static UnitActiveState snapshot_active_state(Unit *u) {
184 return state_translation_table[SNAPSHOT(u)->state];
187 _pure_ static const char *snapshot_sub_state_to_string(Unit *u) {
190 return snapshot_state_to_string(SNAPSHOT(u)->state);
193 int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) {
194 _cleanup_free_ char *n = NULL;
195 Unit *other, *u = NULL;
204 if (!unit_name_is_valid(name, TEMPLATE_INVALID))
205 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
207 if (unit_name_to_type(name) != UNIT_SNAPSHOT)
208 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
210 if (manager_get_unit(m, name))
211 return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
216 if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
219 if (!manager_get_unit(m, n)) {
229 r = manager_load_unit_prepare(m, name, NULL, e, &u);
234 manager_dispatch_load_queue(m);
235 assert(u->load_state == UNIT_LOADED);
237 HASHMAP_FOREACH_KEY(other, k, m->units, i) {
239 if (other->ignore_on_snapshot ||
246 if (UNIT_VTABLE(other)->check_snapshot)
247 if (!UNIT_VTABLE(other)->check_snapshot(other))
250 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
253 r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true);
258 SNAPSHOT(u)->cleanup = cleanup;
261 log_unit_info(u->id, "Created snapshot %s.", u->id);
267 unit_add_to_cleanup_queue(u);
272 void snapshot_remove(Snapshot *s) {
275 log_unit_info(UNIT(s)->id, "Removing snapshot %s.", UNIT(s)->id);
277 unit_add_to_cleanup_queue(UNIT(s));
280 static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
281 [SNAPSHOT_DEAD] = "dead",
282 [SNAPSHOT_ACTIVE] = "active"
285 DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
287 const UnitVTable snapshot_vtable = {
288 .object_size = sizeof(Snapshot),
291 .no_instances = true,
294 .init = snapshot_init,
295 .load = snapshot_load,
297 .coldplug = snapshot_coldplug,
299 .dump = snapshot_dump,
301 .start = snapshot_start,
302 .stop = snapshot_stop,
304 .serialize = snapshot_serialize,
305 .deserialize_item = snapshot_deserialize_item,
307 .active_state = snapshot_active_state,
308 .sub_state_to_string = snapshot_sub_state_to_string,
310 .bus_interface = "org.freedesktop.systemd1.Snapshot",
311 .bus_vtable = bus_snapshot_vtable