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