]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/snapshot.c
Merge nss-myhostname
[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-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 }
44
45 static void snapshot_set_state(Snapshot *s, SnapshotState state) {
46 SnapshotState old_state;
47 assert(s);
48
49 old_state = s->state;
50 s->state = state;
51
52 if (state != old_state)
53 log_debug("%s changed %s -> %s",
54 UNIT(s)->id,
55 snapshot_state_to_string(old_state),
56 snapshot_state_to_string(state));
57
58 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
59 }
60
61 static int snapshot_load(Unit *u) {
62 Snapshot *s = SNAPSHOT(u);
63
64 assert(u);
65 assert(u->load_state == UNIT_STUB);
66
67 /* Make sure that only snapshots created via snapshot_create()
68 * can be loaded */
69 if (!s->by_snapshot_create && UNIT(s)->manager->n_reloading <= 0)
70 return -ENOENT;
71
72 u->load_state = UNIT_LOADED;
73 return 0;
74 }
75
76 static int snapshot_coldplug(Unit *u) {
77 Snapshot *s = SNAPSHOT(u);
78
79 assert(s);
80 assert(s->state == SNAPSHOT_DEAD);
81
82 if (s->deserialized_state != s->state)
83 snapshot_set_state(s, s->deserialized_state);
84
85 return 0;
86 }
87
88 static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
89 Snapshot *s = SNAPSHOT(u);
90
91 assert(s);
92 assert(f);
93
94 fprintf(f,
95 "%sSnapshot State: %s\n"
96 "%sClean Up: %s\n",
97 prefix, snapshot_state_to_string(s->state),
98 prefix, yes_no(s->cleanup));
99 }
100
101 static 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
115 static 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;
123 }
124
125 static 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));
136 SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
137 unit_serialize_item(u, f, "wants", other->id);
138
139 return 0;
140 }
141
142 static 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
166 } else if (streq(key, "wants")) {
167
168 if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true)) < 0)
169 return r;
170 } else
171 log_debug("Unknown serialization key '%s'", key);
172
173 return 0;
174 }
175
176 static UnitActiveState snapshot_active_state(Unit *u) {
177 assert(u);
178
179 return state_translation_table[SNAPSHOT(u)->state];
180 }
181
182 static const char *snapshot_sub_state_to_string(Unit *u) {
183 assert(u);
184
185 return snapshot_state_to_string(SNAPSHOT(u)->state);
186 }
187
188 int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **_s) {
189 Iterator i;
190 Unit *other, *u = NULL;
191 char *n = NULL;
192 int r;
193 const char *k;
194
195 assert(m);
196 assert(_s);
197
198 if (name) {
199 if (!unit_name_is_valid(name, false)) {
200 dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
201 return -EINVAL;
202 }
203
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);
206 return -EINVAL;
207 }
208
209 if (manager_get_unit(m, name)) {
210 dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
211 return -EEXIST;
212 }
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
229 r = manager_load_unit_prepare(m, name, NULL, e, &u);
230 free(n);
231
232 if (r < 0)
233 goto fail;
234
235 SNAPSHOT(u)->by_snapshot_create = true;
236 manager_dispatch_load_queue(m);
237 assert(u->load_state == UNIT_LOADED);
238
239 HASHMAP_FOREACH_KEY(other, k, m->units, i) {
240
241 if (other->ignore_on_snapshot)
242 continue;
243
244 if (k != other->id)
245 continue;
246
247 if (UNIT_VTABLE(other)->check_snapshot)
248 if (!UNIT_VTABLE(other)->check_snapshot(other))
249 continue;
250
251 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
252 continue;
253
254 if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true)) < 0)
255 goto fail;
256 }
257
258 SNAPSHOT(u)->cleanup = cleanup;
259 *_s = SNAPSHOT(u);
260
261 return 0;
262
263 fail:
264 if (u)
265 unit_add_to_cleanup_queue(u);
266
267 return r;
268 }
269
270 void snapshot_remove(Snapshot *s) {
271 assert(s);
272
273 unit_add_to_cleanup_queue(UNIT(s));
274 }
275
276 static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
277 [SNAPSHOT_DEAD] = "dead",
278 [SNAPSHOT_ACTIVE] = "active"
279 };
280
281 DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
282
283 const 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,
291
292 .load = snapshot_load,
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",
307 .bus_message_handler = bus_snapshot_message_handler
308 };