diff options
-rw-r--r-- | device.c | 1 | ||||
-rw-r--r-- | manager.h | 3 | ||||
-rw-r--r-- | snapshot.c | 161 | ||||
-rw-r--r-- | snapshot.h | 10 | ||||
-rw-r--r-- | systemctl.vala | 16 | ||||
-rw-r--r-- | systemd-interfaces.vala | 2 | ||||
-rw-r--r-- | unit.h | 5 |
7 files changed, 188 insertions, 10 deletions
@@ -451,6 +451,7 @@ const UnitVTable device_vtable = { .no_requires = true, .no_instances = true, + .no_snapshots = true, .init = device_init, .load = unit_load_fragment_and_dropin_optional, @@ -190,6 +190,9 @@ struct Manager { /* Data specific to the Automount subsystem */ int dev_autofs_fd; + + /* Data specific to the Snapshot subsystem */ + unsigned n_snapshots; }; int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **m); diff --git a/snapshot.c b/snapshot.c index 0039ca4610..1fc0ab8164 100644 --- a/snapshot.c +++ b/snapshot.c @@ -19,25 +19,176 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <errno.h> + #include "unit.h" #include "snapshot.h" +#include "unit-name.h" +#include "dbus-snapshot.h" + +static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = { + [SNAPSHOT_DEAD] = UNIT_INACTIVE, + [SNAPSHOT_ACTIVE] = UNIT_ACTIVE +}; + +static const char* const state_string_table[_SNAPSHOT_STATE_MAX] = { + [SNAPSHOT_DEAD] = "dead", + [SNAPSHOT_ACTIVE] = "active" +}; + +static int snapshot_load(Unit *u) { + Iterator i; + Unit *other; + int r; + + assert(u); + + HASHMAP_FOREACH(other, u->meta.manager->units, i) { -static void snapshot_done(Unit *u) { + if (UNIT_VTABLE(other)->no_snapshots) + continue; + + if ((r = unit_add_dependency(u, UNIT_REQUIRES, other)) < 0) + return r; + + if ((r = unit_add_dependency(u, UNIT_AFTER, other)) < 0) + return r; + } + + u->meta.load_state = UNIT_LOADED; + + return 0; +} + +static void snapshot_dump(Unit *u, FILE *f, const char *prefix) { Snapshot *s = SNAPSHOT(u); assert(s); + assert(f); - /* Nothing here for now */ + fprintf(f, + "%sSnapshot State: %s\n" + "%sClean Up: %s\n", + prefix, state_string_table[s->state], + prefix, yes_no(s->cleanup)); +} + +static void snapshot_set_state(Snapshot *s, SnapshotState state) { + SnapshotState old_state; + assert(s); + + old_state = s->state; + s->state = state; + + if (state != old_state) + log_debug("%s changed %s → %s", UNIT(s)->meta.id, state_string_table[old_state], state_string_table[state]); + + unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]); +} + +static int snapshot_start(Unit *u) { + Snapshot *s = SNAPSHOT(u); + + assert(s); + assert(s->state == SNAPSHOT_DEAD); + + snapshot_set_state(s, SNAPSHOT_ACTIVE); + + if (s->cleanup) + unit_add_to_cleanup_queue(u); + + return 0; +} + +static int snapshot_stop(Unit *u) { + Snapshot *s = SNAPSHOT(u); + + assert(s); + assert(s->state == SNAPSHOT_ACTIVE); + + snapshot_set_state(s, SNAPSHOT_DEAD); + return 0; } static UnitActiveState snapshot_active_state(Unit *u) { - return SNAPSHOT(u)->state == SNAPSHOT_DEAD ? UNIT_INACTIVE : UNIT_ACTIVE; + assert(u); + + return state_translation_table[SNAPSHOT(u)->state]; +} + +static const char *snapshot_sub_state_to_string(Unit *u) { + assert(u); + + return state_string_table[SNAPSHOT(u)->state]; +} + +int snapshot_create(Manager *m, const char *name, bool cleanup, Snapshot **_s) { + Unit *u; + char *n = NULL; + int r; + + assert(m); + assert(_s); + + if (name) { + if (!unit_name_is_valid(name)) + return -EINVAL; + + if (unit_name_to_type(name) != UNIT_SNAPSHOT) + return -EINVAL; + + if (manager_get_unit(m, name)) + return -EEXIST; + + } else { + + for (;;) { + if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0) + return -ENOMEM; + + if (!manager_get_unit(m, n)) + break; + + free(n); + } + + name = n; + } + + r = manager_load_unit(m, name, NULL, &u); + free(n); + + if (r < 0) + return r; + + SNAPSHOT(u)->cleanup = cleanup; + *_s = SNAPSHOT(u); + + return 0; +} + +void snapshot_remove(Snapshot *s) { + assert(s); + + unit_add_to_cleanup_queue(UNIT(s)); } const UnitVTable snapshot_vtable = { .suffix = ".snapshot", - .done = snapshot_done, + .no_alias = true, + .no_instances = true, + .no_snapshots = true, + + .load = snapshot_load, + + .dump = snapshot_dump, + + .start = snapshot_start, + .stop = snapshot_stop, + + .active_state = snapshot_active_state, + .sub_state_to_string = snapshot_sub_state_to_string, - .active_state = snapshot_active_state + .bus_message_handler = bus_snapshot_message_handler }; diff --git a/snapshot.h b/snapshot.h index cde5a13857..78bcafa448 100644 --- a/snapshot.h +++ b/snapshot.h @@ -28,16 +28,22 @@ typedef struct Snapshot Snapshot; typedef enum SnapshotState { SNAPSHOT_DEAD, - SNAPSHOT_ACTIVE + SNAPSHOT_ACTIVE, + _SNAPSHOT_STATE_MAX, + _SNAPSHOT_STATE_INVALID = -1 } SnapshotState; struct Snapshot { Meta meta; SnapshotState state; - bool cleanup:1; + + bool cleanup; }; extern const UnitVTable snapshot_vtable; +int snapshot_create(Manager *m, const char *name, bool cleanup, Snapshot **s); +void snapshot_remove(Snapshot *s); + #endif diff --git a/systemctl.vala b/systemctl.vala index 8f16b90482..4de856e756 100644 --- a/systemctl.vala +++ b/systemctl.vala @@ -83,7 +83,9 @@ int main (string[] args) { " stop [NAME...] Stop on or more units\n" + " restart [NAME...] Restart on or more units\n" + " reload [NAME...] Reload on or more units\n" + - " monitor Monitor unit/job changes\n"); + " monitor Monitor unit/job changes\n" + + " dump Dump servier status\n" + + " snapshot [NAME] Create a snapshot\n"); try { context.parse(ref args); @@ -224,7 +226,17 @@ int main (string[] args) { } else if (args[1] == "dump") stdout.puts(manager.dump()); - else { + else if (args[1] == "snapshot") { + + ObjectPath p = manager.create_snapshot(args.length > 2 ? args[2] : ""); + + Unit u = bus.get_object( + "org.freedesktop.systemd1", + p, + "org.freedesktop.systemd1.Unit") as Unit; + + stdout.printf("%s\n", u.id); + } else { stderr.printf("Unknown command %s.\n", args[1]); return 1; } diff --git a/systemd-interfaces.vala b/systemd-interfaces.vala index 069c5a1aa2..dae0648c64 100644 --- a/systemd-interfaces.vala +++ b/systemd-interfaces.vala @@ -57,6 +57,8 @@ public interface Manager : DBus.Object { public abstract string dump() throws DBus.Error; + public abstract ObjectPath create_snapshot(string name, bool cleanup = false) throws DBus.Error; + public abstract signal void unit_new(string id, ObjectPath path); public abstract signal void unit_removed(string id, ObjectPath path); public abstract signal void job_new(uint32 id, ObjectPath path); @@ -59,8 +59,8 @@ enum UnitType { UNIT_DEVICE, UNIT_MOUNT, UNIT_AUTOMOUNT, - UNIT_TIMER, UNIT_SNAPSHOT, + UNIT_TIMER, _UNIT_TYPE_MAX, _UNIT_TYPE_INVALID = -1 }; @@ -209,6 +209,9 @@ struct UnitVTable { /* Instances make no sense for this type */ bool no_instances:1; + /* Execlude this type from snapshots */ + bool no_snapshots:1; + /* This should reset all type-specific variables. This should * not allocate memory, and is either called with 0 * initialized data, or with data left from done() */ |