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