1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
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
11 (at your option) any later version.
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 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "unit-name.h"
27 #include "dbus-snapshot.h"
28 #include "bus-errors.h"
30 static const UnitActiveState state_translation_table
[_SNAPSHOT_STATE_MAX
] = {
31 [SNAPSHOT_DEAD
] = UNIT_INACTIVE
,
32 [SNAPSHOT_ACTIVE
] = UNIT_ACTIVE
35 static void snapshot_init(Unit
*u
) {
36 Snapshot
*s
= SNAPSHOT(u
);
39 assert(UNIT(s
)->load_state
== UNIT_STUB
);
41 UNIT(s
)->ignore_on_isolate
= true;
42 UNIT(s
)->ignore_on_snapshot
= true;
43 UNIT(s
)->allow_isolate
= true;
46 static void snapshot_set_state(Snapshot
*s
, SnapshotState state
) {
47 SnapshotState old_state
;
53 if (state
!= old_state
)
54 log_debug("%s changed %s -> %s",
56 snapshot_state_to_string(old_state
),
57 snapshot_state_to_string(state
));
59 unit_notify(UNIT(s
), state_translation_table
[old_state
], state_translation_table
[state
], true);
62 static int snapshot_load(Unit
*u
) {
63 Snapshot
*s
= SNAPSHOT(u
);
66 assert(u
->load_state
== UNIT_STUB
);
68 /* Make sure that only snapshots created via snapshot_create()
70 if (!u
->transient
&& UNIT(s
)->manager
->n_reloading
<= 0)
73 u
->load_state
= UNIT_LOADED
;
77 static int snapshot_coldplug(Unit
*u
) {
78 Snapshot
*s
= SNAPSHOT(u
);
81 assert(s
->state
== SNAPSHOT_DEAD
);
83 if (s
->deserialized_state
!= s
->state
)
84 snapshot_set_state(s
, s
->deserialized_state
);
89 static void snapshot_dump(Unit
*u
, FILE *f
, const char *prefix
) {
90 Snapshot
*s
= SNAPSHOT(u
);
96 "%sSnapshot State: %s\n"
98 prefix
, snapshot_state_to_string(s
->state
),
99 prefix
, yes_no(s
->cleanup
));
102 static int snapshot_start(Unit
*u
) {
103 Snapshot
*s
= SNAPSHOT(u
);
106 assert(s
->state
== SNAPSHOT_DEAD
);
108 snapshot_set_state(s
, SNAPSHOT_ACTIVE
);
111 unit_add_to_cleanup_queue(u
);
116 static int snapshot_stop(Unit
*u
) {
117 Snapshot
*s
= SNAPSHOT(u
);
120 assert(s
->state
== SNAPSHOT_ACTIVE
);
122 snapshot_set_state(s
, SNAPSHOT_DEAD
);
126 static int snapshot_serialize(Unit
*u
, FILE *f
, FDSet
*fds
) {
127 Snapshot
*s
= SNAPSHOT(u
);
135 unit_serialize_item(u
, f
, "state", snapshot_state_to_string(s
->state
));
136 unit_serialize_item(u
, f
, "cleanup", yes_no(s
->cleanup
));
137 SET_FOREACH(other
, u
->dependencies
[UNIT_WANTS
], i
)
138 unit_serialize_item(u
, f
, "wants", other
->id
);
143 static int snapshot_deserialize_item(Unit
*u
, const char *key
, const char *value
, FDSet
*fds
) {
144 Snapshot
*s
= SNAPSHOT(u
);
152 if (streq(key
, "state")) {
155 state
= snapshot_state_from_string(value
);
157 log_debug("Failed to parse state value %s", value
);
159 s
->deserialized_state
= state
;
161 } else if (streq(key
, "cleanup")) {
163 r
= parse_boolean(value
);
165 log_debug("Failed to parse cleanup value %s", value
);
169 } else if (streq(key
, "wants")) {
171 r
= unit_add_two_dependencies_by_name(u
, UNIT_AFTER
, UNIT_WANTS
, value
, NULL
, true);
175 log_debug("Unknown serialization key '%s'", key
);
180 _pure_
static UnitActiveState
snapshot_active_state(Unit
*u
) {
183 return state_translation_table
[SNAPSHOT(u
)->state
];
186 _pure_
static const char *snapshot_sub_state_to_string(Unit
*u
) {
189 return snapshot_state_to_string(SNAPSHOT(u
)->state
);
192 int snapshot_create(Manager
*m
, const char *name
, bool cleanup
, DBusError
*e
, Snapshot
**_s
) {
193 _cleanup_free_
char *n
= NULL
;
194 Unit
*other
, *u
= NULL
;
203 if (!unit_name_is_valid(name
, false)) {
204 dbus_set_error(e
, BUS_ERROR_INVALID_NAME
, "Unit name %s is not valid.", name
);
208 if (unit_name_to_type(name
) != UNIT_SNAPSHOT
) {
209 dbus_set_error(e
, BUS_ERROR_UNIT_TYPE_MISMATCH
, "Unit name %s lacks snapshot suffix.", name
);
213 if (manager_get_unit(m
, name
)) {
214 dbus_set_error(e
, BUS_ERROR_UNIT_EXISTS
, "Snapshot %s exists already.", name
);
221 if (asprintf(&n
, "snapshot-%u.snapshot", ++ m
->n_snapshots
) < 0)
224 if (!manager_get_unit(m
, n
)) {
234 r
= manager_load_unit_prepare(m
, name
, NULL
, e
, &u
);
239 manager_dispatch_load_queue(m
);
240 assert(u
->load_state
== UNIT_LOADED
);
242 HASHMAP_FOREACH_KEY(other
, k
, m
->units
, i
) {
244 if (other
->ignore_on_snapshot
||
251 if (UNIT_VTABLE(other
)->check_snapshot
)
252 if (!UNIT_VTABLE(other
)->check_snapshot(other
))
255 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other
)))
258 r
= unit_add_two_dependencies(u
, UNIT_AFTER
, UNIT_WANTS
, other
, true);
263 SNAPSHOT(u
)->cleanup
= cleanup
;
270 unit_add_to_cleanup_queue(u
);
275 void snapshot_remove(Snapshot
*s
) {
278 unit_add_to_cleanup_queue(UNIT(s
));
281 static const char* const snapshot_state_table
[_SNAPSHOT_STATE_MAX
] = {
282 [SNAPSHOT_DEAD
] = "dead",
283 [SNAPSHOT_ACTIVE
] = "active"
286 DEFINE_STRING_TABLE_LOOKUP(snapshot_state
, SnapshotState
);
288 const UnitVTable snapshot_vtable
= {
289 .object_size
= sizeof(Snapshot
),
292 .no_instances
= true,
295 .init
= snapshot_init
,
297 .load
= snapshot_load
,
298 .coldplug
= snapshot_coldplug
,
300 .dump
= snapshot_dump
,
302 .start
= snapshot_start
,
303 .stop
= snapshot_stop
,
305 .serialize
= snapshot_serialize
,
306 .deserialize_item
= snapshot_deserialize_item
,
308 .active_state
= snapshot_active_state
,
309 .sub_state_to_string
= snapshot_sub_state_to_string
,
311 .bus_interface
= "org.freedesktop.systemd1.Snapshot",
312 .bus_message_handler
= bus_snapshot_message_handler