]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/snapshot.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / core / 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
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
41447faf
LP
22#include <errno.h>
23
07630cea
LP
24#include "bus-common-errors.h"
25#include "dbus-snapshot.h"
26#include "string-util.h"
27#include "unit-name.h"
87f0e418 28#include "unit.h"
5cb5a6ff 29#include "snapshot.h"
41447faf
LP
30
31static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
32 [SNAPSHOT_DEAD] = UNIT_INACTIVE,
33 [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
34};
35
7a6000a6
LP
36static void snapshot_init(Unit *u) {
37 Snapshot *s = SNAPSHOT(u);
38
39 assert(s);
1124fe6f 40 assert(UNIT(s)->load_state == UNIT_STUB);
7a6000a6 41
1124fe6f
MS
42 UNIT(s)->ignore_on_isolate = true;
43 UNIT(s)->ignore_on_snapshot = true;
a190eeb8 44 UNIT(s)->allow_isolate = true;
7a6000a6
LP
45}
46
a16e1123
LP
47static void snapshot_set_state(Snapshot *s, SnapshotState state) {
48 SnapshotState old_state;
49 assert(s);
41447faf 50
a16e1123
LP
51 old_state = s->state;
52 s->state = state;
41447faf 53
a16e1123 54 if (state != old_state)
f2341e0a 55 log_unit_debug(UNIT(s), "Changed %s -> %s", snapshot_state_to_string(old_state), snapshot_state_to_string(state));
5cb5a6ff 56
e2f3b44c 57 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
a16e1123 58}
41447faf 59
6ec1117a
LP
60static int snapshot_load(Unit *u) {
61 Snapshot *s = SNAPSHOT(u);
62
63 assert(u);
ac155bb8 64 assert(u->load_state == UNIT_STUB);
6ec1117a
LP
65
66 /* Make sure that only snapshots created via snapshot_create()
67 * can be loaded */
a190eeb8 68 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
6ec1117a
LP
69 return -ENOENT;
70
ac155bb8 71 u->load_state = UNIT_LOADED;
6ec1117a
LP
72 return 0;
73}
74
be847e82 75static int snapshot_coldplug(Unit *u) {
a16e1123 76 Snapshot *s = SNAPSHOT(u);
41447faf 77
a16e1123
LP
78 assert(s);
79 assert(s->state == SNAPSHOT_DEAD);
41447faf 80
a16e1123
LP
81 if (s->deserialized_state != s->state)
82 snapshot_set_state(s, s->deserialized_state);
41447faf
LP
83
84 return 0;
85}
86
87static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
87f0e418 88 Snapshot *s = SNAPSHOT(u);
5cb5a6ff
LP
89
90 assert(s);
41447faf 91 assert(f);
5cb5a6ff 92
41447faf
LP
93 fprintf(f,
94 "%sSnapshot State: %s\n"
95 "%sClean Up: %s\n",
a16e1123 96 prefix, snapshot_state_to_string(s->state),
41447faf
LP
97 prefix, yes_no(s->cleanup));
98}
99
41447faf
LP
100static int snapshot_start(Unit *u) {
101 Snapshot *s = SNAPSHOT(u);
102
103 assert(s);
104 assert(s->state == SNAPSHOT_DEAD);
105
106 snapshot_set_state(s, SNAPSHOT_ACTIVE);
107
108 if (s->cleanup)
109 unit_add_to_cleanup_queue(u);
110
82a2b6bb 111 return 1;
41447faf
LP
112}
113
114static int snapshot_stop(Unit *u) {
115 Snapshot *s = SNAPSHOT(u);
116
117 assert(s);
118 assert(s->state == SNAPSHOT_ACTIVE);
119
120 snapshot_set_state(s, SNAPSHOT_DEAD);
82a2b6bb 121 return 1;
5cb5a6ff
LP
122}
123
a16e1123
LP
124static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
125 Snapshot *s = SNAPSHOT(u);
126 Unit *other;
127 Iterator i;
128
129 assert(s);
130 assert(f);
131 assert(fds);
132
133 unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
134 unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
ac155bb8
MS
135 SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
136 unit_serialize_item(u, f, "wants", other->id);
a16e1123
LP
137
138 return 0;
139}
140
141static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
142 Snapshot *s = SNAPSHOT(u);
143 int r;
144
145 assert(u);
146 assert(key);
147 assert(value);
148 assert(fds);
149
150 if (streq(key, "state")) {
151 SnapshotState state;
152
a190eeb8
LP
153 state = snapshot_state_from_string(value);
154 if (state < 0)
f2341e0a 155 log_unit_debug(u, "Failed to parse state value: %s", value);
a16e1123
LP
156 else
157 s->deserialized_state = state;
158
159 } else if (streq(key, "cleanup")) {
160
a190eeb8
LP
161 r = parse_boolean(value);
162 if (r < 0)
f2341e0a 163 log_unit_debug(u, "Failed to parse cleanup value: %s", value);
a16e1123
LP
164 else
165 s->cleanup = r;
166
daf32cc7 167 } else if (streq(key, "wants")) {
a16e1123 168
a190eeb8
LP
169 r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true);
170 if (r < 0)
a16e1123
LP
171 return r;
172 } else
f2341e0a 173 log_unit_debug(u, "Unknown serialization key: %s", key);
a16e1123
LP
174
175 return 0;
176}
177
44a6b1b6 178_pure_ static UnitActiveState snapshot_active_state(Unit *u) {
41447faf
LP
179 assert(u);
180
181 return state_translation_table[SNAPSHOT(u)->state];
182}
183
44a6b1b6 184_pure_ static const char *snapshot_sub_state_to_string(Unit *u) {
41447faf
LP
185 assert(u);
186
a16e1123 187 return snapshot_state_to_string(SNAPSHOT(u)->state);
41447faf
LP
188}
189
718db961 190int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) {
a190eeb8 191 _cleanup_free_ char *n = NULL;
a16e1123 192 Unit *other, *u = NULL;
a190eeb8 193 Iterator i;
41447faf 194 int r;
a16e1123 195 const char *k;
41447faf
LP
196
197 assert(m);
198 assert(_s);
199
200 if (name) {
7410616c 201 if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
718db961 202 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
41447faf 203
7410616c 204 if (!endswith(name, ".snapshot"))
718db961 205 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
41447faf 206
718db961 207 if (manager_get_unit(m, name))
7cabba07 208 return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
41447faf
LP
209
210 } else {
211
212 for (;;) {
213 if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
214 return -ENOMEM;
215
ebec5783
ZJS
216 if (!manager_get_unit(m, n)) {
217 name = n;
41447faf 218 break;
ebec5783 219 }
41447faf 220
97b11eed 221 n = mfree(n);
41447faf 222 }
41447faf
LP
223 }
224
398ef8ba 225 r = manager_load_unit_prepare(m, name, NULL, e, &u);
41447faf 226 if (r < 0)
a16e1123
LP
227 goto fail;
228
a190eeb8 229 u->transient = true;
6ec1117a 230 manager_dispatch_load_queue(m);
ac155bb8 231 assert(u->load_state == UNIT_LOADED);
6ec1117a 232
a16e1123
LP
233 HASHMAP_FOREACH_KEY(other, k, m->units, i) {
234
a190eeb8
LP
235 if (other->ignore_on_snapshot ||
236 other->transient)
a16e1123
LP
237 continue;
238
ac155bb8 239 if (k != other->id)
a16e1123
LP
240 continue;
241
701cc384
LP
242 if (UNIT_VTABLE(other)->check_snapshot)
243 if (!UNIT_VTABLE(other)->check_snapshot(other))
244 continue;
245
a16e1123
LP
246 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
247 continue;
248
a190eeb8
LP
249 r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true);
250 if (r < 0)
a16e1123
LP
251 goto fail;
252 }
41447faf
LP
253
254 SNAPSHOT(u)->cleanup = cleanup;
255 *_s = SNAPSHOT(u);
256
f2341e0a 257 log_unit_info(u, "Created snapshot.");
6f8bd5c9 258
41447faf 259 return 0;
a16e1123
LP
260
261fail:
262 if (u)
263 unit_add_to_cleanup_queue(u);
264
265 return r;
41447faf
LP
266}
267
268void snapshot_remove(Snapshot *s) {
269 assert(s);
270
f2341e0a 271 log_unit_info(UNIT(s), "Removing snapshot.");
6f8bd5c9 272
41447faf 273 unit_add_to_cleanup_queue(UNIT(s));
034c6ed7
LP
274}
275
87f0e418 276const UnitVTable snapshot_vtable = {
7d17cfbc 277 .object_size = sizeof(Snapshot),
5cb5a6ff 278
41447faf
LP
279 .no_alias = true,
280 .no_instances = true,
701cc384 281 .no_gc = true,
41447faf 282
7a6000a6 283 .init = snapshot_init,
6ec1117a 284 .load = snapshot_load,
718db961 285
a16e1123 286 .coldplug = snapshot_coldplug,
41447faf
LP
287
288 .dump = snapshot_dump,
289
290 .start = snapshot_start,
291 .stop = snapshot_stop,
292
a16e1123
LP
293 .serialize = snapshot_serialize,
294 .deserialize_item = snapshot_deserialize_item,
295
41447faf
LP
296 .active_state = snapshot_active_state,
297 .sub_state_to_string = snapshot_sub_state_to_string,
5cb5a6ff 298
718db961 299 .bus_vtable = bus_snapshot_vtable
5cb5a6ff 300};