chiark / gitweb /
dbus: properly name StartupTimestamp property
[elogind.git] / src / snapshot.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
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
22 #include <errno.h>
23
24 #include "unit.h"
25 #include "snapshot.h"
26 #include "unit-name.h"
27 #include "dbus-snapshot.h"
28
29 static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
30         [SNAPSHOT_DEAD] = UNIT_INACTIVE,
31         [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
32 };
33
34 static void snapshot_set_state(Snapshot *s, SnapshotState state) {
35         SnapshotState old_state;
36         assert(s);
37
38         old_state = s->state;
39         s->state = state;
40
41         if (state != old_state)
42                 log_debug("%s changed %s -> %s",
43                           s->meta.id,
44                           snapshot_state_to_string(old_state),
45                           snapshot_state_to_string(state));
46
47         unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
48 }
49
50 static int snapshot_load(Unit *u) {
51         Snapshot *s = SNAPSHOT(u);
52
53         assert(u);
54         assert(u->meta.load_state == UNIT_STUB);
55
56         /* Make sure that only snapshots created via snapshot_create()
57          * can be loaded */
58         if (!s->by_snapshot_create)
59                 return -ENOENT;
60
61         u->meta.load_state = UNIT_LOADED;
62         return 0;
63 }
64
65 static int snapshot_coldplug(Unit *u) {
66         Snapshot *s = SNAPSHOT(u);
67
68         assert(s);
69         assert(s->state == SNAPSHOT_DEAD);
70
71         if (s->deserialized_state != s->state)
72                 snapshot_set_state(s, s->deserialized_state);
73
74         return 0;
75 }
76
77 static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
78         Snapshot *s = SNAPSHOT(u);
79
80         assert(s);
81         assert(f);
82
83         fprintf(f,
84                 "%sSnapshot State: %s\n"
85                 "%sClean Up: %s\n",
86                 prefix, snapshot_state_to_string(s->state),
87                 prefix, yes_no(s->cleanup));
88 }
89
90 static int snapshot_start(Unit *u) {
91         Snapshot *s = SNAPSHOT(u);
92
93         assert(s);
94         assert(s->state == SNAPSHOT_DEAD);
95
96         snapshot_set_state(s, SNAPSHOT_ACTIVE);
97
98         if (s->cleanup)
99                 unit_add_to_cleanup_queue(u);
100
101         return 0;
102 }
103
104 static int snapshot_stop(Unit *u) {
105         Snapshot *s = SNAPSHOT(u);
106
107         assert(s);
108         assert(s->state == SNAPSHOT_ACTIVE);
109
110         snapshot_set_state(s, SNAPSHOT_DEAD);
111         return 0;
112 }
113
114 static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
115         Snapshot *s = SNAPSHOT(u);
116         Unit *other;
117         Iterator i;
118
119         assert(s);
120         assert(f);
121         assert(fds);
122
123         unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
124         unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
125         SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i)
126                 unit_serialize_item(u, f, "wants", other->meta.id);
127
128         return 0;
129 }
130
131 static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
132         Snapshot *s = SNAPSHOT(u);
133         int r;
134
135         assert(u);
136         assert(key);
137         assert(value);
138         assert(fds);
139
140         if (streq(key, "state")) {
141                 SnapshotState state;
142
143                 if ((state = snapshot_state_from_string(value)) < 0)
144                         log_debug("Failed to parse state value %s", value);
145                 else
146                         s->deserialized_state = state;
147
148         } else if (streq(key, "cleanup")) {
149
150                 if ((r = parse_boolean(value)) < 0)
151                         log_debug("Failed to parse cleanup value %s", value);
152                 else
153                         s->cleanup = r;
154
155         } else if (streq(key, "wants")) {
156
157                 if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true)) < 0)
158                         return r;
159         } else
160                 log_debug("Unknown serialization key '%s'", key);
161
162         return 0;
163 }
164
165 static UnitActiveState snapshot_active_state(Unit *u) {
166         assert(u);
167
168         return state_translation_table[SNAPSHOT(u)->state];
169 }
170
171 static const char *snapshot_sub_state_to_string(Unit *u) {
172         assert(u);
173
174         return snapshot_state_to_string(SNAPSHOT(u)->state);
175 }
176
177 int snapshot_create(Manager *m, const char *name, bool cleanup, Snapshot **_s) {
178         Iterator i;
179         Unit *other, *u = NULL;
180         char *n = NULL;
181         int r;
182         const char *k;
183
184         assert(m);
185         assert(_s);
186
187         if (name) {
188                 if (!unit_name_is_valid(name))
189                         return -EINVAL;
190
191                 if (unit_name_to_type(name) != UNIT_SNAPSHOT)
192                         return -EINVAL;
193
194                 if (manager_get_unit(m, name))
195                         return -EEXIST;
196
197         } else {
198
199                 for (;;) {
200                         if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
201                                 return -ENOMEM;
202
203                         if (!manager_get_unit(m, n))
204                                 break;
205
206                         free(n);
207                 }
208
209                 name = n;
210         }
211
212         r = manager_load_unit_prepare(m, name, NULL, &u);
213         free(n);
214
215         if (r < 0)
216                 goto fail;
217
218         SNAPSHOT(u)->by_snapshot_create = true;
219         manager_dispatch_load_queue(m);
220         assert(u->meta.load_state == UNIT_LOADED);
221
222         HASHMAP_FOREACH_KEY(other, k, m->units, i) {
223
224                 if (UNIT_VTABLE(other)->no_snapshots)
225                         continue;
226
227                 if (k != other->meta.id)
228                         continue;
229
230                 if (UNIT_VTABLE(other)->check_snapshot)
231                         if (!UNIT_VTABLE(other)->check_snapshot(other))
232                             continue;
233
234                 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
235                         continue;
236
237                 if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true)) < 0)
238                         goto fail;
239         }
240
241         SNAPSHOT(u)->cleanup = cleanup;
242         *_s = SNAPSHOT(u);
243
244         return 0;
245
246 fail:
247         if (u)
248                 unit_add_to_cleanup_queue(u);
249
250         return r;
251 }
252
253 void snapshot_remove(Snapshot *s) {
254         assert(s);
255
256         unit_add_to_cleanup_queue(UNIT(s));
257 }
258
259 static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
260         [SNAPSHOT_DEAD] = "dead",
261         [SNAPSHOT_ACTIVE] = "active"
262 };
263
264 DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
265
266 const UnitVTable snapshot_vtable = {
267         .suffix = ".snapshot",
268
269         .no_alias = true,
270         .no_instances = true,
271         .no_snapshots = true,
272         .no_gc = true,
273
274         .load = snapshot_load,
275         .coldplug = snapshot_coldplug,
276
277         .dump = snapshot_dump,
278
279         .start = snapshot_start,
280         .stop = snapshot_stop,
281
282         .serialize = snapshot_serialize,
283         .deserialize_item = snapshot_deserialize_item,
284
285         .active_state = snapshot_active_state,
286         .sub_state_to_string = snapshot_sub_state_to_string,
287
288         .bus_message_handler = bus_snapshot_message_handler
289 };