chiark / gitweb /
logger: adjust socket description to match service
[elogind.git] / src / 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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU 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_set_state(Snapshot *s, SnapshotState state) {
36         SnapshotState old_state;
37         assert(s);
38
39         old_state = s->state;
40         s->state = state;
41
42         if (state != old_state)
43                 log_debug("%s changed %s -> %s",
44                           s->meta.id,
45                           snapshot_state_to_string(old_state),
46                           snapshot_state_to_string(state));
47
48         unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
49 }
50
51 static int snapshot_load(Unit *u) {
52         Snapshot *s = SNAPSHOT(u);
53
54         assert(u);
55         assert(u->meta.load_state == UNIT_STUB);
56
57         /* Make sure that only snapshots created via snapshot_create()
58          * can be loaded */
59         if (!s->by_snapshot_create && s->meta.manager->n_deserializing <= 0)
60                 return -ENOENT;
61
62         u->meta.load_state = UNIT_LOADED;
63         return 0;
64 }
65
66 static int snapshot_coldplug(Unit *u) {
67         Snapshot *s = SNAPSHOT(u);
68
69         assert(s);
70         assert(s->state == SNAPSHOT_DEAD);
71
72         if (s->deserialized_state != s->state)
73                 snapshot_set_state(s, s->deserialized_state);
74
75         return 0;
76 }
77
78 static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
79         Snapshot *s = SNAPSHOT(u);
80
81         assert(s);
82         assert(f);
83
84         fprintf(f,
85                 "%sSnapshot State: %s\n"
86                 "%sClean Up: %s\n",
87                 prefix, snapshot_state_to_string(s->state),
88                 prefix, yes_no(s->cleanup));
89 }
90
91 static int snapshot_start(Unit *u) {
92         Snapshot *s = SNAPSHOT(u);
93
94         assert(s);
95         assert(s->state == SNAPSHOT_DEAD);
96
97         snapshot_set_state(s, SNAPSHOT_ACTIVE);
98
99         if (s->cleanup)
100                 unit_add_to_cleanup_queue(u);
101
102         return 0;
103 }
104
105 static int snapshot_stop(Unit *u) {
106         Snapshot *s = SNAPSHOT(u);
107
108         assert(s);
109         assert(s->state == SNAPSHOT_ACTIVE);
110
111         snapshot_set_state(s, SNAPSHOT_DEAD);
112         return 0;
113 }
114
115 static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
116         Snapshot *s = SNAPSHOT(u);
117         Unit *other;
118         Iterator i;
119
120         assert(s);
121         assert(f);
122         assert(fds);
123
124         unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
125         unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
126         SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i)
127                 unit_serialize_item(u, f, "wants", other->meta.id);
128
129         return 0;
130 }
131
132 static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
133         Snapshot *s = SNAPSHOT(u);
134         int r;
135
136         assert(u);
137         assert(key);
138         assert(value);
139         assert(fds);
140
141         if (streq(key, "state")) {
142                 SnapshotState state;
143
144                 if ((state = snapshot_state_from_string(value)) < 0)
145                         log_debug("Failed to parse state value %s", value);
146                 else
147                         s->deserialized_state = state;
148
149         } else if (streq(key, "cleanup")) {
150
151                 if ((r = parse_boolean(value)) < 0)
152                         log_debug("Failed to parse cleanup value %s", value);
153                 else
154                         s->cleanup = r;
155
156         } else if (streq(key, "wants")) {
157
158                 if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true)) < 0)
159                         return r;
160         } else
161                 log_debug("Unknown serialization key '%s'", key);
162
163         return 0;
164 }
165
166 static UnitActiveState snapshot_active_state(Unit *u) {
167         assert(u);
168
169         return state_translation_table[SNAPSHOT(u)->state];
170 }
171
172 static const char *snapshot_sub_state_to_string(Unit *u) {
173         assert(u);
174
175         return snapshot_state_to_string(SNAPSHOT(u)->state);
176 }
177
178 int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **_s) {
179         Iterator i;
180         Unit *other, *u = NULL;
181         char *n = NULL;
182         int r;
183         const char *k;
184
185         assert(m);
186         assert(_s);
187
188         if (name) {
189                 if (!unit_name_is_valid(name, false)) {
190                         dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
191                         return -EINVAL;
192                 }
193
194                 if (unit_name_to_type(name) != UNIT_SNAPSHOT) {
195                         dbus_set_error(e, BUS_ERROR_UNIT_TYPE_MISMATCH, "Unit name %s lacks snapshot suffix.", name);
196                         return -EINVAL;
197                 }
198
199                 if (manager_get_unit(m, name)) {
200                         dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
201                         return -EEXIST;
202                 }
203
204         } else {
205
206                 for (;;) {
207                         if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
208                                 return -ENOMEM;
209
210                         if (!manager_get_unit(m, n))
211                                 break;
212
213                         free(n);
214                 }
215
216                 name = n;
217         }
218
219         r = manager_load_unit_prepare(m, name, NULL, e, &u);
220         free(n);
221
222         if (r < 0)
223                 goto fail;
224
225         SNAPSHOT(u)->by_snapshot_create = true;
226         manager_dispatch_load_queue(m);
227         assert(u->meta.load_state == UNIT_LOADED);
228
229         HASHMAP_FOREACH_KEY(other, k, m->units, i) {
230
231                 if (UNIT_VTABLE(other)->no_snapshots)
232                         continue;
233
234                 if (k != other->meta.id)
235                         continue;
236
237                 if (UNIT_VTABLE(other)->check_snapshot)
238                         if (!UNIT_VTABLE(other)->check_snapshot(other))
239                             continue;
240
241                 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
242                         continue;
243
244                 if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true)) < 0)
245                         goto fail;
246         }
247
248         SNAPSHOT(u)->cleanup = cleanup;
249         *_s = SNAPSHOT(u);
250
251         return 0;
252
253 fail:
254         if (u)
255                 unit_add_to_cleanup_queue(u);
256
257         return r;
258 }
259
260 void snapshot_remove(Snapshot *s) {
261         assert(s);
262
263         unit_add_to_cleanup_queue(UNIT(s));
264 }
265
266 static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
267         [SNAPSHOT_DEAD] = "dead",
268         [SNAPSHOT_ACTIVE] = "active"
269 };
270
271 DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
272
273 const UnitVTable snapshot_vtable = {
274         .suffix = ".snapshot",
275
276         .no_alias = true,
277         .no_instances = true,
278         .no_snapshots = true,
279         .no_gc = true,
280
281         .load = snapshot_load,
282         .coldplug = snapshot_coldplug,
283
284         .dump = snapshot_dump,
285
286         .start = snapshot_start,
287         .stop = snapshot_stop,
288
289         .serialize = snapshot_serialize,
290         .deserialize_item = snapshot_deserialize_item,
291
292         .active_state = snapshot_active_state,
293         .sub_state_to_string = snapshot_sub_state_to_string,
294
295         .bus_interface = "org.freedesktop.systemd1.Snapshot",
296         .bus_message_handler = bus_snapshot_message_handler
297 };