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-common-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_unit_debug(UNIT(s
), "Changed %s -> %s", snapshot_state_to_string(old_state
), snapshot_state_to_string(state
));
56 unit_notify(UNIT(s
), state_translation_table
[old_state
], state_translation_table
[state
], true);
59 static int snapshot_load(Unit
*u
) {
60 Snapshot
*s
= SNAPSHOT(u
);
63 assert(u
->load_state
== UNIT_STUB
);
65 /* Make sure that only snapshots created via snapshot_create()
67 if (!u
->transient
&& UNIT(s
)->manager
->n_reloading
<= 0)
70 u
->load_state
= UNIT_LOADED
;
74 static int snapshot_coldplug(Unit
*u
) {
75 Snapshot
*s
= SNAPSHOT(u
);
78 assert(s
->state
== SNAPSHOT_DEAD
);
80 if (s
->deserialized_state
!= s
->state
)
81 snapshot_set_state(s
, s
->deserialized_state
);
86 static void snapshot_dump(Unit
*u
, FILE *f
, const char *prefix
) {
87 Snapshot
*s
= SNAPSHOT(u
);
93 "%sSnapshot State: %s\n"
95 prefix
, snapshot_state_to_string(s
->state
),
96 prefix
, yes_no(s
->cleanup
));
99 static int snapshot_start(Unit
*u
) {
100 Snapshot
*s
= SNAPSHOT(u
);
103 assert(s
->state
== SNAPSHOT_DEAD
);
105 snapshot_set_state(s
, SNAPSHOT_ACTIVE
);
108 unit_add_to_cleanup_queue(u
);
113 static int snapshot_stop(Unit
*u
) {
114 Snapshot
*s
= SNAPSHOT(u
);
117 assert(s
->state
== SNAPSHOT_ACTIVE
);
119 snapshot_set_state(s
, SNAPSHOT_DEAD
);
123 static int snapshot_serialize(Unit
*u
, FILE *f
, FDSet
*fds
) {
124 Snapshot
*s
= SNAPSHOT(u
);
132 unit_serialize_item(u
, f
, "state", snapshot_state_to_string(s
->state
));
133 unit_serialize_item(u
, f
, "cleanup", yes_no(s
->cleanup
));
134 SET_FOREACH(other
, u
->dependencies
[UNIT_WANTS
], i
)
135 unit_serialize_item(u
, f
, "wants", other
->id
);
140 static int snapshot_deserialize_item(Unit
*u
, const char *key
, const char *value
, FDSet
*fds
) {
141 Snapshot
*s
= SNAPSHOT(u
);
149 if (streq(key
, "state")) {
152 state
= snapshot_state_from_string(value
);
154 log_unit_debug(u
, "Failed to parse state value: %s", value
);
156 s
->deserialized_state
= state
;
158 } else if (streq(key
, "cleanup")) {
160 r
= parse_boolean(value
);
162 log_unit_debug(u
, "Failed to parse cleanup value: %s", value
);
166 } else if (streq(key
, "wants")) {
168 r
= unit_add_two_dependencies_by_name(u
, UNIT_AFTER
, UNIT_WANTS
, value
, NULL
, true);
172 log_unit_debug(u
, "Unknown serialization key: %s", key
);
177 _pure_
static UnitActiveState
snapshot_active_state(Unit
*u
) {
180 return state_translation_table
[SNAPSHOT(u
)->state
];
183 _pure_
static const char *snapshot_sub_state_to_string(Unit
*u
) {
186 return snapshot_state_to_string(SNAPSHOT(u
)->state
);
189 int snapshot_create(Manager
*m
, const char *name
, bool cleanup
, sd_bus_error
*e
, Snapshot
**_s
) {
190 _cleanup_free_
char *n
= NULL
;
191 Unit
*other
, *u
= NULL
;
200 if (!unit_name_is_valid(name
, UNIT_NAME_PLAIN
))
201 return sd_bus_error_setf(e
, SD_BUS_ERROR_INVALID_ARGS
, "Unit name %s is not valid.", name
);
203 if (!endswith(name
, ".snapshot"))
204 return sd_bus_error_setf(e
, SD_BUS_ERROR_INVALID_ARGS
, "Unit name %s lacks snapshot suffix.", name
);
206 if (manager_get_unit(m
, name
))
207 return sd_bus_error_setf(e
, BUS_ERROR_UNIT_EXISTS
, "Snapshot %s exists already.", name
);
212 if (asprintf(&n
, "snapshot-%u.snapshot", ++ m
->n_snapshots
) < 0)
215 if (!manager_get_unit(m
, n
)) {
225 r
= manager_load_unit_prepare(m
, name
, NULL
, e
, &u
);
230 manager_dispatch_load_queue(m
);
231 assert(u
->load_state
== UNIT_LOADED
);
233 HASHMAP_FOREACH_KEY(other
, k
, m
->units
, i
) {
235 if (other
->ignore_on_snapshot
||
242 if (UNIT_VTABLE(other
)->check_snapshot
)
243 if (!UNIT_VTABLE(other
)->check_snapshot(other
))
246 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other
)))
249 r
= unit_add_two_dependencies(u
, UNIT_AFTER
, UNIT_WANTS
, other
, true);
254 SNAPSHOT(u
)->cleanup
= cleanup
;
257 log_unit_info(u
, "Created snapshot.");
263 unit_add_to_cleanup_queue(u
);
268 void snapshot_remove(Snapshot
*s
) {
271 log_unit_info(UNIT(s
), "Removing snapshot.");
273 unit_add_to_cleanup_queue(UNIT(s
));
276 static const char* const snapshot_state_table
[_SNAPSHOT_STATE_MAX
] = {
277 [SNAPSHOT_DEAD
] = "dead",
278 [SNAPSHOT_ACTIVE
] = "active"
281 DEFINE_STRING_TABLE_LOOKUP(snapshot_state
, SnapshotState
);
283 const UnitVTable snapshot_vtable
= {
284 .object_size
= sizeof(Snapshot
),
287 .no_instances
= true,
290 .init
= snapshot_init
,
291 .load
= snapshot_load
,
293 .coldplug
= snapshot_coldplug
,
295 .dump
= snapshot_dump
,
297 .start
= snapshot_start
,
298 .stop
= snapshot_stop
,
300 .serialize
= snapshot_serialize
,
301 .deserialize_item
= snapshot_deserialize_item
,
303 .active_state
= snapshot_active_state
,
304 .sub_state_to_string
= snapshot_sub_state_to_string
,
306 .bus_interface
= "org.freedesktop.systemd1.Snapshot",
307 .bus_vtable
= bus_snapshot_vtable