From d90d76ff5e5a969f04ced0794753b5bfd59b1a4b Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Wed, 1 Jun 2022 13:14:15 +0200 Subject: [PATCH] Implement generic plugin script support Instead of hardcoding calls to specific scripts, just read the content of /usr/lib/snapper/plugins and execute all scripts that start with a digit. Implemented for create_snapshot, modify_snapshot, delete_snapshot, and set_default_snapshot for a start. --- doc/snapper.xml.in | 35 +++++++++++++++++++++++++++++++++++ snapper/Btrfs.cc | 3 +++ snapper/Hooks.cc | 45 ++++++++++++++++++++++++++++++++++++++++++--- snapper/Hooks.h | 8 +++++--- snapper/Snapshot.cc | 6 +++--- 5 files changed, 88 insertions(+), 9 deletions(-) diff --git a/doc/snapper.xml.in b/doc/snapper.xml.in index d44b3ea1..c9d1aa3b 100644 --- a/doc/snapper.xml.in +++ b/doc/snapper.xml.in @@ -839,6 +839,41 @@ snapper-configs5. + + PLUGINS + snapper can execute external scripts after certain actions. Scripts + have to be placed in /usr/lib/snapper/plugins. + The name has to start with a digit, execution order is alphabetical. + The first argument of a script is the action snapper executed. The + following actions are defined: + + + + + Executed when a new snapshot gets created + + + + + + Executed when a snapshot is removed + + + + + + Executed when a snapshot gets modified + + + + + + Executed when the default snapshot gets changed + + + + + FILES diff --git a/snapper/Btrfs.cc b/snapper/Btrfs.cc index 02bf167f..5dc1e267 100644 --- a/snapper/Btrfs.cc +++ b/snapper/Btrfs.cc @@ -51,6 +51,7 @@ #include "snapper/Btrfs.h" #include "snapper/BtrfsUtils.h" #include "snapper/File.h" +#include "snapper/Hooks.h" #include "snapper/Snapper.h" #include "snapper/SnapperTmpl.h" #include "snapper/SnapperDefines.h" @@ -1530,6 +1531,8 @@ namespace snapper SDir snapshot_dir = openSnapshotDir(num); subvolid_t id = get_id(snapshot_dir.fd()); set_default_id(general_dir.fd(), id); + + Hooks::set_default_snapshot(subvolume, this, num); } } catch (const runtime_error& e) diff --git a/snapper/Hooks.cc b/snapper/Hooks.cc index abd9e30d..54dec216 100644 --- a/snapper/Hooks.cc +++ b/snapper/Hooks.cc @@ -22,14 +22,45 @@ #include "config.h" +#include + +#include + +#include "snapper/FileUtils.h" #include "snapper/Hooks.h" #include "snapper/SystemCmd.h" +#include "snapper/Log.h" namespace snapper { using namespace std; + static bool + _plugins_filter_entries(unsigned char type, const char* name) + { + // must start with digit + if (*name >= '0' && *name <= '9') + return true; + return false; + } + + void + Hooks::run_scripts(const list& args) + { + SDir dir("/usr/lib/snapper/plugins"); + + vector scripts = dir.entries(_plugins_filter_entries); + std::sort(scripts.begin(), scripts.end()); + for (const string& script : scripts) + { + string cmdln = dir.fullname(script); + for (const string& arg : args) { + cmdln += " " + quote(arg); + } + SystemCmd cmd(cmdln); + } + } void Hooks::create_config(const string& subvolume, const Filesystem* filesystem) @@ -46,25 +77,33 @@ namespace snapper void - Hooks::create_snapshot(const string& subvolume, const Filesystem* filesystem) + Hooks::create_snapshot(const string& subvolume, const Filesystem* filesystem, const Snapshot& snapshot) { grub(subvolume, filesystem, "--refresh"); + run_scripts(std::list({"create-snapshot", subvolume, std::to_string(snapshot.getNum())})); } void - Hooks::modify_snapshot(const string& subvolume, const Filesystem* filesystem) + Hooks::modify_snapshot(const string& subvolume, const Filesystem* filesystem, const Snapshot& snapshot) { grub(subvolume, filesystem, "--refresh"); + run_scripts(std::list({"modify-snapshot", subvolume, std::to_string(snapshot.getNum())})); } void - Hooks::delete_snapshot(const string& subvolume, const Filesystem* filesystem) + Hooks::delete_snapshot(const string& subvolume, const Filesystem* filesystem, const Snapshot& snapshot) { grub(subvolume, filesystem, "--refresh"); + run_scripts(std::list({"delete-snapshot", subvolume, std::to_string(snapshot.getNum())})); } + void + Hooks::set_default_snapshot(const string& subvolume, const Filesystem* filesystem, unsigned int num) + { + run_scripts(std::list({"set-default-snapshot", subvolume, std::to_string(num)})); + } void Hooks::grub(const string& subvolume, const Filesystem* filesystem, const char* option) diff --git a/snapper/Hooks.h b/snapper/Hooks.h index befb274a..a81fa31c 100644 --- a/snapper/Hooks.h +++ b/snapper/Hooks.h @@ -37,12 +37,14 @@ namespace snapper { public: + static void run_scripts(const list& args); static void create_config(const string& subvolume, const Filesystem* filesystem); static void delete_config(const string& subvolume, const Filesystem* filesystem); - static void create_snapshot(const string& subvolume, const Filesystem* filesystem); - static void modify_snapshot(const string& subvolume, const Filesystem* filesystem); - static void delete_snapshot(const string& subvolume, const Filesystem* filesystem); + static void create_snapshot(const string& subvolume, const Filesystem* filesystem, const Snapshot& snapshot); + static void modify_snapshot(const string& subvolume, const Filesystem* filesystem, const Snapshot& snapshot); + static void delete_snapshot(const string& subvolume, const Filesystem* filesystem, const Snapshot& snapshot); + static void set_default_snapshot(const string& subvolume, const Filesystem* filesystem, unsigned int num); static void rollback(const string& old_root, const string& new_root); diff --git a/snapper/Snapshot.cc b/snapper/Snapshot.cc index d9c01ac6..384701a2 100644 --- a/snapper/Snapshot.cc +++ b/snapper/Snapshot.cc @@ -733,7 +733,7 @@ namespace snapper SN_RETHROW(e); } - Hooks::create_snapshot(snapper->subvolumeDir(), snapper->getFilesystem()); + Hooks::create_snapshot(snapper->subvolumeDir(), snapper->getFilesystem(), snapshot); return entries.insert(entries.end(), snapshot); } @@ -753,7 +753,7 @@ namespace snapper snapshot->writeInfo(); - Hooks::modify_snapshot(snapper->subvolumeDir(), snapper->getFilesystem()); + Hooks::modify_snapshot(snapper->subvolumeDir(), snapper->getFilesystem(), *snapshot); } @@ -794,7 +794,7 @@ namespace snapper entries.erase(snapshot); - Hooks::delete_snapshot(snapper->subvolumeDir(), snapper->getFilesystem()); + Hooks::delete_snapshot(snapper->subvolumeDir(), snapper->getFilesystem(), *snapshot); } -- 2.47.3