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