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