]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/snapshot.c
dbus: follow standardized fdo PropertiesChanged signal spec
[thirdparty/systemd.git] / src / 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
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
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
a16e1123
LP
35static void snapshot_set_state(Snapshot *s, SnapshotState state) {
36 SnapshotState old_state;
37 assert(s);
41447faf 38
a16e1123
LP
39 old_state = s->state;
40 s->state = state;
41447faf 41
a16e1123 42 if (state != old_state)
40d50879 43 log_debug("%s changed %s -> %s",
4cd1fbcc 44 s->meta.id,
a16e1123
LP
45 snapshot_state_to_string(old_state),
46 snapshot_state_to_string(state));
5cb5a6ff 47
a16e1123
LP
48 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
49}
41447faf 50
6ec1117a
LP
51static 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 */
9f611ad8 59 if (!s->by_snapshot_create && s->meta.manager->n_deserializing <= 0)
6ec1117a
LP
60 return -ENOENT;
61
62 u->meta.load_state = UNIT_LOADED;
63 return 0;
64}
65
a16e1123
LP
66static int snapshot_coldplug(Unit *u) {
67 Snapshot *s = SNAPSHOT(u);
41447faf 68
a16e1123
LP
69 assert(s);
70 assert(s->state == SNAPSHOT_DEAD);
41447faf 71
a16e1123
LP
72 if (s->deserialized_state != s->state)
73 snapshot_set_state(s, s->deserialized_state);
41447faf
LP
74
75 return 0;
76}
77
78static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
87f0e418 79 Snapshot *s = SNAPSHOT(u);
5cb5a6ff
LP
80
81 assert(s);
41447faf 82 assert(f);
5cb5a6ff 83
41447faf
LP
84 fprintf(f,
85 "%sSnapshot State: %s\n"
86 "%sClean Up: %s\n",
a16e1123 87 prefix, snapshot_state_to_string(s->state),
41447faf
LP
88 prefix, yes_no(s->cleanup));
89}
90
41447faf
LP
91static 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
105static 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;
5cb5a6ff
LP
113}
114
a16e1123
LP
115static 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));
daf32cc7
LP
126 SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i)
127 unit_serialize_item(u, f, "wants", other->meta.id);
a16e1123
LP
128
129 return 0;
130}
131
132static 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
daf32cc7 156 } else if (streq(key, "wants")) {
a16e1123 157
daf32cc7 158 if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true)) < 0)
a16e1123
LP
159 return r;
160 } else
161 log_debug("Unknown serialization key '%s'", key);
162
163 return 0;
164}
165
87f0e418 166static UnitActiveState snapshot_active_state(Unit *u) {
41447faf
LP
167 assert(u);
168
169 return state_translation_table[SNAPSHOT(u)->state];
170}
171
172static const char *snapshot_sub_state_to_string(Unit *u) {
173 assert(u);
174
a16e1123 175 return snapshot_state_to_string(SNAPSHOT(u)->state);
41447faf
LP
176}
177
398ef8ba 178int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **_s) {
a16e1123
LP
179 Iterator i;
180 Unit *other, *u = NULL;
41447faf
LP
181 char *n = NULL;
182 int r;
a16e1123 183 const char *k;
41447faf
LP
184
185 assert(m);
186 assert(_s);
187
188 if (name) {
398ef8ba
LP
189 if (!unit_name_is_valid(name)) {
190 dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
41447faf 191 return -EINVAL;
398ef8ba 192 }
41447faf 193
398ef8ba
LP
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);
41447faf 196 return -EINVAL;
398ef8ba 197 }
41447faf 198
398ef8ba
LP
199 if (manager_get_unit(m, name)) {
200 dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
41447faf 201 return -EEXIST;
398ef8ba 202 }
41447faf
LP
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
398ef8ba 219 r = manager_load_unit_prepare(m, name, NULL, e, &u);
41447faf
LP
220 free(n);
221
222 if (r < 0)
a16e1123
LP
223 goto fail;
224
6ec1117a
LP
225 SNAPSHOT(u)->by_snapshot_create = true;
226 manager_dispatch_load_queue(m);
227 assert(u->meta.load_state == UNIT_LOADED);
228
a16e1123
LP
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
701cc384
LP
237 if (UNIT_VTABLE(other)->check_snapshot)
238 if (!UNIT_VTABLE(other)->check_snapshot(other))
239 continue;
240
a16e1123
LP
241 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
242 continue;
243
daf32cc7 244 if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true)) < 0)
a16e1123
LP
245 goto fail;
246 }
41447faf
LP
247
248 SNAPSHOT(u)->cleanup = cleanup;
249 *_s = SNAPSHOT(u);
250
251 return 0;
a16e1123
LP
252
253fail:
254 if (u)
255 unit_add_to_cleanup_queue(u);
256
257 return r;
41447faf
LP
258}
259
260void snapshot_remove(Snapshot *s) {
261 assert(s);
262
263 unit_add_to_cleanup_queue(UNIT(s));
034c6ed7
LP
264}
265
a16e1123
LP
266static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
267 [SNAPSHOT_DEAD] = "dead",
268 [SNAPSHOT_ACTIVE] = "active"
269};
270
271DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
272
87f0e418 273const UnitVTable snapshot_vtable = {
5cb5a6ff
LP
274 .suffix = ".snapshot",
275
41447faf
LP
276 .no_alias = true,
277 .no_instances = true,
278 .no_snapshots = true,
701cc384 279 .no_gc = true,
41447faf 280
6ec1117a 281 .load = snapshot_load,
a16e1123 282 .coldplug = snapshot_coldplug,
41447faf
LP
283
284 .dump = snapshot_dump,
285
286 .start = snapshot_start,
287 .stop = snapshot_stop,
288
a16e1123
LP
289 .serialize = snapshot_serialize,
290 .deserialize_item = snapshot_deserialize_item,
291
41447faf
LP
292 .active_state = snapshot_active_state,
293 .sub_state_to_string = snapshot_sub_state_to_string,
5cb5a6ff 294
c4e2ceae 295 .bus_interface = "org.freedesktop.systemd1.Snapshot",
41447faf 296 .bus_message_handler = bus_snapshot_message_handler
5cb5a6ff 297};