]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/snapshot.c
Merge pull request #837 from ssahani/dhcp
[thirdparty/systemd.git] / src / core / snapshot.c
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 static 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;
43 UNIT(s)->allow_isolate = true;
44 }
45
46 static 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)
54 log_unit_debug(UNIT(s), "Changed %s -> %s", snapshot_state_to_string(old_state), snapshot_state_to_string(state));
55
56 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
57 }
58
59 static 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 */
67 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
68 return -ENOENT;
69
70 u->load_state = UNIT_LOADED;
71 return 0;
72 }
73
74 static 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
86 static 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
99 static 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
110 return 1;
111 }
112
113 static 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);
120 return 1;
121 }
122
123 static 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
140 static 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
152 state = snapshot_state_from_string(value);
153 if (state < 0)
154 log_unit_debug(u, "Failed to parse state value: %s", value);
155 else
156 s->deserialized_state = state;
157
158 } else if (streq(key, "cleanup")) {
159
160 r = parse_boolean(value);
161 if (r < 0)
162 log_unit_debug(u, "Failed to parse cleanup value: %s", value);
163 else
164 s->cleanup = r;
165
166 } else if (streq(key, "wants")) {
167
168 r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true);
169 if (r < 0)
170 return r;
171 } else
172 log_unit_debug(u, "Unknown serialization key: %s", key);
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
189 int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) {
190 _cleanup_free_ char *n = NULL;
191 Unit *other, *u = NULL;
192 Iterator i;
193 int r;
194 const char *k;
195
196 assert(m);
197 assert(_s);
198
199 if (name) {
200 if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
201 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
202
203 if (!endswith(name, ".snapshot"))
204 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
205
206 if (manager_get_unit(m, name))
207 return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
208
209 } else {
210
211 for (;;) {
212 if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
213 return -ENOMEM;
214
215 if (!manager_get_unit(m, n)) {
216 name = n;
217 break;
218 }
219
220 n = mfree(n);
221 }
222 }
223
224 r = manager_load_unit_prepare(m, name, NULL, e, &u);
225 if (r < 0)
226 goto fail;
227
228 u->transient = true;
229 manager_dispatch_load_queue(m);
230 assert(u->load_state == UNIT_LOADED);
231
232 HASHMAP_FOREACH_KEY(other, k, m->units, i) {
233
234 if (other->ignore_on_snapshot ||
235 other->transient)
236 continue;
237
238 if (k != other->id)
239 continue;
240
241 if (UNIT_VTABLE(other)->check_snapshot)
242 if (!UNIT_VTABLE(other)->check_snapshot(other))
243 continue;
244
245 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
246 continue;
247
248 r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true);
249 if (r < 0)
250 goto fail;
251 }
252
253 SNAPSHOT(u)->cleanup = cleanup;
254 *_s = SNAPSHOT(u);
255
256 log_unit_info(u, "Created snapshot.");
257
258 return 0;
259
260 fail:
261 if (u)
262 unit_add_to_cleanup_queue(u);
263
264 return r;
265 }
266
267 void snapshot_remove(Snapshot *s) {
268 assert(s);
269
270 log_unit_info(UNIT(s), "Removing snapshot.");
271
272 unit_add_to_cleanup_queue(UNIT(s));
273 }
274
275 static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
276 [SNAPSHOT_DEAD] = "dead",
277 [SNAPSHOT_ACTIVE] = "active"
278 };
279
280 DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
281
282 const UnitVTable snapshot_vtable = {
283 .object_size = sizeof(Snapshot),
284
285 .no_alias = true,
286 .no_instances = true,
287 .no_gc = true,
288
289 .init = snapshot_init,
290 .load = snapshot_load,
291
292 .coldplug = snapshot_coldplug,
293
294 .dump = snapshot_dump,
295
296 .start = snapshot_start,
297 .stop = snapshot_stop,
298
299 .serialize = snapshot_serialize,
300 .deserialize_item = snapshot_deserialize_item,
301
302 .active_state = snapshot_active_state,
303 .sub_state_to_string = snapshot_sub_state_to_string,
304
305 .bus_interface = "org.freedesktop.systemd1.Snapshot",
306 .bus_vtable = bus_snapshot_vtable
307 };