]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/snapshot.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / core / snapshot.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5cb5a6ff 2
a7334b09
LP
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
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
41447faf
LP
22#include <errno.h>
23
87f0e418 24#include "unit.h"
5cb5a6ff 25#include "snapshot.h"
41447faf
LP
26#include "unit-name.h"
27#include "dbus-snapshot.h"
398ef8ba 28#include "bus-errors.h"
41447faf
LP
29
30static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
31 [SNAPSHOT_DEAD] = UNIT_INACTIVE,
32 [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
33};
34
7a6000a6
LP
35static void snapshot_init(Unit *u) {
36 Snapshot *s = SNAPSHOT(u);
37
38 assert(s);
1124fe6f 39 assert(UNIT(s)->load_state == UNIT_STUB);
7a6000a6 40
1124fe6f
MS
41 UNIT(s)->ignore_on_isolate = true;
42 UNIT(s)->ignore_on_snapshot = true;
7a6000a6
LP
43}
44
a16e1123
LP
45static void snapshot_set_state(Snapshot *s, SnapshotState state) {
46 SnapshotState old_state;
47 assert(s);
41447faf 48
a16e1123
LP
49 old_state = s->state;
50 s->state = state;
41447faf 51
a16e1123 52 if (state != old_state)
40d50879 53 log_debug("%s changed %s -> %s",
1124fe6f 54 UNIT(s)->id,
a16e1123
LP
55 snapshot_state_to_string(old_state),
56 snapshot_state_to_string(state));
5cb5a6ff 57
e2f3b44c 58 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
a16e1123 59}
41447faf 60
6ec1117a
LP
61static int snapshot_load(Unit *u) {
62 Snapshot *s = SNAPSHOT(u);
63
64 assert(u);
ac155bb8 65 assert(u->load_state == UNIT_STUB);
6ec1117a
LP
66
67 /* Make sure that only snapshots created via snapshot_create()
68 * can be loaded */
1124fe6f 69 if (!s->by_snapshot_create && UNIT(s)->manager->n_reloading <= 0)
6ec1117a
LP
70 return -ENOENT;
71
ac155bb8 72 u->load_state = UNIT_LOADED;
6ec1117a
LP
73 return 0;
74}
75
a16e1123
LP
76static int snapshot_coldplug(Unit *u) {
77 Snapshot *s = SNAPSHOT(u);
41447faf 78
a16e1123
LP
79 assert(s);
80 assert(s->state == SNAPSHOT_DEAD);
41447faf 81
a16e1123
LP
82 if (s->deserialized_state != s->state)
83 snapshot_set_state(s, s->deserialized_state);
41447faf
LP
84
85 return 0;
86}
87
88static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
87f0e418 89 Snapshot *s = SNAPSHOT(u);
5cb5a6ff
LP
90
91 assert(s);
41447faf 92 assert(f);
5cb5a6ff 93
41447faf
LP
94 fprintf(f,
95 "%sSnapshot State: %s\n"
96 "%sClean Up: %s\n",
a16e1123 97 prefix, snapshot_state_to_string(s->state),
41447faf
LP
98 prefix, yes_no(s->cleanup));
99}
100
41447faf
LP
101static int snapshot_start(Unit *u) {
102 Snapshot *s = SNAPSHOT(u);
103
104 assert(s);
105 assert(s->state == SNAPSHOT_DEAD);
106
107 snapshot_set_state(s, SNAPSHOT_ACTIVE);
108
109 if (s->cleanup)
110 unit_add_to_cleanup_queue(u);
111
112 return 0;
113}
114
115static int snapshot_stop(Unit *u) {
116 Snapshot *s = SNAPSHOT(u);
117
118 assert(s);
119 assert(s->state == SNAPSHOT_ACTIVE);
120
121 snapshot_set_state(s, SNAPSHOT_DEAD);
122 return 0;
5cb5a6ff
LP
123}
124
a16e1123
LP
125static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
126 Snapshot *s = SNAPSHOT(u);
127 Unit *other;
128 Iterator i;
129
130 assert(s);
131 assert(f);
132 assert(fds);
133
134 unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
135 unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
ac155bb8
MS
136 SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
137 unit_serialize_item(u, f, "wants", other->id);
a16e1123
LP
138
139 return 0;
140}
141
142static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
143 Snapshot *s = SNAPSHOT(u);
144 int r;
145
146 assert(u);
147 assert(key);
148 assert(value);
149 assert(fds);
150
151 if (streq(key, "state")) {
152 SnapshotState state;
153
154 if ((state = snapshot_state_from_string(value)) < 0)
155 log_debug("Failed to parse state value %s", value);
156 else
157 s->deserialized_state = state;
158
159 } else if (streq(key, "cleanup")) {
160
161 if ((r = parse_boolean(value)) < 0)
162 log_debug("Failed to parse cleanup value %s", value);
163 else
164 s->cleanup = r;
165
daf32cc7 166 } else if (streq(key, "wants")) {
a16e1123 167
daf32cc7 168 if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true)) < 0)
a16e1123
LP
169 return r;
170 } else
171 log_debug("Unknown serialization key '%s'", key);
172
173 return 0;
174}
175
87f0e418 176static UnitActiveState snapshot_active_state(Unit *u) {
41447faf
LP
177 assert(u);
178
179 return state_translation_table[SNAPSHOT(u)->state];
180}
181
182static const char *snapshot_sub_state_to_string(Unit *u) {
183 assert(u);
184
a16e1123 185 return snapshot_state_to_string(SNAPSHOT(u)->state);
41447faf
LP
186}
187
398ef8ba 188int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **_s) {
a16e1123
LP
189 Iterator i;
190 Unit *other, *u = NULL;
41447faf
LP
191 char *n = NULL;
192 int r;
a16e1123 193 const char *k;
41447faf
LP
194
195 assert(m);
196 assert(_s);
197
198 if (name) {
b9c0d441 199 if (!unit_name_is_valid(name, false)) {
398ef8ba 200 dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
41447faf 201 return -EINVAL;
398ef8ba 202 }
41447faf 203
398ef8ba
LP
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);
41447faf 206 return -EINVAL;
398ef8ba 207 }
41447faf 208
398ef8ba
LP
209 if (manager_get_unit(m, name)) {
210 dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
41447faf 211 return -EEXIST;
398ef8ba 212 }
41447faf
LP
213
214 } else {
215
216 for (;;) {
217 if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
218 return -ENOMEM;
219
220 if (!manager_get_unit(m, n))
221 break;
222
223 free(n);
224 }
225
226 name = n;
227 }
228
398ef8ba 229 r = manager_load_unit_prepare(m, name, NULL, e, &u);
41447faf
LP
230 free(n);
231
232 if (r < 0)
a16e1123
LP
233 goto fail;
234
6ec1117a
LP
235 SNAPSHOT(u)->by_snapshot_create = true;
236 manager_dispatch_load_queue(m);
ac155bb8 237 assert(u->load_state == UNIT_LOADED);
6ec1117a 238
a16e1123
LP
239 HASHMAP_FOREACH_KEY(other, k, m->units, i) {
240
ac155bb8 241 if (other->ignore_on_snapshot)
a16e1123
LP
242 continue;
243
ac155bb8 244 if (k != other->id)
a16e1123
LP
245 continue;
246
701cc384
LP
247 if (UNIT_VTABLE(other)->check_snapshot)
248 if (!UNIT_VTABLE(other)->check_snapshot(other))
249 continue;
250
a16e1123
LP
251 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
252 continue;
253
daf32cc7 254 if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true)) < 0)
a16e1123
LP
255 goto fail;
256 }
41447faf
LP
257
258 SNAPSHOT(u)->cleanup = cleanup;
259 *_s = SNAPSHOT(u);
260
261 return 0;
a16e1123
LP
262
263fail:
264 if (u)
265 unit_add_to_cleanup_queue(u);
266
267 return r;
41447faf
LP
268}
269
270void snapshot_remove(Snapshot *s) {
271 assert(s);
272
273 unit_add_to_cleanup_queue(UNIT(s));
034c6ed7
LP
274}
275
a16e1123
LP
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
87f0e418 283const UnitVTable snapshot_vtable = {
5cb5a6ff 284 .suffix = ".snapshot",
7d17cfbc 285 .object_size = sizeof(Snapshot),
5cb5a6ff 286
41447faf
LP
287 .no_alias = true,
288 .no_instances = true,
701cc384 289 .no_gc = true,
41447faf 290
7a6000a6
LP
291 .init = snapshot_init,
292
6ec1117a 293 .load = snapshot_load,
a16e1123 294 .coldplug = snapshot_coldplug,
41447faf
LP
295
296 .dump = snapshot_dump,
297
298 .start = snapshot_start,
299 .stop = snapshot_stop,
300
a16e1123
LP
301 .serialize = snapshot_serialize,
302 .deserialize_item = snapshot_deserialize_item,
303
41447faf
LP
304 .active_state = snapshot_active_state,
305 .sub_state_to_string = snapshot_sub_state_to_string,
5cb5a6ff 306
c4e2ceae 307 .bus_interface = "org.freedesktop.systemd1.Snapshot",
41447faf 308 .bus_message_handler = bus_snapshot_message_handler
5cb5a6ff 309};