]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/snapshot.c
core,network: major per-object logging rework
[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
87f0e418 24#include "unit.h"
5cb5a6ff 25#include "snapshot.h"
41447faf
LP
26#include "unit-name.h"
27#include "dbus-snapshot.h"
96aad8d1 28#include "bus-common-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
7a6000a6
LP
35static void snapshot_init(Unit *u) {
36 Snapshot *s = SNAPSHOT(u);
37
38 assert(s);
1124fe6f 39 assert(UNIT(s)->load_state == UNIT_STUB);
7a6000a6 40
1124fe6f
MS
41 UNIT(s)->ignore_on_isolate = true;
42 UNIT(s)->ignore_on_snapshot = true;
a190eeb8 43 UNIT(s)->allow_isolate = true;
7a6000a6
LP
44}
45
a16e1123
LP
46static void snapshot_set_state(Snapshot *s, SnapshotState state) {
47 SnapshotState old_state;
48 assert(s);
41447faf 49
a16e1123
LP
50 old_state = s->state;
51 s->state = state;
41447faf 52
a16e1123 53 if (state != old_state)
f2341e0a 54 log_unit_debug(UNIT(s), "Changed %s -> %s", snapshot_state_to_string(old_state), snapshot_state_to_string(state));
5cb5a6ff 55
e2f3b44c 56 unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
a16e1123 57}
41447faf 58
6ec1117a
LP
59static int snapshot_load(Unit *u) {
60 Snapshot *s = SNAPSHOT(u);
61
62 assert(u);
ac155bb8 63 assert(u->load_state == UNIT_STUB);
6ec1117a
LP
64
65 /* Make sure that only snapshots created via snapshot_create()
66 * can be loaded */
a190eeb8 67 if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
6ec1117a
LP
68 return -ENOENT;
69
ac155bb8 70 u->load_state = UNIT_LOADED;
6ec1117a
LP
71 return 0;
72}
73
be847e82 74static int snapshot_coldplug(Unit *u) {
a16e1123 75 Snapshot *s = SNAPSHOT(u);
41447faf 76
a16e1123
LP
77 assert(s);
78 assert(s->state == SNAPSHOT_DEAD);
41447faf 79
a16e1123
LP
80 if (s->deserialized_state != s->state)
81 snapshot_set_state(s, s->deserialized_state);
41447faf
LP
82
83 return 0;
84}
85
86static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
87f0e418 87 Snapshot *s = SNAPSHOT(u);
5cb5a6ff
LP
88
89 assert(s);
41447faf 90 assert(f);
5cb5a6ff 91
41447faf
LP
92 fprintf(f,
93 "%sSnapshot State: %s\n"
94 "%sClean Up: %s\n",
a16e1123 95 prefix, snapshot_state_to_string(s->state),
41447faf
LP
96 prefix, yes_no(s->cleanup));
97}
98
41447faf
LP
99static int snapshot_start(Unit *u) {
100 Snapshot *s = SNAPSHOT(u);
101
102 assert(s);
103 assert(s->state == SNAPSHOT_DEAD);
104
105 snapshot_set_state(s, SNAPSHOT_ACTIVE);
106
107 if (s->cleanup)
108 unit_add_to_cleanup_queue(u);
109
82a2b6bb 110 return 1;
41447faf
LP
111}
112
113static int snapshot_stop(Unit *u) {
114 Snapshot *s = SNAPSHOT(u);
115
116 assert(s);
117 assert(s->state == SNAPSHOT_ACTIVE);
118
119 snapshot_set_state(s, SNAPSHOT_DEAD);
82a2b6bb 120 return 1;
5cb5a6ff
LP
121}
122
a16e1123
LP
123static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
124 Snapshot *s = SNAPSHOT(u);
125 Unit *other;
126 Iterator i;
127
128 assert(s);
129 assert(f);
130 assert(fds);
131
132 unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
133 unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
ac155bb8
MS
134 SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
135 unit_serialize_item(u, f, "wants", other->id);
a16e1123
LP
136
137 return 0;
138}
139
140static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
141 Snapshot *s = SNAPSHOT(u);
142 int r;
143
144 assert(u);
145 assert(key);
146 assert(value);
147 assert(fds);
148
149 if (streq(key, "state")) {
150 SnapshotState state;
151
a190eeb8
LP
152 state = snapshot_state_from_string(value);
153 if (state < 0)
f2341e0a 154 log_unit_debug(u, "Failed to parse state value: %s", value);
a16e1123
LP
155 else
156 s->deserialized_state = state;
157
158 } else if (streq(key, "cleanup")) {
159
a190eeb8
LP
160 r = parse_boolean(value);
161 if (r < 0)
f2341e0a 162 log_unit_debug(u, "Failed to parse cleanup value: %s", value);
a16e1123
LP
163 else
164 s->cleanup = r;
165
daf32cc7 166 } else if (streq(key, "wants")) {
a16e1123 167
a190eeb8
LP
168 r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true);
169 if (r < 0)
a16e1123
LP
170 return r;
171 } else
f2341e0a 172 log_unit_debug(u, "Unknown serialization key: %s", key);
a16e1123
LP
173
174 return 0;
175}
176
44a6b1b6 177_pure_ static UnitActiveState snapshot_active_state(Unit *u) {
41447faf
LP
178 assert(u);
179
180 return state_translation_table[SNAPSHOT(u)->state];
181}
182
44a6b1b6 183_pure_ static const char *snapshot_sub_state_to_string(Unit *u) {
41447faf
LP
184 assert(u);
185
a16e1123 186 return snapshot_state_to_string(SNAPSHOT(u)->state);
41447faf
LP
187}
188
718db961 189int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) {
a190eeb8 190 _cleanup_free_ char *n = NULL;
a16e1123 191 Unit *other, *u = NULL;
a190eeb8 192 Iterator i;
41447faf 193 int r;
a16e1123 194 const char *k;
41447faf
LP
195
196 assert(m);
197 assert(_s);
198
199 if (name) {
7410616c 200 if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
718db961 201 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
41447faf 202
7410616c 203 if (!endswith(name, ".snapshot"))
718db961 204 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
41447faf 205
718db961 206 if (manager_get_unit(m, name))
7cabba07 207 return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
41447faf
LP
208
209 } else {
210
211 for (;;) {
212 if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
213 return -ENOMEM;
214
ebec5783
ZJS
215 if (!manager_get_unit(m, n)) {
216 name = n;
41447faf 217 break;
ebec5783 218 }
41447faf
LP
219
220 free(n);
a190eeb8 221 n = NULL;
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
a16e1123
LP
276static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
277 [SNAPSHOT_DEAD] = "dead",
278 [SNAPSHOT_ACTIVE] = "active"
279};
280
281DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
282
87f0e418 283const UnitVTable snapshot_vtable = {
7d17cfbc 284 .object_size = sizeof(Snapshot),
5cb5a6ff 285
41447faf
LP
286 .no_alias = true,
287 .no_instances = true,
701cc384 288 .no_gc = true,
41447faf 289
7a6000a6 290 .init = snapshot_init,
6ec1117a 291 .load = snapshot_load,
718db961 292
a16e1123 293 .coldplug = snapshot_coldplug,
41447faf
LP
294
295 .dump = snapshot_dump,
296
297 .start = snapshot_start,
298 .stop = snapshot_stop,
299
a16e1123
LP
300 .serialize = snapshot_serialize,
301 .deserialize_item = snapshot_deserialize_item,
302
41447faf
LP
303 .active_state = snapshot_active_state,
304 .sub_state_to_string = snapshot_sub_state_to_string,
5cb5a6ff 305
c4e2ceae 306 .bus_interface = "org.freedesktop.systemd1.Snapshot",
718db961 307 .bus_vtable = bus_snapshot_vtable
5cb5a6ff 308};