- make all snapper commands available with option --no-dbus by using new proxy classes
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
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
*/
+#include <vector>
+
+#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 <vector>
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<typename Type>
+ void read(const ProxyConfig& config, const char* name, Type& value)
+ {
+ const map<string, string>& raw = config.getAllValues();
+ map<string, string>::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);
}
{
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() {}
protected:
- virtual list<XSnapshots::iterator> calculate_candidates(Range::Value value) = 0;
+ virtual list<ProxySnapshots::iterator> 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<XSnapshots::iterator>& tmp) const;
+ void filter(ProxySnapshots& snapshots, list<ProxySnapshots::iterator>& tmp) const;
// Removes snapshots younger than parameters.min_age from tmp
- void filter_min_age(list<XSnapshots::iterator>& tmp) const;
+ void filter_min_age(ProxySnapshots& snapshots, list<ProxySnapshots::iterator>& 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<XSnapshots::iterator>& tmp) const;
+ void filter_pre_post(ProxySnapshots& snapshots, list<ProxySnapshots::iterator>& tmp) const;
- void remove(const list<XSnapshots::iterator>& tmp);
+ void remove(const list<ProxySnapshots::iterator>& 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<XSnapshots::iterator>& tmp) const
+Cleaner::filter(ProxySnapshots& snapshots, list<ProxySnapshots::iterator>& 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<XSnapshots::iterator>& tmp) const
+Cleaner::filter_min_age(ProxySnapshots& snapshots, list<ProxySnapshots::iterator>& tmp) const
{
time_t now = time(NULL);
tmp.remove_if(younger_than(now - parameters.min_age));
void
-Cleaner::filter_pre_post(list<XSnapshots::iterator>& tmp) const
+Cleaner::filter_pre_post(ProxySnapshots& snapshots, list<ProxySnapshots::iterator>& tmp) const
{
- list<XSnapshots::iterator> ret;
+ list<ProxySnapshots::iterator> ret;
- for (list<XSnapshots::iterator>::iterator it1 = tmp.begin(); it1 != tmp.end(); ++it1)
+ for (list<ProxySnapshots::iterator>::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())
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())
void
-Cleaner::remove(const list<XSnapshots::iterator>& tmp)
+Cleaner::remove(const list<ProxySnapshots::iterator>& tmp)
{
- for (list<XSnapshots::iterator>::const_iterator it = tmp.begin(); it != tmp.end(); ++it)
+ for (list<ProxySnapshots::iterator>::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);
}
}
try
{
- command_prepare_quota(conn, config_name);
+ snapper->prepareQuota();
}
catch (const DBus::ErrorException& e)
{
SN_RETHROW(e);
}
+ catch (const QuotaException& e)
+ {
+ SN_CAUGHT(e);
+
+ cerr << "quota not working (" << e.what() << ")" << endl;
+ return false;
+ }
return true;
}
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<XSnapshots::iterator> candidates = calculate_candidates(Range::MAX);
+ list<ProxySnapshots::iterator> 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<XSnapshots::iterator> candidates = calculate_candidates(Range::MIN);
+ list<ProxySnapshots::iterator> candidates = calculate_candidates(snapshots, Range::MIN);
if (candidates.empty())
{
// not enough candidates to satisfy quota
// snapshot candidate if the post snapshot is missing so simply
// removing the first candidate is not possible.
- for (list<XSnapshots::iterator>::iterator e = candidates.begin(); e != candidates.end(); ++e)
+ for (list<ProxySnapshots::iterator>::iterator e = candidates.begin(); e != candidates.end(); ++e)
{
- list<XSnapshots::iterator> tmp = list<XSnapshots::iterator>(candidates.begin(), next(e));
+ list<ProxySnapshots::iterator> tmp = list<ProxySnapshots::iterator>(candidates.begin(), next(e));
- filter(tmp);
+ filter(snapshots, tmp);
if (!tmp.empty())
{
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);
}
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<string, string>::const_iterator it2 = it1->getUserdata().find("important");
return it2 != it1->getUserdata().end() && it2->second == "yes";
}
- list<XSnapshots::iterator>
- calculate_candidates(Range::Value value)
+ list<ProxySnapshots::iterator>
+ calculate_candidates(ProxySnapshots& snapshots, Range::Value value) override
{
const NumberParameters& parameters = dynamic_cast<const NumberParameters&>(Cleaner::parameters);
- list<XSnapshots::iterator> ret;
+ list<ProxySnapshots::iterator> 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);
size_t num = 0;
size_t num_important = 0;
- list<XSnapshots::iterator>::iterator it = ret.begin();
+ list<ProxySnapshots::iterator>::iterator it = ret.begin();
while (it != ret.end())
{
bool keep = false;
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;
};
-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);
}
{
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<XSnapshots::iterator>::const_iterator first,
- list<XSnapshots::iterator>::const_iterator last,
- XSnapshots::const_iterator it1,
+ is_first(list<ProxySnapshots::iterator>::const_iterator first,
+ list<ProxySnapshots::iterator>::const_iterator last,
+ ProxySnapshots::const_iterator it1,
std::function<bool(const struct tm& tmp1, const struct tm& tmp2)> pred)
{
time_t t1 = it1->getDate();
struct tm tmp1;
localtime_r(&t1, &tmp1);
- for (list<XSnapshots::iterator>::const_iterator it2 = first; it2 != last; ++it2)
+ for (list<ProxySnapshots::iterator>::const_iterator it2 = first; it2 != last; ++it2)
{
if (it1 == *it2)
continue;
bool
- is_first_yearly(list<XSnapshots::iterator>::const_iterator first,
- list<XSnapshots::iterator>::const_iterator last,
- XSnapshots::const_iterator it1)
+ is_first_yearly(list<ProxySnapshots::iterator>::const_iterator first,
+ list<ProxySnapshots::iterator>::const_iterator last,
+ ProxySnapshots::const_iterator it1)
{
return is_first(first, last, it1, equal_year);
}
bool
- is_first_monthly(list<XSnapshots::iterator>::const_iterator first,
- list<XSnapshots::iterator>::const_iterator last,
- XSnapshots::const_iterator it1)
+ is_first_monthly(list<ProxySnapshots::iterator>::const_iterator first,
+ list<ProxySnapshots::iterator>::const_iterator last,
+ ProxySnapshots::const_iterator it1)
{
return is_first(first, last, it1, equal_month);
}
bool
- is_first_weekly(list<XSnapshots::iterator>::const_iterator first,
- list<XSnapshots::iterator>::const_iterator last,
- XSnapshots::const_iterator it1)
+ is_first_weekly(list<ProxySnapshots::iterator>::const_iterator first,
+ list<ProxySnapshots::iterator>::const_iterator last,
+ ProxySnapshots::const_iterator it1)
{
return is_first(first, last, it1, equal_week);
}
bool
- is_first_daily(list<XSnapshots::iterator>::const_iterator first,
- list<XSnapshots::iterator>::const_iterator last,
- XSnapshots::const_iterator it1)
+ is_first_daily(list<ProxySnapshots::iterator>::const_iterator first,
+ list<ProxySnapshots::iterator>::const_iterator last,
+ ProxySnapshots::const_iterator it1)
{
return is_first(first, last, it1, equal_day);
}
bool
- is_first_hourly(list<XSnapshots::iterator>::const_iterator first,
- list<XSnapshots::iterator>::const_iterator last,
- XSnapshots::const_iterator it1)
+ is_first_hourly(list<ProxySnapshots::iterator>::const_iterator first,
+ list<ProxySnapshots::iterator>::const_iterator last,
+ ProxySnapshots::const_iterator it1)
{
return is_first(first, last, it1, equal_hour);
}
- list<XSnapshots::iterator>
- calculate_candidates(Range::Value value)
+ list<ProxySnapshots::iterator>
+ calculate_candidates(ProxySnapshots& snapshots, Range::Value value) override
{
const TimelineParameters& parameters = dynamic_cast<const TimelineParameters&>(Cleaner::parameters);
- list<XSnapshots::iterator> ret;
+ list<ProxySnapshots::iterator> 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);
size_t num_monthly = 0;
size_t num_yearly = 0;
- list<XSnapshots::iterator>::iterator it = ret.begin();
+ list<ProxySnapshots::iterator>::iterator it = ret.begin();
while (it != ret.end())
{
bool keep = false;
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);
}
{
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<XSnapshots::iterator>
- calculate_candidates(Range::Value value)
+ list<ProxySnapshots::iterator>
+ calculate_candidates(ProxySnapshots& snapshots, Range::Value value) override
{
- list<XSnapshots::iterator> ret;
+ list<ProxySnapshots::iterator> 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<XFile> 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());
}
}
}
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();
}
/*
* Copyright (c) [2011-2012] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
*
* All Rights Reserved.
*
*/
+#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);
#define INTERFACE "org.opensuse.Snapper"
-list<XConfigInfo>
+vector<XConfigInfo>
command_list_xconfigs(DBus::Connection& conn)
{
DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "ListConfigs");
DBus::Message reply = conn.send_with_reply_and_block(call);
- list<XConfigInfo> ret;
+ vector<XConfigInfo> ret;
DBus::Hihi hihi(reply);
hihi >> ret;
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");
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");
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<string, string>& userdata)
+command_create_single_snapshot(DBus::Connection& conn, const string& config_name,
+ const string& description, const string& cleanup,
+ const map<string, string>& userdata)
{
DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreateSingleSnapshot");
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<string, string>& 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<string, string>& userdata)
{
DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreateSingleSnapshotV2");
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<string, string>& 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<string, string>& userdata)
{
DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreateSingleSnapshotOfDefault");
unsigned int
-command_create_pre_xsnapshot(DBus::Connection& conn, const string& config_name,
- const string& description, const string& cleanup,
- const map<string, string>& userdata)
+command_create_pre_snapshot(DBus::Connection& conn, const string& config_name,
+ const string& description, const string& cleanup,
+ const map<string, string>& userdata)
{
DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreatePreSnapshot");
unsigned int
-command_create_post_xsnapshot(DBus::Connection& conn, const string& config_name,
- unsigned int prenum, const string& description,
- const string& cleanup, const map<string, string>& userdata)
+command_create_post_snapshot(DBus::Connection& conn, const string& config_name,
+ unsigned int prenum, const string& description,
+ const string& cleanup, const map<string, string>& userdata)
{
DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "CreatePostSnapshot");
void
-command_delete_xsnapshots(DBus::Connection& conn, const string& config_name,
- const list<unsigned int>& nums, bool verbose)
+command_delete_snapshots(DBus::Connection& conn, const string& config_name,
+ const vector<unsigned int>& nums, bool verbose)
{
if (verbose)
{
cout << sformat(_("Deleting snapshot from %s:", "Deleting snapshots from %s:", nums.size()),
config_name.c_str()) << endl;
- for (list<unsigned int>::const_iterator it = nums.begin(); it != nums.end(); ++it)
+ for (vector<unsigned int>::const_iterator it = nums.begin(); it != nums.end(); ++it)
{
if (it != nums.begin())
cout << ", ";
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");
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");
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");
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");
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");
}
-list<XFile>
+vector<XFile>
command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned int number1,
unsigned int number2)
{
DBus::Message reply = conn.send_with_reply_and_block(call);
- list<XFile> files;
+ vector<XFile> 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;
}
}
-XQuotaData
+QuotaData
command_query_quota(DBus::Connection& conn, const string& config_name)
{
DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "QueryQuota");
DBus::Message reply = conn.send_with_reply_and_block(call);
- XQuotaData quota_data;
+ QuotaData quota_data;
DBus::Hihi hihi(reply);
hihi >> quota_data;
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");
vector<string>
-command_xdebug(DBus::Connection& conn)
+command_debug(DBus::Connection& conn)
{
DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "Debug");
#include <string>
#include <vector>
-#include <list>
#include <map>
using std::string;
using std::vector;
-using std::list;
using std::map;
#include "types.h"
-list<XConfigInfo>
+vector<XConfigInfo>
command_list_xconfigs(DBus::Connection& conn);
XConfigInfo
const map<string, string>& 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);
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<string, string>& userdata);
+command_create_single_snapshot(DBus::Connection& conn, const string& config_name,
+ const string& description, const string& cleanup,
+ const map<string, string>& 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<string, string>& 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<string, string>& 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<string, string>& 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<string, string>& userdata);
unsigned int
-command_create_pre_xsnapshot(DBus::Connection& conn, const string& config_name,
- const string& description, const string& cleanup,
- const map<string, string>& userdata);
+command_create_pre_snapshot(DBus::Connection& conn, const string& config_name,
+ const string& description, const string& cleanup,
+ const map<string, string>& 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<string, string>& userdata);
+command_create_post_snapshot(DBus::Connection& conn, const string& config_name,
+ unsigned int prenum, const string& description,
+ const string& cleanup, const map<string, string>& userdata);
void
-command_delete_xsnapshots(DBus::Connection& conn, const string& config_name,
- const list<unsigned int>& nums, bool verbose);
+command_delete_snapshots(DBus::Connection& conn, const string& config_name,
+ const vector<unsigned int>& 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<XFile>
+vector<XFile>
command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned int number1,
unsigned int number2);
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<string>
-command_xdebug(DBus::Connection& conn);
+command_debug(DBus::Connection& conn);
return _("Invalid configdata.");
if (name == "error.illegal_snapshot")
- return _("Illegal Snapshot.");
+ return _("Illegal snapshot.");
if (name == "error.config_locked")
return _("Config is locked.");
#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)
{
}
-pair<unsigned int, unsigned int>
-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<unsigned int, unsigned int>(num1, num2);
-}
-
-
map<string, string>
read_userdata(const string& s, const map<string, string>& old)
{
using namespace std;
-Snapshots::iterator
-read_num(Snapper* snapper, const string& str);
-
unsigned int
read_num(const string& str);
-pair<unsigned int, unsigned int>
-read_nums(const string& str, const string& delim = "..");
-
map<string, string>
read_userdata(const string& s, const map<string, string>& old = map<string, string>());
--- /dev/null
+/*
+ * 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<string, string>& 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<ProxySnapshots::iterator> snapshots, bool verbose)
+{
+ vector<unsigned int> 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<ProxySnapperDbus>& 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<string, ProxyConfig>
+ProxySnappersDbus::getConfigs() const
+{
+ map<string, ProxyConfig> ret;
+
+ vector<XConfigInfo> config_infos = command_list_xconfigs(conn);
+ for (XConfigInfo& x : config_infos)
+ ret.emplace(make_pair(x.config_name, x.raw));
+
+ return ret;
+}
+
+
+vector<string>
+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<XFile> tmp1 = command_get_xfiles(backref->conn(), backref->config_name, lhs.getNum(),
+ rhs.getNum());
+
+ vector<File> 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());
+}
--- /dev/null
+/*
+ * 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<string, string>& 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<string, string>& 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<string, string> 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<ProxySnapshots::iterator> 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<string, ProxyConfig> getConfigs() const override;
+
+ virtual vector<string> debug() const override;
+
+ mutable DBus::Connection conn;
+
+ list<std::unique_ptr<ProxySnapperDbus>> 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
--- /dev/null
+/*
+ * 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<ProxySnapshots::iterator> 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<ProxySnapperLib>& 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<string, ProxyConfig>
+ProxySnappersLib::getConfigs() const
+{
+ map<string, ProxyConfig> ret;
+
+ list<ConfigInfo> 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<const ProxySnapshotLib&>(proxy_snapshot.get_impl());
+}
--- /dev/null
+/*
+ * 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 <snapper/Snapper.h>
+#include <snapper/Comparison.h>
+
+
+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<string, string>& 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<ProxySnapshots::iterator> 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> 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<string, ProxyConfig> getConfigs() const override;
+
+ virtual vector<string> debug() const { return Snapper::debug(); }
+
+private:
+
+ const string target_root;
+
+ list<std::unique_ptr<ProxySnapperLib>> 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> comparison;
+
+};
+
+
+const ProxySnapshotLib&
+to_lib(const ProxySnapshot& proxy_snapshot);
+
+
+#endif
--- /dev/null
+/*
+ * 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 <sstream>
+#include <iostream>
+#include <algorithm>
+
+#include <snapper/AppUtil.h>
+#include <snapper/SnapperDefines.h>
+
+#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<string, string>::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::iterator, ProxySnapshots::iterator>
+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();
+}
--- /dev/null
+/*
+ * 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 <memory>
+#include <vector>
+#include <list>
+#include <map>
+
+#include <snapper/Snapshot.h>
+#include <snapper/Snapper.h>
+#include <snapper/File.h>
+
+
+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<ProxySnapshot> 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<ProxySnapshot*> 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<string, string>& values) : values(values) {}
+
+ const map<string, string>& getAllValues() const { return values; }
+
+ string getSubvolume() const;
+
+ bool getValue(const string& key, string& value) const;
+
+private:
+
+ map<string, string> 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<string, string>& 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<string, string>& 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> impl;
+
+};
+
+
+class ProxySnapshots
+{
+
+public:
+
+ virtual ~ProxySnapshots() {}
+
+ typedef list<ProxySnapshot>::iterator iterator;
+ typedef list<ProxySnapshot>::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<iterator, iterator> 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<ProxySnapshot> 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<ProxySnapshots::iterator> 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<string, ProxyConfig> getConfigs() const
+ { return impl->getConfigs(); }
+
+ vector<string> 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<string, ProxyConfig> getConfigs() const = 0;
+
+ virtual vector<string> 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> 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> impl;
+
+};
+
+
+#endif
#include "utils/Table.h"
#include "utils/GetOpts.h"
-#include "commands.h"
#include "cleanup.h"
#include "errors.h"
+#include "proxy.h"
#include "misc.h"
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<string>& 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<string> 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;
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<void(File& file)> callback);
}
-struct MyComparison
-{
- MyComparison(DBus::Connection& conn, pair<unsigned int, unsigned int> 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<XFile> tmp = command_get_xfiles(conn, config_name, nums.first, nums.second);
- for (list<XFile>::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()
{
}
-list<pair<string, string>>
-enum_configs(DBus::Connection* conn)
-{
- list<pair<string, string>> configs;
-
- if (no_dbus)
- {
- list<ConfigInfo> config_infos = Snapper::getConfigs(target_root);
- for (list<ConfigInfo>::const_iterator it = config_infos.begin(); it != config_infos.end(); ++it)
- {
- configs.push_back(make_pair(it->getConfigName(), it->getSubvolume()));
- }
- }
- else
- {
- list<XConfigInfo> config_infos = command_list_xconfigs(*conn);
- for (list<XConfigInfo>::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())
header.add(_("Subvolume"));
table.setHeader(header);
- list<pair<string, string> > configs = enum_configs(conn);
-
- for (list<pair<string,string> >::iterator it = configs.begin(); it != configs.end(); ++it)
+ map<string, ProxyConfig> configs = snappers->getConfigs();
+ for (const map<string, ProxyConfig>::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);
}
void
-command_create_config(DBus::Connection* conn, Snapper* snapper)
+command_create_config(ProxySnappers* snappers, ProxySnapper*)
{
const struct option options[] = {
{ "fstype", required_argument, 0, 'f' },
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);
}
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())
exit(EXIT_FAILURE);
}
- if (no_dbus)
- {
- Snapper::deleteConfig(config_name, target_root);
- }
- else
- {
- command_delete_xconfig(*conn, config_name);
- }
+ snappers->deleteConfig(config_name);
}
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())
header.add(_("Value"));
table.setHeader(header);
- if (no_dbus)
- {
- ConfigInfo config_info = Snapper::getConfig(config_name, target_root);
- map<string, string> raw = config_info.getAllValues();
-
- for (map<string, string>::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<string, string>::value_type& value : config.getAllValues())
{
- XConfigInfo ci = command_get_xconfig(*conn, config_name);
-
- for (map<string, string>::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;
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())
exit(EXIT_FAILURE);
}
- map<string, string> 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);
}
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' },
}
}
- list<pair<string, string> > configs;
- if ((opt = opts.find("all-configs")) != opts.end())
+ vector<string> 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<string, ProxyConfig> configs = snappers->getConfigs();
+ for (map<string, ProxyConfig>::value_type it : configs)
+ tmp.push_back(it.first);
}
- for (list<pair<string,string> >::iterator it = configs.begin(); it != configs.end(); ++it)
+ for (vector<string>::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;
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;
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;
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;
void
-command_create(DBus::Connection* conn, Snapper* snapper)
+command_create(ProxySnappers* snappers, ProxySnapper* snapper)
{
const struct option options[] = {
{ "type", required_argument, 0, 't' },
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<string, string> userdata;
+ SCD scd;
string command;
GetOpts::parsed_opts::const_iterator opt;
}
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())
{
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);
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;
}
}
void
-command_modify(DBus::Connection* conn, Snapper* snapper)
+command_modify(ProxySnappers* snappers, ProxySnapper* snapper)
{
const struct option options[] = {
{ "description", required_argument, 0, 'd' },
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);
}
}
void
-command_delete(DBus::Connection* conn, Snapper* snapper)
+command_delete(ProxySnappers* snappers, ProxySnapper* snapper)
{
const struct option options[] = {
{ "sync", no_argument, 0, 's' },
if ((opt = opts.find("sync")) != opts.end())
sync = true;
- XSnapshots snapshots = command_list_xsnapshots(*conn, config_name);
+ ProxySnapshots& snapshots = snapper->getSnapshots();
- list<unsigned int> nums;
+ vector<ProxySnapshots::iterator> nums;
while (getopts.hasArgs())
{
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<unsigned int, unsigned int> r(read_nums(arg, "-"));
+ pair<ProxySnapshots::iterator, ProxySnapshots::iterator> 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();
}
void
-command_mount(DBus::Connection* conn, Snapper* snapper)
+command_mount(ProxySnappers* snappers, ProxySnapper* snapper)
{
getopts.parse("mount", GetOpts::no_options);
if (!getopts.hasArgs())
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);
}
}
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);
}
}
void
-command_status(DBus::Connection* conn, Snapper* snapper)
+command_status(ProxySnappers* snappers, ProxySnapper* snapper)
{
const struct option options[] = {
{ "output", required_argument, 0, 'o' },
GetOpts::parsed_opts::const_iterator opt;
- pair<unsigned int, unsigned int> nums(read_nums(getopts.popArg()));
+ ProxySnapshots& snapshots = snapper->getSnapshots();
- MyComparison comparison(*conn, nums, false);
- MyFiles& files = comparison.files;
+ pair<ProxySnapshots::const_iterator, ProxySnapshots::const_iterator> range =
+ snapshots.findNums(getopts.popArg());
+
+ ProxyComparison comparison = snapper->createComparison(*range.first, *range.second, false);
+
+ MyFiles files(comparison.getFiles());
FILE* file = stdout;
void
-command_diff(DBus::Connection* conn, Snapper* snapper)
+command_diff(ProxySnappers* snappers, ProxySnapper* snapper)
{
const struct option options[] = {
{ "input", required_argument, 0, 'i' },
if ((opt = opts.find("extensions")) != opts.end())
differ.extensions = opt->second;
- pair<unsigned int, unsigned int> nums(read_nums(getopts.popArg()));
+ ProxySnapshots& snapshots = snapper->getSnapshots();
+
+ pair<ProxySnapshots::const_iterator, ProxySnapshots::const_iterator> 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));
void
-command_undo(DBus::Connection* conn, Snapper* snapper)
+command_undo(ProxySnappers* snappers, ProxySnapper* snapper)
{
const struct option options[] = {
{ "input", required_argument, 0, 'i' },
exit(EXIT_FAILURE);
}
- pair<unsigned int, unsigned int> nums(read_nums(getopts.popArg()));
+ ProxySnapshots& snapshots = snapper->getSnapshots();
+
+ pair<ProxySnapshots::const_iterator, ProxySnapshots::const_iterator> range =
+ snapshots.findNums(getopts.popArg());
FILE* file = NULL;
}
}
- 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);
#ifdef ENABLE_ROLLBACK
const Filesystem*
-getFilesystem(const XConfigInfo &ci, Snapper* snapper)
+getFilesystem(const ProxyConfig& config)
{
- map<string, string>::const_iterator it = ci.raw.find(KEY_FSTYPE);
- if (it == ci.raw.end())
+ const map<string, string>& raw = config.getAllValues();
+
+ map<string, string>::const_iterator pos1 = raw.find(KEY_FSTYPE);
+ map<string, string>::const_iterator pos2 = raw.find(KEY_SUBVOLUME);
+ if (pos1 == raw.end() || pos2 == raw.end())
{
cerr << _("Failed to initialize filesystem handler.") << endl;
exit(EXIT_FAILURE);
try
{
- return Filesystem::create(it->second, ci.subvolume, target_root);
+ return Filesystem::create(pos1->second, pos2->second, target_root);
}
catch (const InvalidConfigException& e)
{
}
}
-const string
-getSubvolume(const XConfigInfo &ci, Snapper* snapper)
-{
- map<string, string>::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()
void
-command_rollback(DBus::Connection* conn, Snapper* snapper)
+command_rollback(ProxySnappers* snappers, ProxySnapper* snapper)
{
const struct option options[] = {
{ "print-number", no_argument, 0, 'p' },
}
bool print_number = false;
- string description;
- string cleanup;
- map<string, string> userdata;
+ SCD scd;
GetOpts::parsed_opts::const_iterator opt;
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."),
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.") <<flush;
- num2 = command_create_single_xsnapshot_v2(*conn, config_name, 0, false, description,
- cleanup, userdata);
+ cout << _("Creating read-write snapshot of current subvolume.") << flush;
+
+ scd.read_only = false;
+ snapshot2 = snapper->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
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)
exit(EXIT_FAILURE);
}
- if (no_dbus)
- {
- snapper->setupQuota();
- }
- else
- {
- command_setup_quota(*conn, config_name);
- }
+ snapper->setupQuota();
}
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)
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
{
void
-command_debug(DBus::Connection* conn, Snapper* snapper)
+command_debug(ProxySnappers* snappers, ProxySnapper*)
{
getopts.parse("debug", GetOpts::no_options);
if (getopts.hasArgs())
exit(EXIT_FAILURE);
}
- vector<string> lines = command_xdebug(*conn);
- for (vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it)
- cout << *it << endl;
+ for (const string& line : snappers->debug())
+ cout << line << endl;
}
}
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)
exit(EXIT_FAILURE);
}
- pair<unsigned int, unsigned int> nums(read_nums(getopts.popArg()));
+ ProxySnapshots& snapshots = snapper->getSnapshots();
+
+ pair<ProxySnapshots::const_iterator, ProxySnapshots::const_iterator> 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)
{
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<Cmd> 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[] = {
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)
{
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);
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);
}
/*
* Copyright (c) [2014-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
*
* All Rights Reserved.
*
#include "utils/text.h"
#include "utils/GetOpts.h"
-#include "commands.h"
+#include "proxy.h"
#include "cleanup.h"
#include "errors.h"
#include "misc.h"
using namespace std;
-bool do_timeline = false;
-bool do_cleanup = false;
-
-
void
-timeline(DBus::Connection* conn, const map<string, string>& userdata)
+timeline(ProxySnappers* snappers, const map<string, string>& userdata)
{
- list<XConfigInfo> config_infos = command_list_xconfigs(*conn);
- for (const XConfigInfo& config_info : config_infos)
+ map<string, ProxyConfig> configs = snappers->getConfigs();
+ for (const map<string, ProxyConfig>::value_type value : configs)
{
- map<string, string>::const_iterator pos1 = config_info.raw.find("TIMELINE_CREATE");
- if (pos1 != config_info.raw.end() && pos1->second == "yes")
+ const map<string, string>& raw = value.second.getAllValues();
+
+ map<string, string>::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<XConfigInfo> config_infos = command_list_xconfigs(*conn);
- for (const XConfigInfo& config_info : config_infos)
+ map<string, ProxyConfig> configs = snappers->getConfigs();
+ for (const map<string, ProxyConfig>::value_type value : configs)
{
- map<string, string>::const_iterator pos1 = config_info.raw.find("NUMBER_CLEANUP");
- if (pos1 != config_info.raw.end() && pos1->second == "yes")
+ const map<string, string>& raw = value.second.getAllValues();
+
+ ProxySnapper* snapper = snappers->getSnapper(value.first);
+
+ map<string, string>::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<string, string>::const_iterator pos2 = config_info.raw.find("TIMELINE_CLEANUP");
- if (pos2 != config_info.raw.end() && pos2->second == "yes")
+ map<string, string>::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<string, string>::const_iterator pos3 = config_info.raw.find("EMPTY_PRE_POST_CLEANUP");
- if (pos3 != config_info.raw.end() && pos3->second == "yes")
+ map<string, string>::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);
}
}
}
{ 0, 0, 0, 0 }
};
+ bool do_timeline = false;
+ bool do_cleanup = false;
+
map<string, string> userdata;
GetOpts getopts;
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)
{
#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<XConfigInfo>::signature = "(ssa{ss})";
Hihi&
- operator>>(Hihi& hihi, XQuotaData& data)
+ operator>>(Hihi& hihi, QuotaData& data)
{
hihi.open_recurse();
hihi >> data.size >> data.used;
#include <string>
-#include <list>
+#include <vector>
#include <map>
using std::string;
-using std::list;
+using std::vector;
using std::map;
#include "dbus/DBusMessage.h"
#include "snapper/Snapshot.h"
#include "snapper/File.h"
#include "snapper/SnapperTmpl.h"
+#include "snapper/Snapper.h"
using namespace snapper;
string subvolume;
map<string, string> raw;
-
- template<typename Type>
- void read(const char* name, Type& value)
- {
- map<string, string>::const_iterator pos = raw.find(name);
- if (pos != raw.end())
- pos->second >> value;
- }
};
SnapshotType getType() const { return type; }
unsigned int getNum() const { return num; }
- bool isCurrent() const { return num == 0; }
time_t getDate() const { return date; }
struct XSnapshots
{
- typedef list<XSnapshot>::iterator iterator;
- typedef list<XSnapshot>::const_iterator const_iterator;
+ typedef vector<XSnapshot>::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<XSnapshot> entries;
+ vector<XSnapshot> entries;
};
};
-struct XQuotaData
-{
- uint64_t size;
- uint64_t used;
-};
-
-
namespace DBus
{
Hihi& operator>>(Hihi& hihi, XFile& data);
- Hihi& operator>>(Hihi& hihi, XQuotaData& data);
+ Hihi& operator>>(Hihi& hihi, QuotaData& data);
}
<varlistentry>
<term><option>--no-dbus</option></term>
<listitem>
- <para>Operate without a DBus connection. Only works for some commands.</para>
+ <para>Operate without a DBus connection.</para>
<para>Use with caution since a running snapperd will not know about
modifications made to the system.</para>
</listitem>
void
-deleteAll()
+delete_all()
{
- Snapper* sh = new Snapper("testsuite", "/");
+ Snapper snapper("testsuite", "/");
- Snapshots snapshots = sh->getSnapshots();
+ Snapshots snapshots = snapper.getSnapshots();
vector<Snapshots::iterator> tmp;
for (Snapshots::iterator it = snapshots.begin(); it != snapshots.end(); ++it)
tmp.push_back(it);
for (vector<Snapshots::iterator>::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)
{
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);
}
void
-deleteAll()
+delete_all()
{
- Snapper* sh = new Snapper("testsuite", "/");
+ Snapper snapper("testsuite", "/");
- Snapshots snapshots = sh->getSnapshots();
+ Snapshots snapshots = snapper.getSnapshots();
vector<Snapshots::iterator> tmp;
for (Snapshots::iterator it = snapshots.begin(); it != snapshots.end(); ++it)
tmp.push_back(it);
for (vector<Snapshots::iterator>::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))
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);
}
+-------------------------------------------------------------------
+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
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();
lock.unlock();
- Comparison* comparison = new Comparison(snapper, snapshot1, snapshot2);
+ Comparison* comparison = new Comparison(snapper, snapshot1, snapshot2, false);
lock.lock();
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() ||
file_paths.post_path = snapshot2->snapshotDir();
initialize();
+
+ if (mount)
+ do_mount();
+ }
+
+
+ Comparison::~Comparison()
+ {
+ if (mount)
+ do_umount();
}
void
- Comparison::mount() const
+ Comparison::do_mount() const
{
if (!getSnapshot1()->isCurrent())
getSnapshot1()->mountFilesystemSnapshot(false);
void
- Comparison::umount() const
+ Comparison::do_umount() const
{
if (!getSnapshot1()->isCurrent())
getSnapshot1()->umountFilesystemSnapshot(false);
files.push_back(File(&file_paths, name, status));
};
- mount();
+ do_mount();
{
SDir dir1 = getSnapshot1()->openSnapshotDir();
snapper->getFilesystem()->cmpDirs(dir1, dir2, cb);
}
- umount();
+ do_umount();
files.sort();
{
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; }
Files& getFiles() { return files; }
const Files& getFiles() const { return files; }
- void mount() const;
- void umount() const;
-
UndoStatistic getUndoStatistic() const;
XAUndoStatistic getXAUndoStatistic() const;
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;
Files(const FilePaths* file_paths)
: file_paths(file_paths) {}
+ Files(const FilePaths* file_paths, const vector<File>& entries)
+ : file_paths(file_paths), entries(entries) {}
+
typedef vector<File>::iterator iterator;
typedef vector<File>::const_iterator const_iterator;
typedef vector<File>::size_type size_type;
#include "config.h"
#include <vector>
-
#include <boost/algorithm/string.hpp>
#include "snapper/Log.h"
;
}
+
+ vector<string>
+ Snapper::debug()
+ {
+ return { "version " + string(compileVersion()),
+ "flags " + string(compileFlags()) };
+ }
+
}
const Filesystem* getFilesystem() const { return filesystem; }
+ const ConfigInfo& getConfigInfo() { return *config_info; }
void setConfigInfo(const map<string, string>& raw);
void syncAcl() const;
static const char* compileVersion();
static const char* compileFlags();
+ static vector<string> debug();
+
private:
void filter1(list<Snapshots::iterator>& tmp, time_t min_age);
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)
cout << "comparing snapshots..." << flush;
- Comparison comparison(sh, first, second);
+ Comparison comparison(sh, first, second, false);
cout << " done" << endl;
{
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)