From: Arvin Schnell Date: Fri, 16 Dec 2016 12:17:38 +0000 (+0100) Subject: support option --no-dbus for all snapper commands (#299) X-Git-Tag: v0.4.0^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5d50934e12dc9a5b2f197cfcf367a14d1cc55c95;p=thirdparty%2Fsnapper.git support option --no-dbus for all snapper commands (#299) - make all snapper commands available with option --no-dbus by using new proxy classes --- diff --git a/LIBVERSION b/LIBVERSION index fd2a0186..fcdb2e10 100644 --- a/LIBVERSION +++ b/LIBVERSION @@ -1 +1 @@ -3.1.0 +4.0.0 diff --git a/VERSION b/VERSION index 1c09c74e..1d0ba9ea 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.3 +0.4.0 diff --git a/client/Makefile.am b/client/Makefile.am index c026e8b4..e8f9a5eb 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -13,6 +13,9 @@ snapper_SOURCES = \ types.cc types.h \ commands.cc commands.h \ cleanup.cc cleanup.h \ + proxy.cc proxy.h \ + proxy-dbus.cc proxy-dbus.h \ + proxy-lib.cc proxy-lib.h \ misc.cc misc.h \ errors.cc errors.h @@ -27,6 +30,9 @@ systemd_helper_SOURCES = \ types.cc types.h \ commands.cc commands.h \ cleanup.cc cleanup.h \ + proxy.cc proxy.h \ + proxy-dbus.cc proxy-dbus.h \ + proxy-lib.cc proxy-lib.h \ misc.cc misc.h \ errors.cc errors.h diff --git a/client/cleanup.cc b/client/cleanup.cc index cb1658d1..0dbfc031 100644 --- a/client/cleanup.cc +++ b/client/cleanup.cc @@ -21,35 +21,48 @@ */ +#include + +#include "dbus/DBusMessage.h" +#include "dbus/DBusConnection.h" +#include "snapper/SnapperTmpl.h" +#include "snapper/Snapper.h" + #include "utils/Range.h" #include "utils/equal-date.h" -#include "commands.h" +#include "cleanup.h" -#include using namespace std; struct Parameters { - Parameters(DBus::Connection& conn, const string& config_name); + Parameters(const ProxySnapper* snapper); virtual ~Parameters() {} virtual bool is_degenerated() const { return true; } - friend ostream& operator<<(ostream& s, const Parameters& parameters); - time_t min_age; double space_limit; + + template + void read(const ProxyConfig& config, const char* name, Type& value) + { + const map& raw = config.getAllValues(); + map::const_iterator pos = raw.find(name); + if (pos != raw.end()) + pos->second >> value; + } }; -Parameters::Parameters(DBus::Connection& conn, const string& config_name) +Parameters::Parameters(const ProxySnapper* snapper) : min_age(1800), space_limit(0.5) { - XConfigInfo ci = command_get_xconfig(conn, config_name); + ProxyConfig config = snapper->getConfig(); - ci.read("SPACE_LIMIT", space_limit); + read(config, "SPACE_LIMIT", space_limit); } @@ -65,8 +78,8 @@ class Cleaner { public: - Cleaner(DBus::Connection& conn, const string& config_name, bool verbose, const Parameters& parameters) - : conn(conn), config_name(config_name), verbose(verbose), parameters(parameters) {} + Cleaner(ProxySnapper* snapper, bool verbose, const Parameters& parameters) + : snapper(snapper), verbose(verbose), parameters(parameters) {} virtual ~Cleaner() {} @@ -74,54 +87,53 @@ public: protected: - virtual list calculate_candidates(Range::Value value) = 0; + virtual list calculate_candidates(ProxySnapshots& snapshots, + Range::Value value) = 0; struct younger_than { younger_than(time_t t) : t(t) {} - bool operator()(XSnapshots::const_iterator it) + bool operator()(ProxySnapshots::const_iterator it) { return it->getDate() > t; } const time_t t; }; - void filter(list& tmp) const; + void filter(ProxySnapshots& snapshots, list& tmp) const; // Removes snapshots younger than parameters.min_age from tmp - void filter_min_age(list& tmp) const; + void filter_min_age(ProxySnapshots& snapshots, list& tmp) const; // Removes pre and post snapshots from tmp that do have a corresponding // snapshot but which is not included in tmp. - void filter_pre_post(list& tmp) const; + void filter_pre_post(ProxySnapshots& snapshots, list& tmp) const; - void remove(const list& tmp); + void remove(const list& tmp); bool is_quota_aware() const; bool is_quota_satisfied() const; - void cleanup_quota_unaware(); - void cleanup_quota_aware(); + void cleanup_quota_unaware(ProxySnapshots& snapshots); + void cleanup_quota_aware(ProxySnapshots& snapshots); - DBus::Connection& conn; - const string& config_name; + ProxySnapper* snapper; bool verbose; const Parameters& parameters; - XSnapshots snapshots; }; void -Cleaner::filter(list& tmp) const +Cleaner::filter(ProxySnapshots& snapshots, list& tmp) const { - filter_min_age(tmp); - filter_pre_post(tmp); + filter_min_age(snapshots, tmp); + filter_pre_post(snapshots, tmp); } void -Cleaner::filter_min_age(list& tmp) const +Cleaner::filter_min_age(ProxySnapshots& snapshots, list& tmp) const { time_t now = time(NULL); tmp.remove_if(younger_than(now - parameters.min_age)); @@ -129,15 +141,15 @@ Cleaner::filter_min_age(list& tmp) const void -Cleaner::filter_pre_post(list& tmp) const +Cleaner::filter_pre_post(ProxySnapshots& snapshots, list& tmp) const { - list ret; + list ret; - for (list::iterator it1 = tmp.begin(); it1 != tmp.end(); ++it1) + for (list::iterator it1 = tmp.begin(); it1 != tmp.end(); ++it1) { if ((*it1)->getType() == PRE) { - XSnapshots::const_iterator it2 = snapshots.findPost(*it1); + ProxySnapshots::const_iterator it2 = snapshots.findPost(*it1); if (it2 != snapshots.end()) { if (find(tmp.begin(), tmp.end(), it2) == tmp.end()) @@ -147,7 +159,7 @@ Cleaner::filter_pre_post(list& tmp) const if ((*it1)->getType() == POST) { - XSnapshots::const_iterator it2 = snapshots.findPre(*it1); + ProxySnapshots::const_iterator it2 = snapshots.findPre(*it1); if (it2 != snapshots.end()) { if (find(tmp.begin(), tmp.end(), it2) == tmp.end()) @@ -163,12 +175,11 @@ Cleaner::filter_pre_post(list& tmp) const void -Cleaner::remove(const list& tmp) +Cleaner::remove(const list& tmp) { - for (list::const_iterator it = tmp.begin(); it != tmp.end(); ++it) + for (list::const_iterator it = tmp.begin(); it != tmp.end(); ++it) { - command_delete_xsnapshots(conn, config_name, { (*it)->getNum() }, verbose); - snapshots.erase(*it); + snapper->deleteSnapshots({ *it }, verbose); } } @@ -181,7 +192,7 @@ Cleaner::is_quota_aware() const try { - command_prepare_quota(conn, config_name); + snapper->prepareQuota(); } catch (const DBus::ErrorException& e) { @@ -195,6 +206,13 @@ Cleaner::is_quota_aware() const SN_RETHROW(e); } + catch (const QuotaException& e) + { + SN_CAUGHT(e); + + cerr << "quota not working (" << e.what() << ")" << endl; + return false; + } return true; } @@ -203,29 +221,29 @@ Cleaner::is_quota_aware() const bool Cleaner::is_quota_satisfied() const { - XQuotaData quota_data = command_query_quota(conn, config_name); + QuotaData quota_data = snapper->queryQuotaData(); return quota_data.used < parameters.space_limit * quota_data.size; } void -Cleaner::cleanup_quota_unaware() +Cleaner::cleanup_quota_unaware(ProxySnapshots& snapshots) { - list candidates = calculate_candidates(Range::MAX); + list candidates = calculate_candidates(snapshots, Range::MAX); - filter(candidates); + filter(snapshots, candidates); remove(candidates); } void -Cleaner::cleanup_quota_aware() +Cleaner::cleanup_quota_aware(ProxySnapshots& snapshots) { while (!is_quota_satisfied()) { - list candidates = calculate_candidates(Range::MIN); + list candidates = calculate_candidates(snapshots, Range::MIN); if (candidates.empty()) { // not enough candidates to satisfy quota @@ -237,11 +255,11 @@ Cleaner::cleanup_quota_aware() // snapshot candidate if the post snapshot is missing so simply // removing the first candidate is not possible. - for (list::iterator e = candidates.begin(); e != candidates.end(); ++e) + for (list::iterator e = candidates.begin(); e != candidates.end(); ++e) { - list tmp = list(candidates.begin(), next(e)); + list tmp = list(candidates.begin(), next(e)); - filter(tmp); + filter(snapshots, tmp); if (!tmp.empty()) { @@ -263,37 +281,35 @@ Cleaner::cleanup_quota_aware() void Cleaner::cleanup() { - snapshots = command_list_xsnapshots(conn, config_name); + ProxySnapshots& snapshots = snapper->getSnapshots(); - cleanup_quota_unaware(); + cleanup_quota_unaware(snapshots); if (is_quota_aware()) - cleanup_quota_aware(); + cleanup_quota_aware(snapshots); } struct NumberParameters : public Parameters { - NumberParameters(DBus::Connection& conn, const string& config_name); + NumberParameters(const ProxySnapper* snapper); bool is_degenerated() const; - friend ostream& operator<<(ostream& s, const NumberParameters& parameters); - Range limit; Range limit_important; }; -NumberParameters::NumberParameters(DBus::Connection& conn, const string& config_name) - : Parameters(conn, config_name), limit(50), limit_important(10) +NumberParameters::NumberParameters(const ProxySnapper* snapper) + : Parameters(snapper), limit(50), limit_important(10) { - XConfigInfo ci = command_get_xconfig(conn, config_name); + ProxyConfig config = snapper->getConfig(); - ci.read("NUMBER_MIN_AGE", min_age); + read(config, "NUMBER_MIN_AGE", min_age); - ci.read("NUMBER_LIMIT", limit); - ci.read("NUMBER_LIMIT_IMPORTANT", limit_important); + read(config, "NUMBER_LIMIT", limit); + read(config, "NUMBER_LIMIT_IMPORTANT", limit_important); } @@ -318,28 +334,27 @@ class NumberCleaner : public Cleaner public: - NumberCleaner(DBus::Connection& conn, const string& config_name, bool verbose, - const NumberParameters& parameters) - : Cleaner(conn, config_name, verbose, parameters) {} + NumberCleaner(ProxySnapper* snapper, bool verbose, const NumberParameters& parameters) + : Cleaner(snapper, verbose, parameters) {} private: bool - is_important(XSnapshots::const_iterator it1) + is_important(ProxySnapshots::const_iterator it1) { map::const_iterator it2 = it1->getUserdata().find("important"); return it2 != it1->getUserdata().end() && it2->second == "yes"; } - list - calculate_candidates(Range::Value value) + list + calculate_candidates(ProxySnapshots& snapshots, Range::Value value) override { const NumberParameters& parameters = dynamic_cast(Cleaner::parameters); - list ret; + list ret; - for (XSnapshots::iterator it = snapshots.begin(); it != snapshots.end(); ++it) + for (ProxySnapshots::iterator it = snapshots.begin(); it != snapshots.end(); ++it) { if (it->getCleanup() == "number") ret.push_front(it); @@ -348,7 +363,7 @@ private: size_t num = 0; size_t num_important = 0; - list::iterator it = ret.begin(); + list::iterator it = ret.begin(); while (it != ret.end()) { bool keep = false; @@ -378,17 +393,17 @@ private: void -do_cleanup_number(DBus::Connection& conn, const string& config_name, bool verbose) +do_cleanup_number(ProxySnapper* snapper, bool verbose) { - NumberParameters parameters(conn, config_name); - NumberCleaner cleaner(conn, config_name, verbose, parameters); + NumberParameters parameters(snapper); + NumberCleaner cleaner(snapper, verbose, parameters); cleaner.cleanup(); } struct TimelineParameters : public Parameters { - TimelineParameters(DBus::Connection& conn, const string& config_name); + TimelineParameters(const ProxySnapper* snapper); bool is_degenerated() const; @@ -400,19 +415,19 @@ struct TimelineParameters : public Parameters }; -TimelineParameters::TimelineParameters(DBus::Connection& conn, const string& config_name) - : Parameters(conn, config_name), limit_hourly(10), limit_daily(10), limit_monthly(10), +TimelineParameters::TimelineParameters(const ProxySnapper* snapper) + : Parameters(snapper), limit_hourly(10), limit_daily(10), limit_monthly(10), limit_weekly(0), limit_yearly(10) { - XConfigInfo ci = command_get_xconfig(conn, config_name); + ProxyConfig config = snapper->getConfig(); - ci.read("TIMELINE_MIN_AGE", min_age); + read(config, "TIMELINE_MIN_AGE", min_age); - ci.read("TIMELINE_LIMIT_HOURLY", limit_hourly); - ci.read("TIMELINE_LIMIT_DAILY", limit_daily); - ci.read("TIMELINE_LIMIT_WEEKLY", limit_weekly); - ci.read("TIMELINE_LIMIT_MONTHLY", limit_monthly); - ci.read("TIMELINE_LIMIT_YEARLY", limit_yearly); + read(config, "TIMELINE_LIMIT_HOURLY", limit_hourly); + read(config, "TIMELINE_LIMIT_DAILY", limit_daily); + read(config, "TIMELINE_LIMIT_WEEKLY", limit_weekly); + read(config, "TIMELINE_LIMIT_MONTHLY", limit_monthly); + read(config, "TIMELINE_LIMIT_YEARLY", limit_yearly); } @@ -441,23 +456,22 @@ class TimelineCleaner : public Cleaner { public: - TimelineCleaner(DBus::Connection& conn, const string& config_name, bool verbose, - const TimelineParameters& parameters) - : Cleaner(conn, config_name, verbose, parameters) {} + TimelineCleaner(ProxySnapper* snapper, bool verbose, const TimelineParameters& parameters) + : Cleaner(snapper, verbose, parameters) {} private: bool - is_first(list::const_iterator first, - list::const_iterator last, - XSnapshots::const_iterator it1, + is_first(list::const_iterator first, + list::const_iterator last, + ProxySnapshots::const_iterator it1, std::function pred) { time_t t1 = it1->getDate(); struct tm tmp1; localtime_r(&t1, &tmp1); - for (list::const_iterator it2 = first; it2 != last; ++it2) + for (list::const_iterator it2 = first; it2 != last; ++it2) { if (it1 == *it2) continue; @@ -478,54 +492,54 @@ private: bool - is_first_yearly(list::const_iterator first, - list::const_iterator last, - XSnapshots::const_iterator it1) + is_first_yearly(list::const_iterator first, + list::const_iterator last, + ProxySnapshots::const_iterator it1) { return is_first(first, last, it1, equal_year); } bool - is_first_monthly(list::const_iterator first, - list::const_iterator last, - XSnapshots::const_iterator it1) + is_first_monthly(list::const_iterator first, + list::const_iterator last, + ProxySnapshots::const_iterator it1) { return is_first(first, last, it1, equal_month); } bool - is_first_weekly(list::const_iterator first, - list::const_iterator last, - XSnapshots::const_iterator it1) + is_first_weekly(list::const_iterator first, + list::const_iterator last, + ProxySnapshots::const_iterator it1) { return is_first(first, last, it1, equal_week); } bool - is_first_daily(list::const_iterator first, - list::const_iterator last, - XSnapshots::const_iterator it1) + is_first_daily(list::const_iterator first, + list::const_iterator last, + ProxySnapshots::const_iterator it1) { return is_first(first, last, it1, equal_day); } bool - is_first_hourly(list::const_iterator first, - list::const_iterator last, - XSnapshots::const_iterator it1) + is_first_hourly(list::const_iterator first, + list::const_iterator last, + ProxySnapshots::const_iterator it1) { return is_first(first, last, it1, equal_hour); } - list - calculate_candidates(Range::Value value) + list + calculate_candidates(ProxySnapshots& snapshots, Range::Value value) override { const TimelineParameters& parameters = dynamic_cast(Cleaner::parameters); - list ret; + list ret; - for (XSnapshots::iterator it = snapshots.begin(); it != snapshots.end(); ++it) + for (ProxySnapshots::iterator it = snapshots.begin(); it != snapshots.end(); ++it) { if (it->getCleanup() == "timeline") ret.push_front(it); @@ -537,7 +551,7 @@ private: size_t num_monthly = 0; size_t num_yearly = 0; - list::iterator it = ret.begin(); + list::iterator it = ret.begin(); while (it != ret.end()) { bool keep = false; @@ -582,26 +596,26 @@ private: void -do_cleanup_timeline(DBus::Connection& conn, const string& config_name, bool verbose) +do_cleanup_timeline(ProxySnapper* snapper, bool verbose) { - TimelineParameters parameters(conn, config_name); - TimelineCleaner cleaner(conn, config_name, verbose, parameters); + TimelineParameters parameters(snapper); + TimelineCleaner cleaner(snapper, verbose, parameters); cleaner.cleanup(); } struct EmptyPrePostParameters : public Parameters { - EmptyPrePostParameters(DBus::Connection& conn, const string& config_name); + EmptyPrePostParameters(const ProxySnapper* snapper); }; -EmptyPrePostParameters::EmptyPrePostParameters(DBus::Connection& conn, const string& config_name) - : Parameters(conn, config_name) +EmptyPrePostParameters::EmptyPrePostParameters(const ProxySnapper* snapper) + : Parameters(snapper) { - XConfigInfo ci = command_get_xconfig(conn, config_name); + ProxyConfig config = snapper->getConfig(); - ci.read("EMPTY_PRE_POST_MIN_AGE", min_age); + read(config, "EMPTY_PRE_POST_MIN_AGE", min_age); } @@ -609,36 +623,30 @@ class EmptyPrePostCleaner : public Cleaner { public: - EmptyPrePostCleaner(DBus::Connection& conn, const string& config_name, bool verbose, + EmptyPrePostCleaner(ProxySnapper* snapper, bool verbose, const EmptyPrePostParameters& parameters) - : Cleaner(conn, config_name, verbose, parameters) {} + : Cleaner(snapper, verbose, parameters) {} private: - list - calculate_candidates(Range::Value value) + list + calculate_candidates(ProxySnapshots& snapshots, Range::Value value) override { - list ret; + list ret; - for (XSnapshots::iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) + for (ProxySnapshots::iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) { if (it1->getType() == PRE) { - XSnapshots::iterator it2 = snapshots.findPost(it1); - + ProxySnapshots::iterator it2 = snapshots.findPost(it1); if (it2 != snapshots.end()) { - command_create_xcomparison(conn, config_name, it1->getNum(), it2->getNum()); - - list files = command_get_xfiles(conn, config_name, it1->getNum(), it2->getNum()); - - if (files.empty()) + ProxyComparison comparison = snapper->createComparison(*it1, *it2, false); + if (comparison.getFiles().empty()) { ret.push_back(it1); ret.push_back(it2); } - - command_delete_xcomparison(conn, config_name, it1->getNum(), it2->getNum()); } } } @@ -649,9 +657,9 @@ private: void -do_cleanup_empty_pre_post(DBus::Connection& conn, const string& config_name, bool verbose) +do_cleanup_empty_pre_post(ProxySnapper* snapper, bool verbose) { - EmptyPrePostParameters parameters(conn, config_name); - EmptyPrePostCleaner cleaner(conn, config_name, verbose, parameters); + EmptyPrePostParameters parameters(snapper); + EmptyPrePostCleaner cleaner(snapper, verbose, parameters); cleaner.cleanup(); } diff --git a/client/cleanup.h b/client/cleanup.h index 35955bf2..000b6698 100644 --- a/client/cleanup.h +++ b/client/cleanup.h @@ -1,5 +1,6 @@ /* * Copyright (c) [2011-2012] Novell, Inc. + * Copyright (c) 2016 SUSE LLC * * All Rights Reserved. * @@ -20,11 +21,14 @@ */ +#include "proxy.h" + + void -do_cleanup_number(DBus::Connection& conn, const string& config_name, bool verbose); +do_cleanup_number(ProxySnapper* snapper, bool verbose); void -do_cleanup_timeline(DBus::Connection& conn, const string& config_name, bool verbose); +do_cleanup_timeline(ProxySnapper* snapper, bool verbose); void -do_cleanup_empty_pre_post(DBus::Connection& conn, const string& config_name, bool verbose); +do_cleanup_empty_pre_post(ProxySnapper* snapper, bool verbose); diff --git a/client/commands.cc b/client/commands.cc index 8cb9fd7c..41c4dc12 100644 --- a/client/commands.cc +++ b/client/commands.cc @@ -35,14 +35,14 @@ using namespace std; #define INTERFACE "org.opensuse.Snapper" -list +vector command_list_xconfigs(DBus::Connection& conn) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "ListConfigs"); DBus::Message reply = conn.send_with_reply_and_block(call); - list ret; + vector ret; DBus::Hihi hihi(reply); hihi >> ret; @@ -84,8 +84,8 @@ command_set_xconfig(DBus::Connection& conn, const string& config_name, void -command_create_xconfig(DBus::Connection& conn, const string& config_name, const string& subvolume, - const string& fstype, const string& template_name) +command_create_config(DBus::Connection& conn, const string& config_name, const string& subvolume, + const string& fstype, const string& template_name) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreateConfig"); @@ -97,7 +97,7 @@ command_create_xconfig(DBus::Connection& conn, const string& config_name, const void -command_delete_xconfig(DBus::Connection& conn, const string& config_name) +command_delete_config(DBus::Connection& conn, const string& config_name) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "DeleteConfig"); @@ -147,22 +147,22 @@ command_get_xsnapshot(DBus::Connection& conn, const string& config_name, unsigne void -command_set_xsnapshot(DBus::Connection& conn, const string& config_name, unsigned int num, - const XSnapshot& data) +command_set_snapshot(DBus::Connection& conn, const string& config_name, unsigned int num, + const SMD& smd) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "SetSnapshot"); DBus::Hoho hoho(call); - hoho << config_name << num << data.description << data.cleanup << data.userdata; + hoho << config_name << num << smd.description << smd.cleanup << smd.userdata; conn.send_with_reply_and_block(call); } unsigned int -command_create_single_xsnapshot(DBus::Connection& conn, const string& config_name, - const string& description, const string& cleanup, - const map& userdata) +command_create_single_snapshot(DBus::Connection& conn, const string& config_name, + const string& description, const string& cleanup, + const map& userdata) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreateSingleSnapshot"); @@ -181,10 +181,10 @@ command_create_single_xsnapshot(DBus::Connection& conn, const string& config_nam unsigned int -command_create_single_xsnapshot_v2(DBus::Connection& conn, const string& config_name, - unsigned int parent_num, bool read_only, - const string& description, const string& cleanup, - const map& userdata) +command_create_single_snapshot_v2(DBus::Connection& conn, const string& config_name, + unsigned int parent_num, bool read_only, + const string& description, const string& cleanup, + const map& userdata) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreateSingleSnapshotV2"); @@ -203,10 +203,10 @@ command_create_single_xsnapshot_v2(DBus::Connection& conn, const string& config_ unsigned int -command_create_single_xsnapshot_of_default(DBus::Connection& conn, const string& config_name, - bool read_only, const string& description, - const string& cleanup, - const map& userdata) +command_create_single_snapshot_of_default(DBus::Connection& conn, const string& config_name, + bool read_only, const string& description, + const string& cleanup, + const map& userdata) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreateSingleSnapshotOfDefault"); @@ -225,9 +225,9 @@ command_create_single_xsnapshot_of_default(DBus::Connection& conn, const string& unsigned int -command_create_pre_xsnapshot(DBus::Connection& conn, const string& config_name, - const string& description, const string& cleanup, - const map& userdata) +command_create_pre_snapshot(DBus::Connection& conn, const string& config_name, + const string& description, const string& cleanup, + const map& userdata) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreatePreSnapshot"); @@ -246,9 +246,9 @@ command_create_pre_xsnapshot(DBus::Connection& conn, const string& config_name, unsigned int -command_create_post_xsnapshot(DBus::Connection& conn, const string& config_name, - unsigned int prenum, const string& description, - const string& cleanup, const map& userdata) +command_create_post_snapshot(DBus::Connection& conn, const string& config_name, + unsigned int prenum, const string& description, + const string& cleanup, const map& userdata) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreatePostSnapshot"); @@ -267,15 +267,15 @@ command_create_post_xsnapshot(DBus::Connection& conn, const string& config_name, void -command_delete_xsnapshots(DBus::Connection& conn, const string& config_name, - const list& nums, bool verbose) +command_delete_snapshots(DBus::Connection& conn, const string& config_name, + const vector& nums, bool verbose) { if (verbose) { cout << sformat(_("Deleting snapshot from %s:", "Deleting snapshots from %s:", nums.size()), config_name.c_str()) << endl; - for (list::const_iterator it = nums.begin(); it != nums.end(); ++it) + for (vector::const_iterator it = nums.begin(); it != nums.end(); ++it) { if (it != nums.begin()) cout << ", "; @@ -294,8 +294,8 @@ command_delete_xsnapshots(DBus::Connection& conn, const string& config_name, string -command_mount_xsnapshots(DBus::Connection& conn, const string& config_name, - unsigned int num, bool user_request) +command_mount_snapshot(DBus::Connection& conn, const string& config_name, + unsigned int num, bool user_request) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "MountSnapshot"); @@ -314,8 +314,8 @@ command_mount_xsnapshots(DBus::Connection& conn, const string& config_name, void -command_umount_xsnapshots(DBus::Connection& conn, const string& config_name, - unsigned int num, bool user_request) +command_umount_snapshot(DBus::Connection& conn, const string& config_name, unsigned int num, + bool user_request) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "UmountSnapshot"); @@ -327,8 +327,7 @@ command_umount_xsnapshots(DBus::Connection& conn, const string& config_name, string -command_get_xmount_point(DBus::Connection& conn, const string& config_name, - unsigned int num) +command_get_mount_point(DBus::Connection& conn, const string& config_name, unsigned int num) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "GetMountPoint"); @@ -347,8 +346,8 @@ command_get_xmount_point(DBus::Connection& conn, const string& config_name, void -command_create_xcomparison(DBus::Connection& conn, const string& config_name, unsigned int number1, - unsigned int number2) +command_create_comparison(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreateComparison"); @@ -360,8 +359,8 @@ command_create_xcomparison(DBus::Connection& conn, const string& config_name, un void -command_delete_xcomparison(DBus::Connection& conn, const string& config_name, unsigned int number1, - unsigned int number2) +command_delete_comparison(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "DeleteComparison"); @@ -379,7 +378,7 @@ operator<(const XFile& lhs, const XFile& rhs) } -list +vector command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned int number1, unsigned int number2) { @@ -390,13 +389,13 @@ command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned i DBus::Message reply = conn.send_with_reply_and_block(call); - list files; + vector files; DBus::Hihi hihi(reply); hihi >> files; - files.sort(); // snapperd can have different locale than client - // so sorting is required here + sort(files.begin(), files.end()); // snapperd can have different locale than client + // so sorting is required here return files; } @@ -426,7 +425,7 @@ command_prepare_quota(DBus::Connection& conn, const string& config_name) } -XQuotaData +QuotaData command_query_quota(DBus::Connection& conn, const string& config_name) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "QueryQuota"); @@ -436,7 +435,7 @@ command_query_quota(DBus::Connection& conn, const string& config_name) DBus::Message reply = conn.send_with_reply_and_block(call); - XQuotaData quota_data; + QuotaData quota_data; DBus::Hihi hihi(reply); hihi >> quota_data; @@ -446,7 +445,7 @@ command_query_quota(DBus::Connection& conn, const string& config_name) void -command_xsync(DBus::Connection& conn, const string& config_name) +command_sync(DBus::Connection& conn, const string& config_name) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "Sync"); @@ -458,7 +457,7 @@ command_xsync(DBus::Connection& conn, const string& config_name) vector -command_xdebug(DBus::Connection& conn) +command_debug(DBus::Connection& conn) { DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "Debug"); diff --git a/client/commands.h b/client/commands.h index 683a11a5..b70aa957 100644 --- a/client/commands.h +++ b/client/commands.h @@ -23,18 +23,16 @@ #include #include -#include #include using std::string; using std::vector; -using std::list; using std::map; #include "types.h" -list +vector command_list_xconfigs(DBus::Connection& conn); XConfigInfo @@ -45,11 +43,11 @@ command_set_xconfig(DBus::Connection& conn, const string& config_name, const map& raw); void -command_create_xconfig(DBus::Connection& conn, const string& config_name, const string& subvolume, - const string& fstype, const string& template_name); +command_create_config(DBus::Connection& conn, const string& config_name, const string& subvolume, + const string& fstype, const string& template_name); void -command_delete_xconfig(DBus::Connection& conn, const string& config_name); +command_delete_config(DBus::Connection& conn, const string& config_name); XSnapshots command_list_xsnapshots(DBus::Connection& conn, const string& config_name); @@ -58,61 +56,61 @@ XSnapshot command_get_xsnapshot(DBus::Connection& conn, const string& config_name, unsigned int num); void -command_set_xsnapshot(DBus::Connection& conn, const string& config_name, unsigned int num, - const XSnapshot& data); +command_set_snapshot(DBus::Connection& conn, const string& config_name, unsigned int num, + const SMD& smd); unsigned int -command_create_single_xsnapshot(DBus::Connection& conn, const string& config_name, - const string& description, const string& cleanup, - const map& userdata); +command_create_single_snapshot(DBus::Connection& conn, const string& config_name, + const string& description, const string& cleanup, + const map& userdata); unsigned int -command_create_single_xsnapshot_v2(DBus::Connection& conn, const string& config_name, - unsigned int parent_num, bool read_only, - const string& description, const string& cleanup, - const map& userdata); +command_create_single_snapshot_v2(DBus::Connection& conn, const string& config_name, + unsigned int parent_num, bool read_only, + const string& description, const string& cleanup, + const map& userdata); unsigned int -command_create_single_xsnapshot_of_default(DBus::Connection& conn, const string& config_name, - bool read_only, const string& description, - const string& cleanup, - const map& userdata); +command_create_single_snapshot_of_default(DBus::Connection& conn, const string& config_name, + bool read_only, const string& description, + const string& cleanup, + const map& userdata); unsigned int -command_create_pre_xsnapshot(DBus::Connection& conn, const string& config_name, - const string& description, const string& cleanup, - const map& userdata); +command_create_pre_snapshot(DBus::Connection& conn, const string& config_name, + const string& description, const string& cleanup, + const map& userdata); unsigned int -command_create_post_xsnapshot(DBus::Connection& conn, const string& config_name, - unsigned int prenum, const string& description, - const string& cleanup, const map& userdata); +command_create_post_snapshot(DBus::Connection& conn, const string& config_name, + unsigned int prenum, const string& description, + const string& cleanup, const map& userdata); void -command_delete_xsnapshots(DBus::Connection& conn, const string& config_name, - const list& nums, bool verbose); +command_delete_snapshots(DBus::Connection& conn, const string& config_name, + const vector& nums, bool verbose); string -command_mount_xsnapshots(DBus::Connection& conn, const string& config_name, - unsigned int num, bool user_request); +command_mount_snapshot(DBus::Connection& conn, const string& config_name, + unsigned int num, bool user_request); void -command_umount_xsnapshots(DBus::Connection& conn, const string& config_name, - unsigned int num, bool user_request); +command_umount_snapshot(DBus::Connection& conn, const string& config_name, + unsigned int num, bool user_request); string -command_get_xmount_point(DBus::Connection& conn, const string& config_name, - unsigned int num); +command_get_mount_point(DBus::Connection& conn, const string& config_name, + unsigned int num); void -command_create_xcomparison(DBus::Connection& conn, const string& config_name, unsigned int number1, - unsigned int number2); +command_create_comparison(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2); void -command_delete_xcomparison(DBus::Connection& conn, const string& config_name, unsigned int number1, - unsigned int number2); +command_delete_comparison(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2); -list +vector command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned int number1, unsigned int number2); @@ -122,11 +120,11 @@ command_setup_quota(DBus::Connection& conn, const string& config_name); void command_prepare_quota(DBus::Connection& conn, const string& config_name); -XQuotaData +QuotaData command_query_quota(DBus::Connection& conn, const string& config_name); void -command_xsync(DBus::Connection& conn, const string& config_name); +command_sync(DBus::Connection& conn, const string& config_name); vector -command_xdebug(DBus::Connection& conn); +command_debug(DBus::Connection& conn); diff --git a/client/errors.cc b/client/errors.cc index f2dc43e4..ff16a8d0 100644 --- a/client/errors.cc +++ b/client/errors.cc @@ -50,7 +50,7 @@ error_description(const DBus::ErrorException& e) return _("Invalid configdata."); if (name == "error.illegal_snapshot") - return _("Illegal Snapshot."); + return _("Illegal snapshot."); if (name == "error.config_locked") return _("Config is locked."); diff --git a/client/misc.cc b/client/misc.cc index be9bf749..843479f2 100644 --- a/client/misc.cc +++ b/client/misc.cc @@ -34,32 +34,6 @@ #include "misc.h" -Snapshots::iterator -read_num(Snapper* snapper, const string& str) -{ - Snapshots& snapshots = snapper->getSnapshots(); - - istringstream s(str); - unsigned int num = 0; - s >> num; - - if (s.fail() || !s.eof()) - { - cerr << sformat(_("Invalid snapshot '%s'."), str.c_str()) << endl; - exit(EXIT_FAILURE); - } - - Snapshots::iterator snap = snapshots.find(num); - if (snap == snapshots.end()) - { - cerr << sformat(_("Snapshot '%u' not found."), num) << endl; - exit(EXIT_FAILURE); - } - - return snap; -} - - unsigned int read_num(const string& str) { @@ -77,36 +51,6 @@ read_num(const string& str) } -pair -read_nums(const string& str, const string& delim) -{ - string::size_type pos = str.find(delim); - if (pos == string::npos) - { - if (delim == "..") - { - cerr << _("Missing delimiter '..' between snapshot numbers.") << endl - << _("See 'man snapper' for further instructions.") << endl; - exit(EXIT_FAILURE); - } - - cerr << _("Invalid snapshots.") << endl; - exit(EXIT_FAILURE); - } - - unsigned int num1 = read_num(str.substr(0, pos)); - unsigned int num2 = read_num(str.substr(pos + delim.size())); - - if (num1 == num2) - { - cerr << _("Identical snapshots.") << endl; - exit(EXIT_FAILURE); - } - - return pair(num1, num2); -} - - map read_userdata(const string& s, const map& old) { diff --git a/client/misc.h b/client/misc.h index 6280a8e7..0e2af7e4 100644 --- a/client/misc.h +++ b/client/misc.h @@ -29,15 +29,9 @@ using namespace snapper; using namespace std; -Snapshots::iterator -read_num(Snapper* snapper, const string& str); - unsigned int read_num(const string& str); -pair -read_nums(const string& str, const string& delim = ".."); - map read_userdata(const string& s, const map& old = map()); diff --git a/client/proxy-dbus.cc b/client/proxy-dbus.cc new file mode 100644 index 00000000..262fc064 --- /dev/null +++ b/client/proxy-dbus.cc @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2016 SUSE LLC + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#include "proxy-dbus.h" +#include "commands.h" +#include "utils/text.h" + + +using namespace std; + + +ProxySnapshotDbus::ProxySnapshotDbus(ProxySnapshotsDbus* backref, unsigned int num) + : backref(backref), num(num) +{ + XSnapshot x = command_get_xsnapshot(conn(), configName(), num); + + type = x.type; + date = x.date; + uid = x.uid; + pre_num = x.pre_num; + description = x.description; + cleanup = x.cleanup; + userdata = x.userdata; +} + + +ProxySnapshotDbus::ProxySnapshotDbus(ProxySnapshotsDbus* backref, SnapshotType type, unsigned int num, + time_t date, uid_t uid, unsigned int pre_num, + const string& description, const string& cleanup, + const map& userdata) + : backref(backref), type(type), num(num), date(date), uid(uid), pre_num(pre_num), + description(description), cleanup(cleanup), userdata(userdata) +{ +} + + +string +ProxySnapshotDbus::mountFilesystemSnapshot(bool user_request) const +{ + return command_mount_snapshot(conn(), configName(), num, user_request); +} + + +void +ProxySnapshotDbus::umountFilesystemSnapshot(bool user_request) const +{ + command_umount_snapshot(conn(), configName(), num, user_request); +} + + +DBus::Connection& +ProxySnapshotDbus::conn() const +{ + return backref->conn(); +} + + +const string& +ProxySnapshotDbus::configName() const +{ + return backref->configName(); +} + + +ProxySnapshotsDbus::ProxySnapshotsDbus(ProxySnapperDbus* backref) + : backref(backref) +{ + XSnapshots tmp = command_list_xsnapshots(conn(), configName()); + for (XSnapshots::const_iterator it = tmp.begin(); it != tmp.end(); ++it) + proxy_snapshots.push_back(new ProxySnapshotDbus(this, it->getType(), it->getNum(), it->getDate(), + it->getUid(), it->getPreNum(), it->getDescription(), + it->getCleanup(), it->getUserdata())); +} + + +DBus::Connection& +ProxySnapshotsDbus::conn() const +{ + return backref->conn(); +} + + +const string& +ProxySnapshotsDbus::configName() const +{ + return backref->config_name; +} + + +ProxyConfig +ProxySnapperDbus::getConfig() const +{ + XConfigInfo tmp = command_get_xconfig(conn(), config_name); + + return ProxyConfig(tmp.raw); +} + + +void +ProxySnapperDbus::setConfig(const ProxyConfig& proxy_config) +{ + command_set_xconfig(conn(), config_name, proxy_config.getAllValues()); +} + + +void +ProxySnapperDbus::setupQuota() +{ + command_setup_quota(conn(), config_name); +} + + +void +ProxySnapperDbus::prepareQuota() const +{ + command_prepare_quota(conn(), config_name); +} + + +QuotaData +ProxySnapperDbus::queryQuotaData() const +{ + return command_query_quota(conn(), config_name); +} + + +ProxySnapshots::const_iterator +ProxySnapperDbus::createSingleSnapshot(const SCD& scd) +{ + unsigned int num = command_create_single_snapshot(conn(), config_name, scd.description, + scd.cleanup, scd.userdata); + + proxy_snapshots.emplace_back(new ProxySnapshotDbus(&proxy_snapshots, num)); + + return --proxy_snapshots.end(); +} + + +ProxySnapshots::const_iterator +ProxySnapperDbus::createSingleSnapshot(ProxySnapshots::const_iterator parent, const SCD& scd) +{ + unsigned int num = command_create_single_snapshot_v2(conn(), config_name, parent->getNum(), + scd.read_only, scd.description, scd.cleanup, + scd.userdata); + + proxy_snapshots.emplace_back(new ProxySnapshotDbus(&proxy_snapshots, num)); + + return --proxy_snapshots.end(); +} + + +ProxySnapshots::const_iterator +ProxySnapperDbus::createSingleSnapshotOfDefault(const SCD& scd) +{ + unsigned int num = command_create_single_snapshot_of_default(conn(), config_name, scd.read_only, + scd.description, scd.cleanup, + scd.userdata); + + proxy_snapshots.emplace_back(new ProxySnapshotDbus(&proxy_snapshots, num)); + + return --proxy_snapshots.end(); +} + + +ProxySnapshots::const_iterator +ProxySnapperDbus::createPreSnapshot(const SCD& scd) +{ + unsigned int num = command_create_pre_snapshot(conn(), config_name, scd.description, + scd.cleanup, scd.userdata); + + proxy_snapshots.emplace_back(new ProxySnapshotDbus(&proxy_snapshots, num)); + + return --proxy_snapshots.end(); +} + + +ProxySnapshots::const_iterator +ProxySnapperDbus::createPostSnapshot(ProxySnapshots::const_iterator pre, const SCD& scd) +{ + unsigned int num = command_create_post_snapshot(conn(), config_name, pre->getNum(), + scd.description, scd.cleanup, scd.userdata); + + proxy_snapshots.emplace_back(new ProxySnapshotDbus(&proxy_snapshots, num)); + + return --proxy_snapshots.end(); +} + + +void +ProxySnapperDbus::modifySnapshot(ProxySnapshots::iterator snapshot, const SMD& smd) +{ + command_set_snapshot(conn(), config_name, snapshot->getNum(), smd); +} + + +void +ProxySnapperDbus::deleteSnapshots(vector snapshots, bool verbose) +{ + vector nums; + for (const ProxySnapshots::iterator& proxy_snapshot : snapshots) + nums.push_back(proxy_snapshot->getNum()); + + command_delete_snapshots(conn(), config_name, nums, verbose); + + ProxySnapshots& proxy_snapshots = getSnapshots(); + for (ProxySnapshots::iterator& proxy_snapshot : snapshots) + proxy_snapshots.erase(proxy_snapshot); +} + + +ProxyComparison +ProxySnapperDbus::createComparison(const ProxySnapshot& lhs, const ProxySnapshot& rhs, bool mount) +{ + return ProxyComparison(new ProxyComparisonDbus(this, lhs, rhs, mount)); +} + + +void +ProxySnapperDbus::syncFilesystem() const +{ + command_sync(conn(), config_name); +} + + +DBus::Connection& +ProxySnapperDbus::conn() const +{ + return backref->conn; +} + + +void +ProxySnappersDbus::createConfig(const string& config_name, const string& subvolume, + const string& fstype, const string& template_name) +{ + command_create_config(conn, config_name, subvolume, fstype, template_name); +} + + +void +ProxySnappersDbus::deleteConfig(const string& config_name) +{ + command_delete_config(conn, config_name); +} + + +ProxySnapper* +ProxySnappersDbus::getSnapper(const string& config_name) +{ + for (unique_ptr& proxy_snapper : proxy_snappers) + { + if (proxy_snapper->config_name == config_name) + return proxy_snapper.get(); + } + + ProxySnapperDbus* ret = new ProxySnapperDbus(this, config_name); + proxy_snappers.emplace_back(ret); + return ret; +} + + +map +ProxySnappersDbus::getConfigs() const +{ + map ret; + + vector config_infos = command_list_xconfigs(conn); + for (XConfigInfo& x : config_infos) + ret.emplace(make_pair(x.config_name, x.raw)); + + return ret; +} + + +vector +ProxySnappersDbus::debug() const +{ + return command_debug(conn); +} + + +ProxyComparisonDbus::ProxyComparisonDbus(ProxySnapperDbus* backref, const ProxySnapshot& lhs, + const ProxySnapshot& rhs, bool mount) + : backref(backref), lhs(lhs), rhs(rhs), files(&file_paths) +{ + command_create_comparison(conn(), configName(), lhs.getNum(), rhs.getNum()); + + file_paths.system_path = command_get_mount_point(backref->conn(), backref->config_name, 0); + + if (mount) + { + if (!lhs.isCurrent()) + file_paths.pre_path = command_mount_snapshot(backref->conn(), backref->config_name, + lhs.getNum(), false); + else + file_paths.pre_path = file_paths.system_path; + + if (!rhs.isCurrent()) + file_paths.post_path = command_mount_snapshot(backref->conn(), backref->config_name, + rhs.getNum(), false); + else + file_paths.post_path = file_paths.system_path; + } + + vector tmp1 = command_get_xfiles(backref->conn(), backref->config_name, lhs.getNum(), + rhs.getNum()); + + vector tmp2; + + for (const XFile& xfile : tmp1) + tmp2.emplace_back(&file_paths, xfile.name, xfile.status); + + files = Files(&file_paths, tmp2); +} + + +ProxyComparisonDbus::~ProxyComparisonDbus() +{ + command_delete_comparison(conn(), configName(), lhs.getNum(), rhs.getNum()); +} + + +DBus::Connection& +ProxyComparisonDbus::conn() const +{ + return backref->conn(); +} + + +const string& +ProxyComparisonDbus::configName() const +{ + return backref->config_name; +} + + +ProxySnappers +ProxySnappers::createDbus() +{ + return ProxySnappers(new ProxySnappersDbus()); +} diff --git a/client/proxy-dbus.h b/client/proxy-dbus.h new file mode 100644 index 00000000..0c49771e --- /dev/null +++ b/client/proxy-dbus.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016 SUSE LLC + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#ifndef SNAPPER_PROXY_DBUS_H +#define SNAPPER_PROXY_DBUS_H + + +#include "dbus/DBusMessage.h" +#include "dbus/DBusConnection.h" + +#include "proxy.h" + + +class ProxySnapshotDbus; +class ProxySnapshotsDbus; +class ProxySnapperDbus; +class ProxySnappersDbus; + + +/** + * Concrete class of ProxySnapshot for DBus communication. Store all snapshot + * data in the client to avoid numerous DBus queries. + */ +class ProxySnapshotDbus : public ProxySnapshot::Impl +{ + +public: + + ProxySnapshotDbus(ProxySnapshotsDbus* backref, SnapshotType type, unsigned int num, + time_t date, uid_t uid, unsigned int pre_num, const string& description, + const string& cleanup, const map& userdata); + + ProxySnapshotDbus(ProxySnapshotsDbus* backref, unsigned int num); + + virtual SnapshotType getType() const override { return type; } + virtual unsigned int getNum() const override { return num; } + virtual time_t getDate() const override { return date; } + virtual uid_t getUid() const override { return uid; } + virtual unsigned int getPreNum() const override { return pre_num; } + virtual const string& getDescription() const override { return description; } + virtual const string& getCleanup() const override { return cleanup; } + virtual const map& getUserdata() const override { return userdata; } + + virtual bool isCurrent() const override { return num == 0; } + + virtual string mountFilesystemSnapshot(bool user_request) const override; + virtual void umountFilesystemSnapshot(bool user_request) const override; + + DBus::Connection& conn() const; + const string& configName() const; + +private: + + ProxySnapshotsDbus* backref; + + SnapshotType type; + unsigned int num; + time_t date; + uid_t uid; + unsigned int pre_num; + string description; + string cleanup; + map userdata; + +}; + + +class ProxySnapshotsDbus : public ProxySnapshots +{ + +public: + + ProxySnapshotsDbus(ProxySnapperDbus* backref); + + DBus::Connection& conn() const; + const string& configName() const; + +private: + + ProxySnapperDbus* backref; + +}; + + +class ProxySnapperDbus : public ProxySnapper +{ + +public: + + ProxySnapperDbus(ProxySnappersDbus* backref, const string& config_name) + : backref(backref), config_name(config_name), proxy_snapshots(this) + {} + + virtual const string& configName() const override { return config_name; } + + virtual ProxyConfig getConfig() const override; + virtual void setConfig(const ProxyConfig& proxy_config) override; + + virtual ProxySnapshots::const_iterator createSingleSnapshot(const SCD& scd) override; + virtual ProxySnapshots::const_iterator createSingleSnapshot(ProxySnapshots::const_iterator parent, + const SCD& scd) override; + virtual ProxySnapshots::const_iterator createSingleSnapshotOfDefault(const SCD& scd) override; + virtual ProxySnapshots::const_iterator createPreSnapshot(const SCD& scd) override; + virtual ProxySnapshots::const_iterator createPostSnapshot(ProxySnapshots::const_iterator pre, + const SCD& scd) override; + + virtual void modifySnapshot(ProxySnapshots::iterator snapshot, const SMD& smd) override; + + virtual void deleteSnapshots(vector snapshots, bool verbose) override; + + virtual ProxyComparison createComparison(const ProxySnapshot& lhs, const ProxySnapshot& rhs, + bool mount) override; + + virtual void syncFilesystem() const override; + + virtual ProxySnapshots& getSnapshots() override { return proxy_snapshots; } + virtual const ProxySnapshots& getSnapshots() const override { return proxy_snapshots; } + + virtual void setupQuota() override; + + virtual void prepareQuota() const override; + + virtual QuotaData queryQuotaData() const override; + + DBus::Connection& conn() const; + +private: + + ProxySnappersDbus* backref; + +public: + + string config_name; + + ProxySnapshotsDbus proxy_snapshots; + +}; + + +class ProxySnappersDbus : public ProxySnappers::Impl +{ + +public: + + ProxySnappersDbus() + : conn(DBUS_BUS_SYSTEM) + {} + + virtual void createConfig(const string& config_name, const string& subvolume, + const string& fstype, const string& template_name) override; + + virtual void deleteConfig(const string& config_name) override; + + virtual ProxySnapper* getSnapper(const string& config_name) override; + + virtual map getConfigs() const override; + + virtual vector debug() const override; + + mutable DBus::Connection conn; + + list> proxy_snappers; + +}; + + +class ProxyComparisonDbus : public ProxyComparison::Impl +{ +public: + + ProxyComparisonDbus(ProxySnapperDbus* backref, const ProxySnapshot& lhs, + const ProxySnapshot& rhs, bool mount); + + ~ProxyComparisonDbus(); + + virtual const Files& getFiles() const override { return files; } + + DBus::Connection& conn() const; + const string& configName() const; + +private: + + ProxySnapperDbus* backref; + + const ProxySnapshot& lhs; + const ProxySnapshot& rhs; + + FilePaths file_paths; + + Files files; + +}; + + +#endif diff --git a/client/proxy-lib.cc b/client/proxy-lib.cc new file mode 100644 index 00000000..9fd7676a --- /dev/null +++ b/client/proxy-lib.cc @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2016 SUSE LLC + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#include "proxy-lib.h" + + +using namespace std; + + +ProxyConfig +ProxySnapperLib::getConfig() const +{ + return ProxyConfig(snapper->getConfigInfo().getAllValues()); +} + + +void +ProxySnapperLib::setConfig(const ProxyConfig& proxy_config) +{ + snapper->setConfigInfo(proxy_config.getAllValues()); +} + + +ProxySnapshots::const_iterator +ProxySnapperLib::createSingleSnapshot(const SCD& scd) +{ + proxy_snapshots.emplace_back(new ProxySnapshotLib(snapper->createSingleSnapshot(scd))); + + return --proxy_snapshots.end(); +} + + +ProxySnapshots::const_iterator +ProxySnapperLib::createSingleSnapshot(ProxySnapshots::const_iterator parent, const SCD& scd) +{ + proxy_snapshots.emplace_back(new ProxySnapshotLib(snapper->createSingleSnapshot(to_lib(*parent).it, scd))); + + return --proxy_snapshots.end(); +} + + +ProxySnapshots::const_iterator +ProxySnapperLib::createSingleSnapshotOfDefault(const SCD& scd) +{ + proxy_snapshots.emplace_back(new ProxySnapshotLib(snapper->createSingleSnapshotOfDefault(scd))); + + return --proxy_snapshots.end(); +} + + +ProxySnapshots::const_iterator +ProxySnapperLib::createPreSnapshot(const SCD& scd) +{ + proxy_snapshots.emplace_back(new ProxySnapshotLib(snapper->createPreSnapshot(scd))); + + return --proxy_snapshots.end(); +} + + +ProxySnapshots::const_iterator +ProxySnapperLib::createPostSnapshot(ProxySnapshots::const_iterator pre, const SCD& scd) +{ + proxy_snapshots.emplace_back(new ProxySnapshotLib(snapper->createPostSnapshot(to_lib(*pre).it, scd))); + + return --proxy_snapshots.end(); +} + + +void +ProxySnapperLib::modifySnapshot(ProxySnapshots::iterator snapshot, const SMD& smd) +{ + snapper->modifySnapshot(to_lib(*snapshot).it, smd); +} + + +void +ProxySnapperLib::deleteSnapshots(vector snapshots, bool verbose) +{ + for (ProxySnapshots::iterator& snapshot : snapshots) + snapper->deleteSnapshot(to_lib(*snapshot).it); + + ProxySnapshots& proxy_snapshots = getSnapshots(); + for (ProxySnapshots::iterator& proxy_snapshot : snapshots) + proxy_snapshots.erase(proxy_snapshot); +} + + +ProxyComparison +ProxySnapperLib::createComparison(const ProxySnapshot& lhs, const ProxySnapshot& rhs, bool mount) +{ + return ProxyComparison(new ProxyComparisonLib(this, lhs, rhs, mount)); +} + + +ProxySnapshotsLib::ProxySnapshotsLib(ProxySnapperLib* backref) + : backref(backref) +{ + Snapshots& tmp = backref->snapper->getSnapshots(); + for (Snapshots::iterator it = tmp.begin(); it != tmp.end(); ++it) + proxy_snapshots.push_back(new ProxySnapshotLib(it)); +} + + +void +ProxySnappersLib::createConfig(const string& config_name, const string& subvolume, + const string& fstype, const string& template_name) +{ + Snapper::createConfig(config_name, target_root, subvolume, fstype, template_name); +} + + +void +ProxySnappersLib::deleteConfig(const string& config_name) +{ + Snapper::deleteConfig(config_name, target_root); +} + + +ProxySnapper* +ProxySnappersLib::getSnapper(const string& config_name) +{ + for (unique_ptr& proxy_snapper : proxy_snappers) + { + if (proxy_snapper->snapper->configName() == config_name) + return proxy_snapper.get(); + } + + ProxySnapperLib* ret = new ProxySnapperLib(config_name); + proxy_snappers.emplace_back(ret); + return ret; +} + + +map +ProxySnappersLib::getConfigs() const +{ + map ret; + + list config_infos = Snapper::getConfigs(target_root); + for (const ConfigInfo& config_info : config_infos) + ret.emplace(make_pair(config_info.getConfigName(), config_info.getAllValues())); + + return ret; +} + + +ProxyComparisonLib::ProxyComparisonLib(ProxySnapperLib* proxy_snapper, const ProxySnapshot& lhs, + const ProxySnapshot& rhs, bool mount) + : proxy_snapper(proxy_snapper) +{ + comparison.reset(new Comparison(proxy_snapper->snapper.get(), to_lib(lhs).it, to_lib(rhs).it, + mount)); +} + + +ProxySnappers +ProxySnappers::createLib(const string& target_root) +{ + return ProxySnappers(new ProxySnappersLib(target_root)); +} + + +const ProxySnapshotLib& +to_lib(const ProxySnapshot& proxy_snapshot) +{ + return dynamic_cast(proxy_snapshot.get_impl()); +} diff --git a/client/proxy-lib.h b/client/proxy-lib.h new file mode 100644 index 00000000..c8f13e72 --- /dev/null +++ b/client/proxy-lib.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016 SUSE LLC + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#ifndef SNAPPER_PROXY_LIB_H +#define SNAPPER_PROXY_LIB_H + + +#include "proxy.h" + +#include +#include + + +class ProxySnapshotLib : public ProxySnapshot::Impl +{ + +public: + + ProxySnapshotLib(Snapshots::iterator it) + : it(it) + {} + + virtual SnapshotType getType() const override { return it->getType(); } + virtual unsigned int getNum() const override { return it->getNum(); } + virtual time_t getDate() const override { return it->getDate(); } + virtual uid_t getUid() const override { return it->getUid(); } + virtual unsigned int getPreNum() const override { return it->getPreNum(); } + virtual const string& getDescription() const override { return it->getDescription(); } + virtual const string& getCleanup() const override { return it->getCleanup(); } + virtual const map& getUserdata() const override { return it->getUserdata(); } + + virtual bool isCurrent() const override { return it->isCurrent(); } + + virtual string mountFilesystemSnapshot(bool user_request) const override + { + it->mountFilesystemSnapshot(user_request); + return it->snapshotDir(); + } + + virtual void umountFilesystemSnapshot(bool user_request) const override + { + it->umountFilesystemSnapshot(user_request); + } + + Snapshots::iterator it; + +}; + + +class ProxySnapperLib; + + +class ProxySnapshotsLib : public ProxySnapshots +{ + +public: + + ProxySnapshotsLib(ProxySnapperLib* backref); + + ProxySnapperLib* backref; + +}; + + +class ProxySnapperLib : public ProxySnapper +{ + +public: + + ProxySnapperLib(const string& config_name) + : snapper(new Snapper(config_name, "/")), proxy_snapshots(this) + {} + + virtual const string& configName() const override { return snapper->configName(); } + + virtual ProxyConfig getConfig() const override; + virtual void setConfig(const ProxyConfig& proxy_config) override; + + virtual ProxySnapshots::const_iterator createSingleSnapshot(const SCD& scd) override; + virtual ProxySnapshots::const_iterator createSingleSnapshot(ProxySnapshots::const_iterator parent, + const SCD& scd) override; + virtual ProxySnapshots::const_iterator createSingleSnapshotOfDefault(const SCD& scd) override; + virtual ProxySnapshots::const_iterator createPreSnapshot(const SCD& scd) override; + virtual ProxySnapshots::const_iterator createPostSnapshot(ProxySnapshots::const_iterator pre, + const SCD& scd) override; + + virtual void modifySnapshot(ProxySnapshots::iterator snapshot, const SMD& smd) override; + + virtual void deleteSnapshots(vector snapshots, bool verbose) override; + + virtual ProxyComparison createComparison(const ProxySnapshot& lhs, const ProxySnapshot& rhs, + bool mount) override; + + virtual void syncFilesystem() const override { snapper->syncFilesystem(); } + + virtual ProxySnapshots& getSnapshots() override { return proxy_snapshots; } + virtual const ProxySnapshots& getSnapshots() const override { return proxy_snapshots; } + + virtual void setupQuota() override { snapper->setupQuota(); } + + virtual void prepareQuota() const override { snapper->prepareQuota(); } + + virtual QuotaData queryQuotaData() const override { return snapper->queryQuotaData(); } + + std::unique_ptr snapper; + +private: + + ProxySnapshotsLib proxy_snapshots; + +}; + + +class ProxySnappersLib : public ProxySnappers::Impl +{ + +public: + + ProxySnappersLib(const string& target_root) + : target_root(target_root) + {} + + virtual void createConfig(const string& config_name, const string& subvolume, + const string& fstype, const string& template_name) override; + + virtual void deleteConfig(const string& config_name) override; + + virtual ProxySnapper* getSnapper(const string& config_name) override; + + virtual map getConfigs() const override; + + virtual vector debug() const { return Snapper::debug(); } + +private: + + const string target_root; + + list> proxy_snappers; + +}; + + +class ProxyComparisonLib : public ProxyComparison::Impl +{ + +public: + + ProxyComparisonLib(ProxySnapperLib* proxy_snapper, const ProxySnapshot& lhs, + const ProxySnapshot& rhs, bool mount); + + virtual const Files& getFiles() const override { return comparison->getFiles(); } + + ProxySnapper* proxy_snapper; + +private: + + std::unique_ptr comparison; + +}; + + +const ProxySnapshotLib& +to_lib(const ProxySnapshot& proxy_snapshot); + + +#endif diff --git a/client/proxy.cc b/client/proxy.cc new file mode 100644 index 00000000..e94a0287 --- /dev/null +++ b/client/proxy.cc @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2016 SUSE LLC + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#include +#include +#include + +#include +#include + +#include "utils/text.h" +#include "proxy.h" + + +using namespace std; + + +string +ProxyConfig::getSubvolume() const +{ + string subvolume; + getValue(KEY_SUBVOLUME, subvolume); + return subvolume; +} + + +bool +ProxyConfig::getValue(const string& key, string& value) const +{ + map::const_iterator it = values.find(key); + if (it == values.end()) + return false; + + value = it->second; + return true; +} + + +ProxySnapshots::iterator +ProxySnapshots::find(unsigned int num) +{ + return find_if(proxy_snapshots.begin(), proxy_snapshots.end(), + [num](const ProxySnapshot& x) { return x.getNum() == num; }); +} + + +ProxySnapshots::const_iterator +ProxySnapshots::find(unsigned int num) const +{ + return find_if(proxy_snapshots.begin(), proxy_snapshots.end(), + [num](const ProxySnapshot& x) { return x.getNum() == num; }); +} + + +ProxySnapshots::iterator +ProxySnapshots::findNum(const string& str) +{ + istringstream s(str); + unsigned int num = 0; + s >> num; + + if (s.fail() || !s.eof()) + { + cerr << sformat(_("Invalid snapshot '%s'."), str.c_str()) << endl; + exit(EXIT_FAILURE); + } + + iterator ret = find(num); + if (ret == proxy_snapshots.end()) + { + cerr << sformat(_("Snapshot '%u' not found."), num) << endl; + exit(EXIT_FAILURE); + } + + return ret; +} + + +ProxySnapshots::const_iterator +ProxySnapshots::findNum(const string& str) const +{ + istringstream s(str); + unsigned int num = 0; + s >> num; + + if (s.fail() || !s.eof()) + { + cerr << sformat(_("Invalid snapshot '%s'."), str.c_str()) << endl; + exit(EXIT_FAILURE); + } + + const_iterator ret = find(num); + if (ret == proxy_snapshots.end()) + { + cerr << sformat(_("Snapshot '%u' not found."), num) << endl; + exit(EXIT_FAILURE); + } + + return ret; +} + + +pair +ProxySnapshots::findNums(const string& str, const string& delim) +{ + string::size_type pos = str.find(delim); + if (pos == string::npos) + { + if (delim == "..") + { + cerr << _("Missing delimiter '..' between snapshot numbers.") << endl + << _("See 'man snapper' for further instructions.") << endl; + exit(EXIT_FAILURE); + } + + cerr << _("Invalid snapshots.") << endl; + exit(EXIT_FAILURE); + } + + ProxySnapshots::iterator num1 = findNum(str.substr(0, pos)); + ProxySnapshots::iterator num2 = findNum(str.substr(pos + delim.size())); + + if (num1->getNum() == num2->getNum()) + { + cerr << _("Identical snapshots.") << endl; + exit(EXIT_FAILURE); + } + + return make_pair(num1, num2); +} + + +ProxySnapshots::const_iterator +ProxySnapshots::findPre(const_iterator post) const +{ + for (const_iterator it = begin(); it != end(); ++it) + { + if (it->getType() == PRE && it->getNum() == post->getPreNum()) + return it; + } + + return end(); +} + + +ProxySnapshots::iterator +ProxySnapshots::findPost(iterator pre) +{ + for (iterator it = begin(); it != end(); ++it) + { + if (it->getType() == POST && it->getPreNum() == pre->getNum()) + return it; + } + + return end(); +} + + +ProxySnapshots::const_iterator +ProxySnapshots::findPost(const_iterator pre) const +{ + for (const_iterator it = begin(); it != end(); ++it) + { + if (it->getType() == POST && it->getPreNum() == pre->getNum()) + return it; + } + + return end(); +} diff --git a/client/proxy.h b/client/proxy.h new file mode 100644 index 00000000..d851af63 --- /dev/null +++ b/client/proxy.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2016 SUSE LLC + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#ifndef SNAPPER_PROXY_H +#define SNAPPER_PROXY_H + + +#include +#include +#include +#include + +#include +#include +#include + + +using namespace snapper; + + +/** + * The proxy classes here allow clients, so far only the snapper command line + * interface, to work with and without DBus in a transparent way by providing + * the same interface in both cases. + * + * The main idea for providing the same interface is to have an abstract + * class, e.g. ProxySnapper, and two concrete implementation ProxySnapperDbus + * and ProxySnapperLib. This is done for ProxySnapshots, ProxySnapper and + * ProxySnappers. + * + * For ProxySnapshot the implementation is more complicated since + * ProxySnapshots provides an interface to list and thus + * polymorphism does not work. Instead ProxySnapshot has an implementation + * pointer (pimpl idiom) which ensures polymorphism. Another possibility would + * be to provide an interface to list in ProxySnapshots but + * that is less intuitive to use. + * + * All objects are stored in containers or smart pointers to avoid manual + * cleanup. + * + * The interface copycats the classes Snapshot, Snapshots and Snapper of + * libsnapper. For consistency one may add a Snappers class to libsnapper. + * + * Limitations: The classes are tailored for the snapper command line + * interface. Other use-cases are not supported. + */ + + +// TODO maybe unique error handling, e.g. catch dbus exceptions and throw +// snapper or new exceptions + + +class ProxyConfig +{ + +public: + + ProxyConfig(const map& values) : values(values) {} + + const map& getAllValues() const { return values; } + + string getSubvolume() const; + + bool getValue(const string& key, string& value) const; + +private: + + map values; + +}; + + +class ProxySnapshot +{ + +public: + + SnapshotType getType() const { return impl->getType(); } + unsigned int getNum() const { return impl->getNum(); } + time_t getDate() const { return impl->getDate(); } + uid_t getUid() const { return impl->getUid(); } + unsigned int getPreNum() const { return impl->getPreNum(); } + const string& getDescription() const { return impl->getDescription(); } + const string& getCleanup() const { return impl->getCleanup(); } + const map& getUserdata() const { return impl->getUserdata(); } + + bool isCurrent() const { return impl->isCurrent(); } + + void mountFilesystemSnapshot(bool user_request) const + { impl->mountFilesystemSnapshot(user_request); } + + void umountFilesystemSnapshot(bool user_request) const + { impl->umountFilesystemSnapshot(user_request); } + +public: + + class Impl + { + + public: + + virtual ~Impl() {} + + virtual SnapshotType getType() const = 0; + virtual unsigned int getNum() const = 0; + virtual time_t getDate() const = 0; + virtual uid_t getUid() const = 0; + virtual unsigned int getPreNum() const = 0; + virtual const string& getDescription() const = 0; + virtual const string& getCleanup() const = 0; + virtual const map& getUserdata() const = 0; + + virtual bool isCurrent() const = 0; + + virtual string mountFilesystemSnapshot(bool user_request) const = 0; + virtual void umountFilesystemSnapshot(bool user_request) const = 0; + + }; + + ProxySnapshot(Impl* impl) : impl(impl) {} + + Impl& get_impl() { return *impl; } + const Impl& get_impl() const { return *impl; } + +private: + + std::unique_ptr impl; + +}; + + +class ProxySnapshots +{ + +public: + + virtual ~ProxySnapshots() {} + + typedef list::iterator iterator; + typedef list::const_iterator const_iterator; + + iterator begin() { return proxy_snapshots.begin(); } + const_iterator begin() const { return proxy_snapshots.begin(); } + + iterator end() { return proxy_snapshots.end(); } + const_iterator end() const { return proxy_snapshots.end(); } + + const_iterator getCurrent() const { return proxy_snapshots.begin(); } + + iterator find(unsigned int i); + const_iterator find(unsigned int i) const; + + iterator findNum(const string& str); + const_iterator findNum(const string& str) const; + + std::pair findNums(const string& str, const string& delim = ".."); + + const_iterator findPre(const_iterator post) const; + + iterator findPost(iterator pre); + const_iterator findPost(const_iterator pre) const; + + void emplace_back(ProxySnapshot::Impl* value) { proxy_snapshots.emplace_back(value); } + + void erase(iterator it) { proxy_snapshots.erase(it); } + +protected: + + list proxy_snapshots; + +}; + + +class ProxyComparison; + + +class ProxySnapper +{ + +public: + + virtual ~ProxySnapper() {} + + virtual const string& configName() const = 0; + + virtual ProxyConfig getConfig() const = 0; + virtual void setConfig(const ProxyConfig& proxy_config) = 0; + + virtual ProxySnapshots::const_iterator createSingleSnapshot(const SCD& scd) = 0; + virtual ProxySnapshots::const_iterator createSingleSnapshot(ProxySnapshots::const_iterator parent, + const SCD& scd) = 0; + virtual ProxySnapshots::const_iterator createSingleSnapshotOfDefault(const SCD& scd) = 0; + virtual ProxySnapshots::const_iterator createPreSnapshot(const SCD& scd) = 0; + virtual ProxySnapshots::const_iterator createPostSnapshot(ProxySnapshots::const_iterator pre, + const SCD& scd) = 0; + + virtual void modifySnapshot(ProxySnapshots::iterator snapshot, const SMD& smd) = 0; + + virtual void deleteSnapshots(vector snapshots, bool verbose) = 0; + + virtual ProxyComparison createComparison(const ProxySnapshot& lhs, const ProxySnapshot& rhs, + bool mount) = 0; + + virtual void syncFilesystem() const = 0; + + virtual ProxySnapshots& getSnapshots() = 0; + virtual const ProxySnapshots& getSnapshots() const = 0; + + virtual void setupQuota() = 0; + + virtual void prepareQuota() const = 0; + + virtual QuotaData queryQuotaData() const = 0; + +}; + + +class ProxySnappers +{ + +public: + + static ProxySnappers createDbus(); + static ProxySnappers createLib(const string& target_root); + + void createConfig(const string& config_name, const string& subvolume, const string& fstype, + const string& template_name) + { return impl->createConfig(config_name, subvolume, fstype, template_name); } + + void deleteConfig(const string& config_name) + { return impl->deleteConfig(config_name); } + + ProxySnapper* getSnapper(const string& config_name) + { return impl->getSnapper(config_name); } + + map getConfigs() const + { return impl->getConfigs(); } + + vector debug() const + { return impl->debug(); } + +public: + + class Impl + { + + public: + + virtual ~Impl() {} + + virtual void createConfig(const string& config_name, const string& subvolume, + const string& fstype, const string& template_name) = 0; + + virtual void deleteConfig(const string& config_name) = 0; + + virtual ProxySnapper* getSnapper(const string& config_name) = 0; + + virtual map getConfigs() const = 0; + + virtual vector debug() const = 0; + + }; + + ProxySnappers(Impl* impl) : impl(impl) {} + + Impl& get_impl() { return *impl; } + const Impl& get_impl() const { return *impl; } + +private: + + std::unique_ptr impl; + +}; + + +class ProxyComparison +{ + +public: + + const Files& getFiles() const { return impl->getFiles(); } + +public: + + class Impl + { + + public: + + virtual ~Impl() {} + + virtual const Files& getFiles() const = 0; + + }; + + ProxyComparison(Impl* impl) : impl(impl) {} + + Impl& get_impl() { return *impl; } + const Impl& get_impl() const { return *impl; } + +private: + + std::unique_ptr impl; + +}; + + +#endif diff --git a/client/snapper.cc b/client/snapper.cc index c3df0728..28ae9d60 100644 --- a/client/snapper.cc +++ b/client/snapper.cc @@ -46,9 +46,9 @@ #include "utils/Table.h" #include "utils/GetOpts.h" -#include "commands.h" #include "cleanup.h" #include "errors.h" +#include "proxy.h" #include "misc.h" @@ -58,29 +58,28 @@ using namespace std; struct Cmd { - typedef void (*cmd_func_t)(DBus::Connection* conn, Snapper* snapper); + typedef void (*cmd_func_t)(ProxySnappers* snappers, ProxySnapper* snapper); typedef void (*help_func_t)(); - Cmd(const string& name, cmd_func_t cmd_func, help_func_t help_func, - bool works_without_dbus, bool needs_snapper) - : name(name), cmd_func(cmd_func), help_func(help_func), - works_without_dbus(works_without_dbus), needs_snapper(needs_snapper) + Cmd(const string& name, cmd_func_t cmd_func, help_func_t help_func, bool needs_snapper) + : name(name), aliases(), cmd_func(cmd_func), help_func(help_func), + needs_snapper(needs_snapper) {} Cmd(const string& name, const vector& aliases, cmd_func_t cmd_func, - help_func_t help_func, bool works_without_dbus, bool needs_snapper) + help_func_t help_func, bool needs_snapper) : name(name), aliases(aliases), cmd_func(cmd_func), help_func(help_func), - works_without_dbus(works_without_dbus), needs_snapper(needs_snapper) + needs_snapper(needs_snapper) {} const string name; const vector aliases; const cmd_func_t cmd_func; const help_func_t help_func; - const bool works_without_dbus; const bool needs_snapper; }; + GetOpts getopts; bool quiet = false; @@ -94,10 +93,8 @@ string target_root = "/"; struct MyFiles : public Files { - friend struct MyComparison; - MyFiles(const FilePaths* file_paths) - : Files(file_paths) {} + MyFiles(const Files& files) : Files(files) {} void bulk_process(FILE* file, std::function callback); @@ -166,39 +163,6 @@ MyFiles::bulk_process(FILE* file, std::function callback) } -struct MyComparison -{ - MyComparison(DBus::Connection& conn, pair nums, bool mount) - : files(&file_paths) - { - command_create_xcomparison(conn, config_name, nums.first, nums.second); - - file_paths.system_path = command_get_xmount_point(conn, config_name, 0); - - if (mount) - { - if (nums.first != 0) - file_paths.pre_path = command_mount_xsnapshots(conn, config_name, nums.first, false); - else - file_paths.pre_path = file_paths.system_path; - - if (nums.second != 0) - file_paths.post_path = command_mount_xsnapshots(conn, config_name, nums.second, false); - else - file_paths.post_path = file_paths.system_path; - } - - list tmp = command_get_xfiles(conn, config_name, nums.first, nums.second); - for (list::const_iterator it = tmp.begin(); it != tmp.end(); ++it) - files.push_back(File(&file_paths, it->name, it->status)); - } - - FilePaths file_paths; - - MyFiles files; -}; - - void help_list_configs() { @@ -208,34 +172,8 @@ help_list_configs() } -list> -enum_configs(DBus::Connection* conn) -{ - list> configs; - - if (no_dbus) - { - list config_infos = Snapper::getConfigs(target_root); - for (list::const_iterator it = config_infos.begin(); it != config_infos.end(); ++it) - { - configs.push_back(make_pair(it->getConfigName(), it->getSubvolume())); - } - } - else - { - list config_infos = command_list_xconfigs(*conn); - for (list::const_iterator it = config_infos.begin(); it != config_infos.end(); ++it) - { - configs.push_back(make_pair(it->config_name, it->subvolume)); - } - } - - return configs; -} - - void -command_list_configs(DBus::Connection* conn, Snapper* snapper) +command_list_configs(ProxySnappers* snappers, ProxySnapper*) { getopts.parse("list-configs", GetOpts::no_options); if (getopts.hasArgs()) @@ -251,13 +189,12 @@ command_list_configs(DBus::Connection* conn, Snapper* snapper) header.add(_("Subvolume")); table.setHeader(header); - list > configs = enum_configs(conn); - - for (list >::iterator it = configs.begin(); it != configs.end(); ++it) + map configs = snappers->getConfigs(); + for (const map::value_type value : configs) { TableRow row; - row.add(it->first); - row.add(it->second); + row.add(value.first); + row.add(value.second.getSubvolume()); table.add(row); } @@ -279,7 +216,7 @@ help_create_config() void -command_create_config(DBus::Connection* conn, Snapper* snapper) +command_create_config(ProxySnappers* snappers, ProxySnapper*) { const struct option options[] = { { "fstype", required_argument, 0, 'f' }, @@ -318,14 +255,7 @@ command_create_config(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } - if (no_dbus) - { - Snapper::createConfig(config_name, target_root, subvolume, fstype, template_name); - } - else - { - command_create_xconfig(*conn, config_name, subvolume, fstype, template_name); - } + snappers->createConfig(config_name, subvolume, fstype, template_name); } @@ -339,7 +269,7 @@ help_delete_config() void -command_delete_config(DBus::Connection* conn, Snapper* snapper) +command_delete_config(ProxySnappers* snappers, ProxySnapper*) { getopts.parse("delete-config", GetOpts::no_options); if (getopts.hasArgs()) @@ -348,14 +278,7 @@ command_delete_config(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } - if (no_dbus) - { - Snapper::deleteConfig(config_name, target_root); - } - else - { - command_delete_xconfig(*conn, config_name); - } + snappers->deleteConfig(config_name); } @@ -369,7 +292,7 @@ help_get_config() void -command_get_config(DBus::Connection* conn, Snapper* snapper) +command_get_config(ProxySnappers* snappers, ProxySnapper* snapper) { getopts.parse("get-config", GetOpts::no_options); if (getopts.hasArgs()) @@ -385,30 +308,13 @@ command_get_config(DBus::Connection* conn, Snapper* snapper) header.add(_("Value")); table.setHeader(header); - if (no_dbus) - { - ConfigInfo config_info = Snapper::getConfig(config_name, target_root); - map raw = config_info.getAllValues(); - - for (map::const_iterator it = raw.begin(); it != raw.end(); ++it) - { - TableRow row; - row.add(it->first); - row.add(it->second); - table.add(row); - } - } - else + ProxyConfig config = snapper->getConfig(); + for (const map::value_type& value : config.getAllValues()) { - XConfigInfo ci = command_get_xconfig(*conn, config_name); - - for (map::const_iterator it = ci.raw.begin(); it != ci.raw.end(); ++it) - { - TableRow row; - row.add(it->first); - row.add(it->second); - table.add(row); - } + TableRow row; + row.add(value.first); + row.add(value.second); + table.add(row); } cout << table; @@ -425,7 +331,7 @@ help_set_config() void -command_set_config(DBus::Connection* conn, Snapper* snapper) +command_set_config(ProxySnappers* snappers, ProxySnapper* snapper) { getopts.parse("set-config", GetOpts::no_options); if (!getopts.hasArgs()) @@ -434,16 +340,9 @@ command_set_config(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } - map raw = read_configdata(getopts.getArgs()); + ProxyConfig config(read_configdata(getopts.getArgs())); - if (no_dbus) - { - snapper->setConfigInfo(raw); - } - else - { - command_set_xconfig(*conn, config_name, raw); - } + snapper->setConfig(config); } @@ -461,10 +360,13 @@ help_list() enum ListMode { LM_ALL, LM_SINGLE, LM_PRE_POST }; -void list_from_one_config(DBus::Connection* conn, Snapper* snapper, string config_name, ListMode list_mode); void -command_list(DBus::Connection* conn, Snapper* snapper) +list_from_one_config(ProxySnapper* snapper, ListMode list_mode); + + +void +command_list(ProxySnappers* snappers, ProxySnapper*) { const struct option options[] = { { "type", required_argument, 0, 't' }, @@ -498,28 +400,39 @@ command_list(DBus::Connection* conn, Snapper* snapper) } } - list > configs; - if ((opt = opts.find("all-configs")) != opts.end()) + vector tmp; + + if ((opt = opts.find("all-configs")) == opts.end()) { - configs = enum_configs(conn); + tmp.push_back(config_name); } else { - configs.push_back(make_pair(config_name, "")); + map configs = snappers->getConfigs(); + for (map::value_type it : configs) + tmp.push_back(it.first); } - for (list >::iterator it = configs.begin(); it != configs.end(); ++it) + for (vector::const_iterator it = tmp.begin(); it != tmp.end(); ++it) { - if (it != configs.begin()) - cout << endl; + ProxySnapper* snapper = snappers->getSnapper(*it); - if (configs.size() > 1) - cout << "Config: " << it->first << ", subvolume: " << it->second << endl; - list_from_one_config(conn, snapper, it->first, list_mode); + if (it != tmp.begin()) + cout << endl; + + if (tmp.size() > 1) + { + cout << "Config: " << snapper->configName() << ", subvolume: " + << snapper->getConfig().getSubvolume() << endl; + } + + list_from_one_config(snapper, list_mode); } } -void list_from_one_config(DBus::Connection* conn, Snapper* snapper, string config_name, ListMode list_mode) + +void +list_from_one_config(ProxySnapper* snapper, ListMode list_mode) { Table table; @@ -538,39 +451,19 @@ void list_from_one_config(DBus::Connection* conn, Snapper* snapper, string confi header.add(_("Userdata")); table.setHeader(header); - if (no_dbus) - { - const Snapshots& snapshots = snapper->getSnapshots(); - for (Snapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) - { - TableRow row; - row.add(toString(it1->getType())); - row.add(decString(it1->getNum())); - row.add(it1->getType() == POST ? decString(it1->getPreNum()) : ""); - row.add(it1->isCurrent() ? "" : datetime(it1->getDate(), utc, iso)); - row.add(username(it1->getUid())); - row.add(it1->getCleanup()); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); - table.add(row); - } - } - else + const ProxySnapshots& snapshots = snapper->getSnapshots(); + for (const ProxySnapshot& snapshot : snapshots) { - XSnapshots snapshots = command_list_xsnapshots(*conn, config_name); - for (XSnapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) - { - TableRow row; - row.add(toString(it1->getType())); - row.add(decString(it1->getNum())); - row.add(it1->getType() == POST ? decString(it1->getPreNum()) : ""); - row.add(it1->isCurrent() ? "" : datetime(it1->getDate(), utc, iso)); - row.add(username(it1->getUid())); - row.add(it1->getCleanup()); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); - table.add(row); - } + TableRow row; + row.add(toString(snapshot.getType())); + row.add(decString(snapshot.getNum())); + row.add(snapshot.getType() == POST ? decString(snapshot.getPreNum()) : ""); + row.add(snapshot.isCurrent() ? "" : datetime(snapshot.getDate(), utc, iso)); + row.add(username(snapshot.getUid())); + row.add(snapshot.getCleanup()); + row.add(snapshot.getDescription()); + row.add(show_userdata(snapshot.getUserdata())); + table.add(row); } } break; @@ -585,39 +478,19 @@ void list_from_one_config(DBus::Connection* conn, Snapper* snapper, string confi header.add(_("Userdata")); table.setHeader(header); - if (no_dbus) + const ProxySnapshots& snapshots = snapper->getSnapshots(); + for (const ProxySnapshot& snapshot : snapshots) { - const Snapshots& snapshots = snapper->getSnapshots(); - for (Snapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) - { - if (it1->getType() != SINGLE) - continue; - - TableRow row; - row.add(decString(it1->getNum())); - row.add(it1->isCurrent() ? "" : datetime(it1->getDate(), utc, iso)); - row.add(username(it1->getUid())); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); - table.add(row); - } - } - else - { - XSnapshots snapshots = command_list_xsnapshots(*conn, config_name); - for (XSnapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) - { - if (it1->getType() != SINGLE) - continue; - - TableRow row; - row.add(decString(it1->getNum())); - row.add(it1->isCurrent() ? "" : datetime(it1->getDate(), utc, iso)); - row.add(username(it1->getUid())); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); - table.add(row); - } + if (snapshot.getType() != SINGLE) + continue; + + TableRow row; + row.add(decString(snapshot.getNum())); + row.add(snapshot.isCurrent() ? "" : datetime(snapshot.getDate(), utc, iso)); + row.add(username(snapshot.getUid())); + row.add(snapshot.getDescription()); + row.add(show_userdata(snapshot.getUserdata())); + table.add(row); } } break; @@ -633,49 +506,27 @@ void list_from_one_config(DBus::Connection* conn, Snapper* snapper, string confi header.add(_("Userdata")); table.setHeader(header); - if (no_dbus) + const ProxySnapshots& snapshots = snapper->getSnapshots(); + for (ProxySnapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) { - const Snapshots& snapshots = snapper->getSnapshots(); - for (Snapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) - { - if (it1->getType() != PRE) - continue; - - Snapshots::const_iterator it2 = snapshots.findPost(it1); - if (it2 == snapshots.end()) - continue; - - TableRow row; - row.add(decString(it1->getNum())); - row.add(decString(it2->getNum())); - row.add(datetime(it1->getDate(), utc, iso)); - row.add(datetime(it2->getDate(), utc, iso)); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); - table.add(row); - } - } - else - { - XSnapshots snapshots = command_list_xsnapshots(*conn, config_name); - for (XSnapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) - { - if (it1->getType() != PRE) - continue; - - XSnapshots::const_iterator it2 = snapshots.findPost(it1); - if (it2 == snapshots.end()) - continue; - - TableRow row; - row.add(decString(it1->getNum())); - row.add(decString(it2->getNum())); - row.add(datetime(it1->getDate(), utc, iso)); - row.add(datetime(it2->getDate(), utc, iso)); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); - table.add(row); - } + if (it1->getType() != PRE) + continue; + + ProxySnapshots::const_iterator it2 = snapshots.findPost(it1); + if (it2 == snapshots.end()) + continue; + + const ProxySnapshot& pre = *it1; + const ProxySnapshot& post = *it2; + + TableRow row; + row.add(decString(pre.getNum())); + row.add(decString(post.getNum())); + row.add(datetime(pre.getDate(), utc, iso)); + row.add(datetime(post.getDate(), utc, iso)); + row.add(pre.getDescription()); + row.add(show_userdata(pre.getUserdata())); + table.add(row); } } break; @@ -704,7 +555,7 @@ help_create() void -command_create(DBus::Connection* conn, Snapper* snapper) +command_create(ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "type", required_argument, 0, 't' }, @@ -726,12 +577,13 @@ command_create(DBus::Connection* conn, Snapper* snapper) enum CreateType { CT_SINGLE, CT_PRE, CT_POST, CT_PRE_POST }; + const ProxySnapshots& snapshots = snapper->getSnapshots(); + CreateType type = CT_SINGLE; - unsigned int num1 = 0; + ProxySnapshots::const_iterator snapshot1 = snapshots.end(); + ProxySnapshots::const_iterator snapshot2 = snapshots.end(); bool print_number = false; - string description; - string cleanup; - map userdata; + SCD scd; string command; GetOpts::parsed_opts::const_iterator opt; @@ -754,19 +606,19 @@ command_create(DBus::Connection* conn, Snapper* snapper) } if ((opt = opts.find("pre-number")) != opts.end()) - num1 = read_num(opt->second); + snapshot1 = snapshots.findNum(opt->second); if ((opt = opts.find("print-number")) != opts.end()) print_number = true; if ((opt = opts.find("description")) != opts.end()) - description = opt->second; + scd.description = opt->second; if ((opt = opts.find("cleanup-algorithm")) != opts.end()) - cleanup = opt->second; + scd.cleanup = opt->second; if ((opt = opts.find("userdata")) != opts.end()) - userdata = read_userdata(opt->second); + scd.userdata = read_userdata(opt->second); if ((opt = opts.find("command")) != opts.end()) { @@ -774,7 +626,7 @@ command_create(DBus::Connection* conn, Snapper* snapper) type = CT_PRE_POST; } - if (type == CT_POST && (num1 == 0)) + if (type == CT_POST && snapshot1 == snapshots.end()) { cerr << _("Missing or invalid pre-number.") << endl; exit(EXIT_FAILURE); @@ -789,34 +641,29 @@ command_create(DBus::Connection* conn, Snapper* snapper) switch (type) { case CT_SINGLE: { - unsigned int num1 = command_create_single_xsnapshot(*conn, config_name, description, - cleanup, userdata); + snapshot1 = snapper->createSingleSnapshot(scd); if (print_number) - cout << num1 << endl; + cout << snapshot1->getNum() << endl; } break; case CT_PRE: { - unsigned int num1 = command_create_pre_xsnapshot(*conn, config_name, description, - cleanup, userdata); + snapshot1 = snapper->createPreSnapshot(scd); if (print_number) - cout << num1 << endl; + cout << snapshot1->getNum() << endl; } break; case CT_POST: { - unsigned int num2 = command_create_post_xsnapshot(*conn, config_name, num1, description, - cleanup, userdata); + snapshot2 = snapper->createPostSnapshot(snapshot1, scd); if (print_number) - cout << num2 << endl; + cout << snapshot2->getNum() << endl; } break; case CT_PRE_POST: { - unsigned int num1 = command_create_pre_xsnapshot(*conn, config_name, description, - cleanup, userdata); + snapshot1 = snapper->createPreSnapshot(scd); system(command.c_str()); - unsigned int num2 = command_create_post_xsnapshot(*conn, config_name, num1, "", - cleanup, userdata); + snapshot2 = snapper->createPostSnapshot(snapshot1, scd); if (print_number) - cout << num1 << ".." << num2 << endl; + cout << snapshot1->getNum() << ".." << snapshot2->getNum() << endl; } break; } } @@ -837,7 +684,7 @@ help_modify() void -command_modify(DBus::Connection* conn, Snapper* snapper) +command_modify(ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "description", required_argument, 0, 'd' }, @@ -853,24 +700,32 @@ command_modify(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } + ProxySnapshots& snapshots = snapper->getSnapshots(); + while (getopts.hasArgs()) { - unsigned int num = read_num(getopts.popArg()); + ProxySnapshots::iterator snapshot = snapshots.findNum(getopts.popArg()); - XSnapshot data = command_get_xsnapshot(*conn, config_name, num); + SMD smd; GetOpts::parsed_opts::const_iterator opt; if ((opt = opts.find("description")) != opts.end()) - data.description = opt->second; + smd.description = opt->second; + else + smd.description = snapshot->getDescription(); if ((opt = opts.find("cleanup-algorithm")) != opts.end()) - data.cleanup = opt->second; + smd.cleanup = opt->second; + else + smd.cleanup = snapshot->getCleanup(); if ((opt = opts.find("userdata")) != opts.end()) - data.userdata = read_userdata(opt->second, data.userdata); + smd.userdata = read_userdata(opt->second, snapshot->getUserdata()); + else + smd.userdata = snapshot->getUserdata(); - command_set_xsnapshot(*conn, config_name, num, data); + snapper->modifySnapshot(snapshot, smd); } } @@ -888,7 +743,7 @@ help_delete() void -command_delete(DBus::Connection* conn, Snapper* snapper) +command_delete(ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "sync", no_argument, 0, 's' }, @@ -909,9 +764,9 @@ command_delete(DBus::Connection* conn, Snapper* snapper) if ((opt = opts.find("sync")) != opts.end()) sync = true; - XSnapshots snapshots = command_list_xsnapshots(*conn, config_name); + ProxySnapshots& snapshots = snapper->getSnapshots(); - list nums; + vector nums; while (getopts.hasArgs()) { @@ -919,31 +774,34 @@ command_delete(DBus::Connection* conn, Snapper* snapper) if (arg.find_first_of("-") == string::npos) { - unsigned int i = read_num(arg); - nums.push_back(i); + ProxySnapshots::iterator tmp = snapshots.findNum(arg); + nums.push_back(tmp); } else { - pair r(read_nums(arg, "-")); + pair range = + snapshots.findNums(arg, "-"); - if (r.first > r.second) - swap(r.first, r.second); + if (range.first->getNum() > range.second->getNum()) + swap(range.first, range.second); - for (unsigned int i = r.first; i <= r.second; ++i) + for (unsigned int i = range.first->getNum(); i <= range.second->getNum(); ++i) { - if (snapshots.find(i) != snapshots.end() && - find(nums.begin(), nums.end(), i) == nums.end()) + ProxySnapshots::iterator x = snapshots.find(i); + if (x != snapshots.end()) { - nums.push_back(i); + if (find_if(nums.begin(), nums.end(), [i](ProxySnapshots::iterator it) + { return it->getNum() == i; }) == nums.end()) + nums.push_back(x); } } } } - command_delete_xsnapshots(*conn, config_name, nums, verbose); + snapper->deleteSnapshots(nums, verbose); if (sync) - command_xsync(*conn, config_name); + snapper->syncFilesystem(); } @@ -957,7 +815,7 @@ help_mount() void -command_mount(DBus::Connection* conn, Snapper* snapper) +command_mount(ProxySnappers* snappers, ProxySnapper* snapper) { getopts.parse("mount", GetOpts::no_options); if (!getopts.hasArgs()) @@ -966,20 +824,12 @@ command_mount(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } + const ProxySnapshots& snapshots = snapper->getSnapshots(); + while (getopts.hasArgs()) { - if (no_dbus) - { - Snapshots::iterator snapshot = read_num(snapper, getopts.popArg()); - - snapshot->mountFilesystemSnapshot(true); - } - else - { - unsigned int num = read_num(getopts.popArg()); - - command_mount_xsnapshots(*conn, config_name, num, true); - } + ProxySnapshots::const_iterator snapshot = snapshots.findNum(getopts.popArg()); + snapshot->mountFilesystemSnapshot(true); } } @@ -994,29 +844,21 @@ help_umount() void -command_umount(DBus::Connection* conn, Snapper* snapper) +command_umount(ProxySnappers* snappers, ProxySnapper* snapper) { - getopts.parse("mount", GetOpts::no_options); + getopts.parse("umount", GetOpts::no_options); if (!getopts.hasArgs()) { - cerr << _("Command 'mount' needs at least one argument.") << endl; + cerr << _("Command 'umount' needs at least one argument.") << endl; exit(EXIT_FAILURE); } + const ProxySnapshots& snapshots = snapper->getSnapshots(); + while (getopts.hasArgs()) { - if (no_dbus) - { - Snapshots::iterator snapshot = read_num(snapper, getopts.popArg()); - - snapshot->umountFilesystemSnapshot(true); - } - else - { - unsigned int num = read_num(getopts.popArg()); - - command_umount_xsnapshots(*conn, config_name, num, true); - } + ProxySnapshots::const_iterator snapshot = snapshots.findNum(getopts.popArg()); + snapshot->umountFilesystemSnapshot(true); } } @@ -1034,7 +876,7 @@ help_status() void -command_status(DBus::Connection* conn, Snapper* snapper) +command_status(ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "output", required_argument, 0, 'o' }, @@ -1057,10 +899,14 @@ command_status(DBus::Connection* conn, Snapper* snapper) GetOpts::parsed_opts::const_iterator opt; - pair nums(read_nums(getopts.popArg())); + ProxySnapshots& snapshots = snapper->getSnapshots(); - MyComparison comparison(*conn, nums, false); - MyFiles& files = comparison.files; + pair range = + snapshots.findNums(getopts.popArg()); + + ProxyComparison comparison = snapper->createComparison(*range.first, *range.second, false); + + MyFiles files(comparison.getFiles()); FILE* file = stdout; @@ -1098,7 +944,7 @@ help_diff() void -command_diff(DBus::Connection* conn, Snapper* snapper) +command_diff(ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "input", required_argument, 0, 'i' }, @@ -1135,10 +981,14 @@ command_diff(DBus::Connection* conn, Snapper* snapper) if ((opt = opts.find("extensions")) != opts.end()) differ.extensions = opt->second; - pair nums(read_nums(getopts.popArg())); + ProxySnapshots& snapshots = snapper->getSnapshots(); + + pair range = + snapshots.findNums(getopts.popArg()); - MyComparison comparison(*conn, nums, true); - MyFiles& files = comparison.files; + ProxyComparison comparison = snapper->createComparison(*range.first, *range.second, true); + + MyFiles files(comparison.getFiles()); files.bulk_process(file, [differ](const File& file) { differ.run(file.getAbsolutePath(LOC_PRE), file.getAbsolutePath(LOC_POST)); @@ -1159,7 +1009,7 @@ help_undo() void -command_undo(DBus::Connection* conn, Snapper* snapper) +command_undo(ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "input", required_argument, 0, 'i' }, @@ -1173,7 +1023,10 @@ command_undo(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } - pair nums(read_nums(getopts.popArg())); + ProxySnapshots& snapshots = snapper->getSnapshots(); + + pair range = + snapshots.findNums(getopts.popArg()); FILE* file = NULL; @@ -1189,14 +1042,15 @@ command_undo(DBus::Connection* conn, Snapper* snapper) } } - if (nums.first == 0) + if (range.first->isCurrent()) { cerr << _("Invalid snapshots.") << endl; exit(EXIT_FAILURE); } - MyComparison comparison(*conn, nums, true); - MyFiles& files = comparison.files; + ProxyComparison comparison = snapper->createComparison(*range.first, *range.second, true); + + MyFiles files(comparison.getFiles()); files.bulk_process(file, [](File& file) { file.setUndo(true); @@ -1268,10 +1122,13 @@ command_undo(DBus::Connection* conn, Snapper* snapper) #ifdef ENABLE_ROLLBACK const Filesystem* -getFilesystem(const XConfigInfo &ci, Snapper* snapper) +getFilesystem(const ProxyConfig& config) { - map::const_iterator it = ci.raw.find(KEY_FSTYPE); - if (it == ci.raw.end()) + const map& raw = config.getAllValues(); + + map::const_iterator pos1 = raw.find(KEY_FSTYPE); + map::const_iterator pos2 = raw.find(KEY_SUBVOLUME); + if (pos1 == raw.end() || pos2 == raw.end()) { cerr << _("Failed to initialize filesystem handler.") << endl; exit(EXIT_FAILURE); @@ -1279,7 +1136,7 @@ getFilesystem(const XConfigInfo &ci, Snapper* snapper) try { - return Filesystem::create(it->second, ci.subvolume, target_root); + return Filesystem::create(pos1->second, pos2->second, target_root); } catch (const InvalidConfigException& e) { @@ -1289,19 +1146,6 @@ getFilesystem(const XConfigInfo &ci, Snapper* snapper) } } -const string -getSubvolume(const XConfigInfo &ci, Snapper* snapper) -{ - map::const_iterator it = ci.raw.find(KEY_SUBVOLUME); - if (it == ci.raw.end()) - { - cerr << _("Failed to initialize subvolume handler.") << endl; - exit(EXIT_FAILURE); - } - - return it->second; -} - void help_rollback() @@ -1319,7 +1163,7 @@ help_rollback() void -command_rollback(DBus::Connection* conn, Snapper* snapper) +command_rollback(ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "print-number", no_argument, 0, 'p' }, @@ -1337,9 +1181,7 @@ command_rollback(DBus::Connection* conn, Snapper* snapper) } bool print_number = false; - string description; - string cleanup; - map userdata; + SCD scd; GetOpts::parsed_opts::const_iterator opt; @@ -1347,24 +1189,24 @@ command_rollback(DBus::Connection* conn, Snapper* snapper) print_number = true; if ((opt = opts.find("description")) != opts.end()) - description = opt->second; + scd.description = opt->second; if ((opt = opts.find("cleanup-algorithm")) != opts.end()) - cleanup = opt->second; + scd.cleanup = opt->second; if ((opt = opts.find("userdata")) != opts.end()) - userdata = read_userdata(opt->second); + scd.userdata = read_userdata(opt->second); - XConfigInfo ci = command_get_xconfig(*conn, config_name); + ProxyConfig config = snapper->getConfig(); - const Filesystem* filesystem = getFilesystem(ci, snapper); + const Filesystem* filesystem = getFilesystem(config); if (filesystem->fstype() != "btrfs") { cerr << _("Command 'rollback' only available for btrfs.") << endl; exit(EXIT_FAILURE); } - const string subvolume = getSubvolume(ci, snapper); + const string subvolume = config.getSubvolume(); if (subvolume != "/") { cerr << sformat(_("Command 'rollback' cannot be used on a non-root subvolume %s."), @@ -1372,53 +1214,63 @@ command_rollback(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } - unsigned int num1; - unsigned int num2; + ProxySnapshots& snapshots = snapper->getSnapshots(); + + ProxySnapshots::const_iterator snapshot1 = snapshots.end(); + ProxySnapshots::const_iterator snapshot2 = snapshots.end(); if (getopts.numArgs() == 0) { if (!quiet) cout << _("Creating read-only snapshot of default subvolume.") << flush; - num1 = command_create_single_xsnapshot_of_default(*conn, config_name, true, - description, cleanup, - userdata); + + scd.read_only = true; + snapshot1 = snapper->createSingleSnapshotOfDefault(scd); + if (!quiet) - cout << " " << sformat(_("(Snapshot %d.)"), num1) << endl; + cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl; if (!quiet) - cout << _("Creating read-write snapshot of current subvolume.") <createSingleSnapshot(snapshots.getCurrent(), scd); + if (!quiet) - cout << " " << sformat(_("(Snapshot %d.)"), num2) << endl; + cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl; } else { - unsigned int tmp = read_num(getopts.popArg()); + ProxySnapshots::const_iterator tmp = snapshots.findNum(getopts.popArg()); if (!quiet) cout << _("Creating read-only snapshot of current system.") << flush; - num1 = command_create_single_xsnapshot(*conn, config_name, description, - cleanup, userdata); + + snapshot1 = snapper->createSingleSnapshot(scd); + if (!quiet) - cout << " " << sformat(_("(Snapshot %d.)"), num1) << endl; + cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl; if (!quiet) - cout << sformat(_("Creating read-write snapshot of snapshot %d."), tmp) << flush; - num2 = command_create_single_xsnapshot_v2(*conn, config_name, tmp, false, - description, cleanup, userdata); + cout << sformat(_("Creating read-write snapshot of snapshot %d."), tmp->getNum()) << flush; + + scd.read_only = false; + snapshot2 = snapper->createSingleSnapshot(tmp, scd); + if (!quiet) - cout << " " << sformat(_("(Snapshot %d.)"), num2) << endl; + cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl; } if (!quiet) - cout << sformat(_("Setting default subvolume to snapshot %d."), num2) << endl; - filesystem->setDefault(num2); + cout << sformat(_("Setting default subvolume to snapshot %d."), snapshot2->getNum()) << endl; - Hooks::rollback(filesystem->snapshotDir(num1), filesystem->snapshotDir(num2)); + filesystem->setDefault(snapshot2->getNum()); + + Hooks::rollback(filesystem->snapshotDir(snapshot1->getNum()), + filesystem->snapshotDir(snapshot2->getNum())); if (print_number) - cout << num2 << endl; + cout << snapshot2->getNum() << endl; } #endif @@ -1434,7 +1286,7 @@ help_setup_quota() void -command_setup_quota(DBus::Connection* conn, Snapper* snapper) +command_setup_quota(ProxySnappers* snappers, ProxySnapper* snapper) { GetOpts::parsed_opts opts = getopts.parse("setup-quota", GetOpts::no_options); if (getopts.numArgs() != 0) @@ -1443,14 +1295,7 @@ command_setup_quota(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } - if (no_dbus) - { - snapper->setupQuota(); - } - else - { - command_setup_quota(*conn, config_name); - } + snapper->setupQuota(); } @@ -1464,7 +1309,7 @@ help_cleanup() void -command_cleanup(DBus::Connection* conn, Snapper* snapper) +command_cleanup(ProxySnappers* snappers, ProxySnapper* snapper) { GetOpts::parsed_opts opts = getopts.parse("cleanup", GetOpts::no_options); if (getopts.numArgs() != 1) @@ -1477,15 +1322,15 @@ command_cleanup(DBus::Connection* conn, Snapper* snapper) if (cleanup == "number") { - do_cleanup_number(*conn, config_name, verbose); + do_cleanup_number(snapper, verbose); } else if (cleanup == "timeline") { - do_cleanup_timeline(*conn, config_name, verbose); + do_cleanup_timeline(snapper, verbose); } else if (cleanup == "empty-pre-post") { - do_cleanup_empty_pre_post(*conn, config_name, verbose); + do_cleanup_empty_pre_post(snapper, verbose); } else { @@ -1502,7 +1347,7 @@ help_debug() void -command_debug(DBus::Connection* conn, Snapper* snapper) +command_debug(ProxySnappers* snappers, ProxySnapper*) { getopts.parse("debug", GetOpts::no_options); if (getopts.hasArgs()) @@ -1511,9 +1356,8 @@ command_debug(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } - vector lines = command_xdebug(*conn); - for (vector::const_iterator it = lines.begin(); it != lines.end(); ++it) - cout << *it << endl; + for (const string& line : snappers->debug()) + cout << line << endl; } @@ -1547,7 +1391,7 @@ print_xa_diff(const string loc_pre, const string loc_post) } void -command_xa_diff(DBus::Connection* conn, Snapper* snapper) +command_xa_diff(ProxySnappers* snappers, ProxySnapper* snapper) { GetOpts::parsed_opts opts = getopts.parse("xadiff", GetOpts::no_options); if (getopts.numArgs() < 1) @@ -1556,10 +1400,14 @@ command_xa_diff(DBus::Connection* conn, Snapper* snapper) exit(EXIT_FAILURE); } - pair nums(read_nums(getopts.popArg())); + ProxySnapshots& snapshots = snapper->getSnapshots(); + + pair range = + snapshots.findNums(getopts.popArg()); - MyComparison comparison(*conn, nums, true); - MyFiles& files = comparison.files; + ProxyComparison comparison = snapper->createComparison(*range.first, *range.second, true); + + MyFiles files(comparison.getFiles()); if (getopts.numArgs() == 0) { @@ -1655,36 +1503,36 @@ main(int argc, char** argv) catch (const runtime_error& e) { cerr << "Failed to set locale. Fix your system." << endl; - exit (EXIT_FAILURE); + exit(EXIT_FAILURE); } setLogDo(&log_do); setLogQuery(&log_query); const list cmds = { - Cmd("list-configs", command_list_configs, help_list_configs, true, false), - Cmd("create-config", command_create_config, help_create_config, true, false), - Cmd("delete-config", command_delete_config, help_delete_config, true, false), - Cmd("get-config", command_get_config, help_get_config, true, false), - Cmd("set-config", command_set_config, help_set_config, true, true), - Cmd("list", { "ls" }, command_list, help_list, true, true), - Cmd("create", command_create, help_create, false, true), - Cmd("modify", command_modify, help_modify, false, true), - Cmd("delete", { "remove", "rm" }, command_delete, help_delete, false, true), - Cmd("mount", command_mount, help_mount, true, true), - Cmd("umount", command_umount, help_umount, true, true), - Cmd("status", command_status, help_status, false, true), - Cmd("diff", command_diff, help_diff, false, true), + Cmd("list-configs", command_list_configs, help_list_configs, false), + Cmd("create-config", command_create_config, help_create_config, false), + Cmd("delete-config", command_delete_config, help_delete_config, false), + Cmd("get-config", command_get_config, help_get_config, true), + Cmd("set-config", command_set_config, help_set_config, true), + Cmd("list", { "ls" }, command_list, help_list, false), + Cmd("create", command_create, help_create, true), + Cmd("modify", command_modify, help_modify, true), + Cmd("delete", { "remove", "rm" }, command_delete, help_delete, true), + Cmd("mount", command_mount, help_mount, true), + Cmd("umount", command_umount, help_umount, true), + Cmd("status", command_status, help_status, true), + Cmd("diff", command_diff, help_diff, true), #ifdef ENABLE_XATTRS - Cmd("xadiff", command_xa_diff, help_xa_diff, false, true), + Cmd("xadiff", command_xa_diff, help_xa_diff, true), #endif - Cmd("undochange", command_undo, help_undo, false, true), + Cmd("undochange", command_undo, help_undo, true), #ifdef ENABLE_ROLLBACK - Cmd("rollback", command_rollback, help_rollback, false, true), + Cmd("rollback", command_rollback, help_rollback, true), #endif - Cmd("setup-quota", command_setup_quota, help_setup_quota, true, true), - Cmd("cleanup", command_cleanup, help_cleanup, false, true), - Cmd("debug", command_debug, help_debug, false, false) + Cmd("setup-quota", command_setup_quota, help_setup_quota, true), + Cmd("cleanup", command_cleanup, help_cleanup, true), + Cmd("debug", command_debug, help_debug, false) }; const struct option options[] = { @@ -1783,26 +1631,13 @@ main(int argc, char** argv) try { - if (no_dbus) - { - if (!cmd->works_without_dbus) - { - cerr << sformat(_("Command '%s' does not work without DBus."), cmd->name.c_str()) << endl; - exit(EXIT_FAILURE); - } - - Snapper* snapper = cmd->needs_snapper ? new Snapper(config_name, target_root) : NULL; - - (*cmd->cmd_func)(NULL, snapper); + ProxySnappers snappers(no_dbus ? ProxySnappers::createLib(target_root) : + ProxySnappers::createDbus()); - delete snapper; - } + if (cmd->needs_snapper) + (*cmd->cmd_func)(&snappers, snappers.getSnapper(config_name)); else - { - DBus::Connection conn(DBUS_BUS_SYSTEM); - - (*cmd->cmd_func)(&conn, NULL); - } + (*cmd->cmd_func)(&snappers, nullptr); } catch (const DBus::ErrorException& e) { @@ -1824,6 +1659,12 @@ main(int argc, char** argv) cerr << _("Failure") << " (" << e.what() << ")." << endl; exit(EXIT_FAILURE); } + catch (const IllegalSnapshotException& e) + { + SN_CAUGHT(e); + cerr << _("Illegal snapshot.") << endl; + exit(EXIT_FAILURE); + } catch (const ConfigNotFoundException& e) { SN_CAUGHT(e); @@ -1890,6 +1731,12 @@ main(int argc, char** argv) cerr << sformat(_("Quota error (%s)."), e.what()) << endl; exit(EXIT_FAILURE); } + catch (const Exception& e) + { + SN_CAUGHT(e); + cerr << sformat(_("Error (%s)."), e.what()) << endl; + exit(EXIT_FAILURE); + } exit(EXIT_SUCCESS); } diff --git a/client/systemd-helper.cc b/client/systemd-helper.cc index 3c76371f..b14bbb1c 100644 --- a/client/systemd-helper.cc +++ b/client/systemd-helper.cc @@ -1,5 +1,6 @@ /* * Copyright (c) [2014-2015] Novell, Inc. + * Copyright (c) 2016 SUSE LLC * * All Rights Reserved. * @@ -28,7 +29,7 @@ #include "utils/text.h" #include "utils/GetOpts.h" -#include "commands.h" +#include "proxy.h" #include "cleanup.h" #include "errors.h" #include "misc.h" @@ -38,48 +39,56 @@ using namespace snapper; using namespace std; -bool do_timeline = false; -bool do_cleanup = false; - - void -timeline(DBus::Connection* conn, const map& userdata) +timeline(ProxySnappers* snappers, const map& userdata) { - list config_infos = command_list_xconfigs(*conn); - for (const XConfigInfo& config_info : config_infos) + map configs = snappers->getConfigs(); + for (const map::value_type value : configs) { - map::const_iterator pos1 = config_info.raw.find("TIMELINE_CREATE"); - if (pos1 != config_info.raw.end() && pos1->second == "yes") + const map& raw = value.second.getAllValues(); + + map::const_iterator pos1 = raw.find("TIMELINE_CREATE"); + if (pos1 != raw.end() && pos1->second == "yes") { - command_create_single_xsnapshot(*conn, config_info.config_name, "timeline", - "timeline", userdata); + ProxySnapper* snapper = snappers->getSnapper(value.first); + + SCD scd; + scd.description = "timeline"; + scd.cleanup = "timeline"; + scd.userdata = userdata; + + snapper->createSingleSnapshot(scd); } } } void -cleanup(DBus::Connection* conn) +cleanup(ProxySnappers* snappers) { - list config_infos = command_list_xconfigs(*conn); - for (const XConfigInfo& config_info : config_infos) + map configs = snappers->getConfigs(); + for (const map::value_type value : configs) { - map::const_iterator pos1 = config_info.raw.find("NUMBER_CLEANUP"); - if (pos1 != config_info.raw.end() && pos1->second == "yes") + const map& raw = value.second.getAllValues(); + + ProxySnapper* snapper = snappers->getSnapper(value.first); + + map::const_iterator pos1 = raw.find("NUMBER_CLEANUP"); + if (pos1 != raw.end() && pos1->second == "yes") { - do_cleanup_number(*conn, config_info.config_name, false); + do_cleanup_number(snapper, false); } - map::const_iterator pos2 = config_info.raw.find("TIMELINE_CLEANUP"); - if (pos2 != config_info.raw.end() && pos2->second == "yes") + map::const_iterator pos2 = raw.find("TIMELINE_CLEANUP"); + if (pos2 != raw.end() && pos2->second == "yes") { - do_cleanup_timeline(*conn, config_info.config_name, false); + do_cleanup_timeline(snapper, false); } - map::const_iterator pos3 = config_info.raw.find("EMPTY_PRE_POST_CLEANUP"); - if (pos3 != config_info.raw.end() && pos3->second == "yes") + map::const_iterator pos3 = raw.find("EMPTY_PRE_POST_CLEANUP"); + if (pos3 != raw.end() && pos3->second == "yes") { - do_cleanup_empty_pre_post(*conn, config_info.config_name, false); + do_cleanup_empty_pre_post(snapper, false); } } } @@ -97,6 +106,9 @@ main(int argc, char** argv) { 0, 0, 0, 0 } }; + bool do_timeline = false; + bool do_cleanup = false; + map userdata; GetOpts getopts; @@ -118,13 +130,13 @@ main(int argc, char** argv) try { - DBus::Connection conn(DBUS_BUS_SYSTEM); + ProxySnappers snappers(ProxySnappers::createDbus()); if (do_timeline) - timeline(&conn, userdata); + timeline(&snappers, userdata); if (do_cleanup) - cleanup(&conn); + cleanup(&snappers); } catch (const DBus::ErrorException& e) { diff --git a/client/types.cc b/client/types.cc index 9501435c..e3acbb85 100644 --- a/client/types.cc +++ b/client/types.cc @@ -27,83 +27,6 @@ #include "types.h" -XSnapshots::const_iterator -XSnapshots::find(unsigned int num) const -{ - for (const_iterator it = begin(); it != end(); ++it) - { - if (it->getNum() == num) - return it; - } - - return end(); -} - - -XSnapshots::iterator -XSnapshots::findPre(iterator post) -{ - if (post == entries.end() || post->isCurrent() || post->getType() != POST) - SN_THROW(IllegalSnapshotException()); - - for (iterator it = begin(); it != end(); ++it) - { - if (it->getType() == PRE && it->getNum() == post->getPreNum()) - return it; - } - - return end(); -} - - -XSnapshots::const_iterator -XSnapshots::findPre(const_iterator post) const -{ - if (post == entries.end() || post->isCurrent() || post->getType() != POST) - SN_THROW(IllegalSnapshotException()); - - for (const_iterator it = begin(); it != end(); ++it) - { - if (it->getType() == PRE && it->getNum() == post->getPreNum()) - return it; - } - - return end(); -} - - -XSnapshots::iterator -XSnapshots::findPost(iterator pre) -{ - if (pre == entries.end() || pre->isCurrent() || pre->getType() != PRE) - SN_THROW(IllegalSnapshotException()); - - for (iterator it = begin(); it != end(); ++it) - { - if (it->getType() == POST && it->getPreNum() == pre->getNum()) - return it; - } - - return end(); -} - - -XSnapshots::const_iterator -XSnapshots::findPost(const_iterator pre) const -{ - if (pre == entries.end() || pre->isCurrent() || pre->getType() != PRE) - SN_THROW(IllegalSnapshotException()); - - for (const_iterator it = begin(); it != end(); ++it) - { - if (it->getType() == POST && it->getPreNum() == pre->getNum()) - return it; - } - - return end(); -} - - namespace DBus { const char* TypeInfo::signature = "(ssa{ss})"; @@ -153,7 +76,7 @@ namespace DBus Hihi& - operator>>(Hihi& hihi, XQuotaData& data) + operator>>(Hihi& hihi, QuotaData& data) { hihi.open_recurse(); hihi >> data.size >> data.used; diff --git a/client/types.h b/client/types.h index c2ec91b9..de1a5da4 100644 --- a/client/types.h +++ b/client/types.h @@ -22,11 +22,11 @@ #include -#include +#include #include using std::string; -using std::list; +using std::vector; using std::map; #include "dbus/DBusMessage.h" @@ -34,6 +34,7 @@ using std::map; #include "snapper/Snapshot.h" #include "snapper/File.h" #include "snapper/SnapperTmpl.h" +#include "snapper/Snapper.h" using namespace snapper; @@ -44,14 +45,6 @@ struct XConfigInfo string subvolume; map raw; - - template - void read(const char* name, Type& value) - { - map::const_iterator pos = raw.find(name); - if (pos != raw.end()) - pos->second >> value; - } }; @@ -60,7 +53,6 @@ struct XSnapshot SnapshotType getType() const { return type; } unsigned int getNum() const { return num; } - bool isCurrent() const { return num == 0; } time_t getDate() const { return date; } @@ -87,26 +79,12 @@ struct XSnapshot struct XSnapshots { - typedef list::iterator iterator; - typedef list::const_iterator const_iterator; + typedef vector::const_iterator const_iterator; - iterator begin() { return entries.begin(); } const_iterator begin() const { return entries.begin(); } - - iterator end() { return entries.end(); } const_iterator end() const { return entries.end(); } - const_iterator find(unsigned int num) const; - - iterator findPre(iterator post); - const_iterator findPre(const_iterator post) const; - - iterator findPost(iterator pre); - const_iterator findPost(const_iterator pre) const; - - iterator erase(iterator pos) { return entries.erase(pos); } - - list entries; + vector entries; }; @@ -117,13 +95,6 @@ struct XFile }; -struct XQuotaData -{ - uint64_t size; - uint64_t used; -}; - - namespace DBus { @@ -140,6 +111,6 @@ namespace DBus Hihi& operator>>(Hihi& hihi, XFile& data); - Hihi& operator>>(Hihi& hihi, XQuotaData& data); + Hihi& operator>>(Hihi& hihi, QuotaData& data); } diff --git a/doc/snapper.xml.in b/doc/snapper.xml.in index 09267034..616e36e1 100644 --- a/doc/snapper.xml.in +++ b/doc/snapper.xml.in @@ -222,7 +222,7 @@ - Operate without a DBus connection. Only works for some commands. + Operate without a DBus connection. Use with caution since a running snapperd will not know about modifications made to the system. diff --git a/examples/c++-lib/CreateNumber.cc b/examples/c++-lib/CreateNumber.cc index 00abab03..46fbb153 100644 --- a/examples/c++-lib/CreateNumber.cc +++ b/examples/c++-lib/CreateNumber.cc @@ -12,11 +12,11 @@ using namespace std; void -deleteAll() +delete_all() { - Snapper* sh = new Snapper("testsuite", "/"); + Snapper snapper("testsuite", "/"); - Snapshots snapshots = sh->getSnapshots(); + Snapshots snapshots = snapper.getSnapshots(); vector tmp; for (Snapshots::iterator it = snapshots.begin(); it != snapshots.end(); ++it) @@ -24,18 +24,14 @@ deleteAll() tmp.push_back(it); for (vector::iterator it = tmp.begin(); it != tmp.end(); ++it) - sh->deleteSnapshot(*it); - - delete sh; + snapper.deleteSnapshot(*it); } -int -main() +void +create_number() { - deleteAll(); - - Snapper* sh = new Snapper("testsuite", "/"); + Snapper snapper("testsuite", "/"); for (size_t i = 0; i < 100; ++i) { @@ -46,10 +42,17 @@ main() if (i % 5 == 0) scd.userdata["important"] = "yes"; - sh->createSingleSnapshot(scd); + snapper.createSingleSnapshot(scd); } +} + + +int +main() +{ + delete_all(); - delete sh; + create_number(); exit(EXIT_SUCCESS); } diff --git a/examples/c++-lib/CreateTimeline.cc b/examples/c++-lib/CreateTimeline.cc index c8e3221b..1ae4e7c2 100644 --- a/examples/c++-lib/CreateTimeline.cc +++ b/examples/c++-lib/CreateTimeline.cc @@ -12,11 +12,11 @@ using namespace std; void -deleteAll() +delete_all() { - Snapper* sh = new Snapper("testsuite", "/"); + Snapper snapper("testsuite", "/"); - Snapshots snapshots = sh->getSnapshots(); + Snapshots snapshots = snapper.getSnapshots(); vector tmp; for (Snapshots::iterator it = snapshots.begin(); it != snapshots.end(); ++it) @@ -24,18 +24,14 @@ deleteAll() tmp.push_back(it); for (vector::iterator it = tmp.begin(); it != tmp.end(); ++it) - sh->deleteSnapshot(*it); - - delete sh; + snapper.deleteSnapshot(*it); } -int -main() +void +create_timeline() { - deleteAll(); - - Snapper* sh = new Snapper("testsuite", "/"); + Snapper snapper("testsuite", "/"); time_t t = time(NULL) - 100 * 24*60*60; while (t < time(NULL)) @@ -45,13 +41,21 @@ main() scd.description = "testsuite"; scd.cleanup = "timeline"; - Snapshots::iterator snap = sh->createSingleSnapshot(scd); - // snap->setDate(t); + Snapshots::iterator snapshot = snapper.createSingleSnapshot(scd); + // snapshot->setDate(t); + snapper.modifySnapshot(snapshot, scd); t += 60*60; } +} + + +int +main() +{ + delete_all(); - delete sh; + create_timeline(); exit(EXIT_SUCCESS); } diff --git a/package/snapper.changes b/package/snapper.changes index 78bc6547..ca3aa513 100644 --- a/package/snapper.changes +++ b/package/snapper.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Thu Dec 15 21:36:23 CET 2016 - aschnell@suse.com + +- support option --no-dbus for all snapper commands (fate#319404, + fate#321049) +- version 0.4.0 + ------------------------------------------------------------------- Fri Nov 04 16:28:49 CET 2016 - aschnell@suse.com diff --git a/server/Background.cc b/server/Background.cc index 32ad57c5..004b9bdc 100644 --- a/server/Background.cc +++ b/server/Background.cc @@ -113,7 +113,7 @@ Backgrounds::worker() lock.unlock(); Snapper* snapper = task.meta_snapper->getSnapper(); - Comparison comparison(snapper, task.snapshot1, task.snapshot2); + Comparison comparison(snapper, task.snapshot1, task.snapshot2, false); task.meta_snapper->dec_use_count(); lock.lock(); diff --git a/server/Client.cc b/server/Client.cc index c658c167..6d69d5ed 100644 --- a/server/Client.cc +++ b/server/Client.cc @@ -1216,7 +1216,7 @@ Client::create_comparison(DBus::Connection& conn, DBus::Message& msg) lock.unlock(); - Comparison* comparison = new Comparison(snapper, snapshot1, snapshot2); + Comparison* comparison = new Comparison(snapper, snapshot1, snapshot2, false); lock.lock(); diff --git a/snapper/Comparison.cc b/snapper/Comparison.cc index 5f39efe3..05427f8a 100644 --- a/snapper/Comparison.cc +++ b/snapper/Comparison.cc @@ -45,8 +45,9 @@ namespace snapper Comparison::Comparison(const Snapper* snapper, Snapshots::const_iterator snapshot1, - Snapshots::const_iterator snapshot2) - : snapper(snapper), snapshot1(snapshot1), snapshot2(snapshot2), files(&file_paths) + Snapshots::const_iterator snapshot2, bool mount) + : snapper(snapper), snapshot1(snapshot1), snapshot2(snapshot2), mount(mount), + files(&file_paths) { if (snapshot1 == snapper->getSnapshots().end() || snapshot2 == snapper->getSnapshots().end() || @@ -60,6 +61,16 @@ namespace snapper file_paths.post_path = snapshot2->snapshotDir(); initialize(); + + if (mount) + do_mount(); + } + + + Comparison::~Comparison() + { + if (mount) + do_umount(); } @@ -102,7 +113,7 @@ namespace snapper void - Comparison::mount() const + Comparison::do_mount() const { if (!getSnapshot1()->isCurrent()) getSnapshot1()->mountFilesystemSnapshot(false); @@ -112,7 +123,7 @@ namespace snapper void - Comparison::umount() const + Comparison::do_umount() const { if (!getSnapshot1()->isCurrent()) getSnapshot1()->umountFilesystemSnapshot(false); @@ -130,7 +141,7 @@ namespace snapper files.push_back(File(&file_paths, name, status)); }; - mount(); + do_mount(); { SDir dir1 = getSnapshot1()->openSnapshotDir(); @@ -138,7 +149,7 @@ namespace snapper snapper->getFilesystem()->cmpDirs(dir1, dir2, cb); } - umount(); + do_umount(); files.sort(); diff --git a/snapper/Comparison.h b/snapper/Comparison.h index a99a8417..9b341399 100644 --- a/snapper/Comparison.h +++ b/snapper/Comparison.h @@ -35,8 +35,16 @@ namespace snapper { public: + /** + * Create a comparison. + * + * The mount parameter allows to ensure that the two snapshots are + * mounted for the lifetime of the Comparison object. + */ Comparison(const Snapper* snapper, Snapshots::const_iterator snapshot1, - Snapshots::const_iterator snapshot2); + Snapshots::const_iterator snapshot2, bool mount); + + ~Comparison(); const Snapper* getSnapper() const { return snapper; } @@ -46,9 +54,6 @@ namespace snapper Files& getFiles() { return files; } const Files& getFiles() const { return files; } - void mount() const; - void umount() const; - UndoStatistic getUndoStatistic() const; XAUndoStatistic getXAUndoStatistic() const; @@ -64,11 +69,16 @@ namespace snapper void save(); void filter(); + void do_mount() const; + void do_umount() const; + const Snapper* snapper; Snapshots::const_iterator snapshot1; Snapshots::const_iterator snapshot2; + const bool mount; + FilePaths file_paths; Files files; diff --git a/snapper/File.h b/snapper/File.h index dba89da1..ade271b7 100644 --- a/snapper/File.h +++ b/snapper/File.h @@ -185,6 +185,9 @@ namespace snapper Files(const FilePaths* file_paths) : file_paths(file_paths) {} + Files(const FilePaths* file_paths, const vector& entries) + : file_paths(file_paths), entries(entries) {} + typedef vector::iterator iterator; typedef vector::const_iterator const_iterator; typedef vector::size_type size_type; diff --git a/snapper/LvmCache.cc b/snapper/LvmCache.cc index 78ccf6e9..f610b608 100644 --- a/snapper/LvmCache.cc +++ b/snapper/LvmCache.cc @@ -21,7 +21,6 @@ #include "config.h" #include - #include #include "snapper/Log.h" diff --git a/snapper/Snapper.cc b/snapper/Snapper.cc index c428437b..d6ee3802 100644 --- a/snapper/Snapper.cc +++ b/snapper/Snapper.cc @@ -966,4 +966,12 @@ namespace snapper ; } + + vector + Snapper::debug() + { + return { "version " + string(compileVersion()), + "flags " + string(compileFlags()) }; + } + } diff --git a/snapper/Snapper.h b/snapper/Snapper.h index 6f9ce872..0e0f4c78 100644 --- a/snapper/Snapper.h +++ b/snapper/Snapper.h @@ -153,6 +153,7 @@ namespace snapper const Filesystem* getFilesystem() const { return filesystem; } + const ConfigInfo& getConfigInfo() { return *config_info; } void setConfigInfo(const map& raw); void syncAcl() const; @@ -168,6 +169,8 @@ namespace snapper static const char* compileVersion(); static const char* compileFlags(); + static vector debug(); + private: void filter1(list& tmp, time_t min_age); diff --git a/testsuite-real/common.cc b/testsuite-real/common.cc index 23b953ad..86d00993 100644 --- a/testsuite-real/common.cc +++ b/testsuite-real/common.cc @@ -70,7 +70,7 @@ second_snapshot() void check_undo_statistics(unsigned int numCreate, unsigned int numModify, unsigned int numDelete) { - Comparison comparison(sh, first, second); + Comparison comparison(sh, first, second, false); Files& files = comparison.getFiles(); for (Files::iterator it = files.begin(); it != files.end(); ++it) @@ -101,7 +101,7 @@ undo() cout << "comparing snapshots..." << flush; - Comparison comparison(sh, first, second); + Comparison comparison(sh, first, second, false); cout << " done" << endl; @@ -158,7 +158,7 @@ check_first() { Snapshots::const_iterator current = sh->getSnapshotCurrent(); - Comparison comparison(sh, first, current); + Comparison comparison(sh, first, current, false); const Files& files = comparison.getFiles(); for (Files::const_iterator it = files.begin(); it != files.end(); ++it)