From: Arvin Schnell Date: Thu, 18 Jun 2020 07:26:45 +0000 (+0200) Subject: - special rollback for transactional server (bsc#1172273) X-Git-Tag: v0.8.10~1^2~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4e571891c266b0be4c56d0757bfe78ba6524b304;p=thirdparty%2Fsnapper.git - special rollback for transactional server (bsc#1172273) --- diff --git a/VERSION b/VERSION index 55485e17..ef505616 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.8.9 +0.8.10 diff --git a/client/Command.cc b/client/Command.cc index 16afbb30..e98b26a7 100644 --- a/client/Command.cc +++ b/client/Command.cc @@ -33,15 +33,5 @@ namespace snapper _options_parser(options_parser), _global_options(global_options), _snappers(snappers) {} - - bool Command::has_errors() const - { - return !errors().empty(); - } - - - Command::~Command() - {} - } } diff --git a/client/Command.h b/client/Command.h index 9ce77600..d7e6393f 100644 --- a/client/Command.h +++ b/client/Command.h @@ -61,13 +61,9 @@ namespace snapper return _snappers; } - virtual bool has_errors() const; - - virtual std::vector errors() const = 0; - virtual void run() = 0; - virtual ~Command(); + virtual ~Command() {} protected: diff --git a/client/Command/ColumnsOption.cc b/client/Command/ColumnsOption.cc index 8384c000..ab559cf7 100644 --- a/client/Command/ColumnsOption.cc +++ b/client/Command/ColumnsOption.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] SUSE LLC + * Copyright (c) [2019-2020] SUSE LLC * * All Rights Reserved. * @@ -19,8 +19,6 @@ * find current contact information at www.novell.com. */ -#include - #include #include "client/Command/ColumnsOption.h" @@ -33,45 +31,30 @@ namespace snapper namespace cli { - vector Command::ColumnsOption::selected_columns() const + vector + Command::ColumnsOption::selected_columns() const { - if (_raw_columns.empty()) - return {}; - vector columns; boost::split(columns, _raw_columns, boost::is_any_of(","), boost::token_compress_on); - return columns; - } - - - string Command::ColumnsOption::error() const - { - if (wrong_columns().empty()) - return ""; - - return _("Unknown columns: ") + boost::algorithm::join(wrong_columns(), ", "); - } - - - vector Command::ColumnsOption::wrong_columns() const - { - vector wrong; - - for (auto column : selected_columns()) + vector unknowns; + for (const string& column : columns) { - if (wrong_column(column)) - wrong.push_back(column); + if (find(_all_columns.begin(), _all_columns.end(), column) == _all_columns.end()) + unknowns.push_back(column); } - return wrong; - } + if (!unknowns.empty()) + { + string error = _("Unknown column:", "Unknown columns:", unknowns.size()) + string(" ") + + boost::algorithm::join(unknowns, ", ") + '\n' + + _("Allowed columns are:") + string(" ") + boost::join(_all_columns, ", "); + SN_THROW(OptionsException(error)); + } - bool Command::ColumnsOption::wrong_column(const std::string& column) const - { - return find(_all_columns.begin(), _all_columns.end(), column) == _all_columns.end(); + return columns; } } diff --git a/client/Command/ColumnsOption.h b/client/Command/ColumnsOption.h index 93bcb8d6..2fec696a 100644 --- a/client/Command/ColumnsOption.h +++ b/client/Command/ColumnsOption.h @@ -48,14 +48,8 @@ namespace snapper std::vector selected_columns() const; - std::string error() const; - - std::vector wrong_columns() const; - private: - bool wrong_column(const std::string& column) const; - const std::vector& _all_columns; std::string _raw_columns; diff --git a/client/Command/GetConfig.cc b/client/Command/GetConfig.cc index f235e081..1c743498 100644 --- a/client/Command/GetConfig.cc +++ b/client/Command/GetConfig.cc @@ -62,12 +62,6 @@ namespace snapper } - vector Command::GetConfig::errors() const - { - return options().errors(); - } - - void Command::GetConfig::run() { if (_options_parser.hasArgs()) @@ -76,12 +70,6 @@ namespace snapper exit(EXIT_FAILURE); } - if (options().has_errors()) - { - cerr << options().errors().front() << endl; - exit(EXIT_FAILURE); - } - string output; switch (global_options().output_format()) diff --git a/client/Command/GetConfig.h b/client/Command/GetConfig.h index 6ef727b6..2c34c1f2 100644 --- a/client/Command/GetConfig.h +++ b/client/Command/GetConfig.h @@ -50,8 +50,6 @@ namespace snapper const Options& options() const; - virtual std::vector errors() const override; - virtual void run() override; virtual ~GetConfig(); diff --git a/client/Command/GetConfig/Options.cc b/client/Command/GetConfig/Options.cc index 006d5612..7294d43c 100644 --- a/client/Command/GetConfig/Options.cc +++ b/client/Command/GetConfig/Options.cc @@ -83,20 +83,9 @@ namespace snapper } - vector Command::GetConfig::Options::errors() const - { - vector detected_errors; - - if (!_columns_option.wrong_columns().empty()) - detected_errors.push_back(_columns_option.error()); - - return detected_errors; - } - - string Command::GetConfig::Options::columns_raw() const { - return has_option("columns") ? get_option("columns")->second : ""; + return has_option("columns") ? get_argument("columns") : ""; } } diff --git a/client/Command/GetConfig/Options.h b/client/Command/GetConfig/Options.h index 30bb7517..ac16eb44 100644 --- a/client/Command/GetConfig/Options.h +++ b/client/Command/GetConfig/Options.h @@ -50,8 +50,6 @@ namespace snapper std::vector columns() const; - virtual std::vector errors() const override; - private: void parse_options(); diff --git a/client/Command/ListConfigs.cc b/client/Command/ListConfigs.cc index 5f070e57..80830ead 100644 --- a/client/Command/ListConfigs.cc +++ b/client/Command/ListConfigs.cc @@ -62,12 +62,6 @@ namespace snapper } - vector Command::ListConfigs::errors() const - { - return options().errors(); - } - - void Command::ListConfigs::run() { if (_options_parser.hasArgs()) @@ -76,12 +70,6 @@ namespace snapper exit(EXIT_FAILURE); } - if (options().has_errors()) - { - cerr << options().errors().front() << endl; - exit(EXIT_FAILURE); - } - string output; switch (global_options().output_format()) diff --git a/client/Command/ListConfigs.h b/client/Command/ListConfigs.h index 25e805ee..fcdb14e0 100644 --- a/client/Command/ListConfigs.h +++ b/client/Command/ListConfigs.h @@ -50,8 +50,6 @@ namespace snapper const Options& options() const; - virtual std::vector errors() const override; - virtual void run() override; virtual ~ListConfigs(); diff --git a/client/Command/ListConfigs/Options.cc b/client/Command/ListConfigs/Options.cc index 8403e996..5d2c5fdc 100644 --- a/client/Command/ListConfigs/Options.cc +++ b/client/Command/ListConfigs/Options.cc @@ -84,20 +84,9 @@ namespace snapper } - vector Command::ListConfigs::Options::errors() const - { - vector detected_errors; - - if (!_columns_option.wrong_columns().empty()) - detected_errors.push_back(_columns_option.error()); - - return detected_errors; - } - - string Command::ListConfigs::Options::columns_raw() const { - return has_option("columns") ? get_option("columns")->second : ""; + return has_option("columns") ? get_argument("columns") : ""; } } diff --git a/client/Command/ListConfigs/Options.h b/client/Command/ListConfigs/Options.h index 531e8dd9..4ed36993 100644 --- a/client/Command/ListConfigs/Options.h +++ b/client/Command/ListConfigs/Options.h @@ -50,8 +50,6 @@ namespace snapper std::vector columns() const; - virtual std::vector errors() const override; - private: void parse_options(); diff --git a/client/Command/ListSnapshots.cc b/client/Command/ListSnapshots.cc index c62d005e..58d11988 100644 --- a/client/Command/ListSnapshots.cc +++ b/client/Command/ListSnapshots.cc @@ -62,12 +62,6 @@ namespace snapper } - vector Command::ListSnapshots::errors() const - { - return options().errors(); - } - - void Command::ListSnapshots::run() { if (_options_parser.hasArgs()) @@ -76,12 +70,6 @@ namespace snapper exit(EXIT_FAILURE); } - if (options().has_errors()) - { - cerr << options().errors().front() << endl; - exit(EXIT_FAILURE); - } - string output; switch (global_options().output_format()) diff --git a/client/Command/ListSnapshots.h b/client/Command/ListSnapshots.h index 4ceaea0f..4849fe18 100644 --- a/client/Command/ListSnapshots.h +++ b/client/Command/ListSnapshots.h @@ -49,8 +49,6 @@ namespace snapper const Options& options() const; - virtual std::vector errors() const override; - virtual void run() override; virtual ~ListSnapshots(); diff --git a/client/Command/ListSnapshots/Options.cc b/client/Command/ListSnapshots/Options.cc index c503d4e8..ab1ea538 100644 --- a/client/Command/ListSnapshots/Options.cc +++ b/client/Command/ListSnapshots/Options.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] SUSE LLC + * Copyright (c) [2019-2020] SUSE LLC * * All Rights Reserved. * @@ -19,10 +19,10 @@ * find current contact information at www.novell.com. */ -#include - #include +#include + #include "client/Command/ListSnapshots/Options.h" #include "client/utils/text.h" @@ -123,41 +123,31 @@ namespace snapper } - vector Command::ListSnapshots::Options::errors() const - { - vector detected_errors; - - if (wrong_type()) - detected_errors.push_back(type_error()); - - if (wrong_columns()) - detected_errors.push_back(columns_error()); - - return detected_errors; - } - - Command::ListSnapshots::Options::ListMode Command::ListSnapshots::Options::list_mode_value() const { - string type = has_option("type") ? get_option("type")->second : ""; + if (!has_option("type")) + return ListMode::ALL; - if (type == "all") - return LM_ALL; + string str = get_argument("type"); - if (type == "single") - return LM_SINGLE; + ListMode list_mode; + if (!toValue(str, list_mode, false)) + { + string error = sformat(_("Unknown snapshots type %s."), str.c_str()) + '\n' + + sformat(_("Use %s, %s or %s."), toString(ListMode::ALL).c_str(), + toString(ListMode::SINGLE).c_str(), toString(ListMode::PRE_POST).c_str()); - if (type == "pre-post") - return LM_PRE_POST; + SN_THROW(OptionsException(error)); + } - return LM_ALL; + return list_mode; } string Command::ListSnapshots::Options::columns_raw() const { - return has_option("columns") ? get_option("columns")->second : ""; + return has_option("columns") ? get_argument("columns") : ""; } @@ -168,15 +158,15 @@ namespace snapper switch (list_mode()) { - case LM_ALL: + case ListMode::ALL: columns = all_mode_columns(format); break; - case LM_SINGLE: + case ListMode::SINGLE: columns = single_mode_columns(format); break; - case LM_PRE_POST: + case ListMode::PRE_POST: columns = pre_post_mode_columns(format); break; } @@ -331,34 +321,8 @@ namespace snapper throw logic_error("unknown output format"); } + } - bool Command::ListSnapshots::Options::wrong_type() const - { - if (!has_option("type")) - return false; - - string type = get_option("type")->second; - - return type != "all" && type != "single" && type != "pre-post"; - } - - - bool Command::ListSnapshots::Options::wrong_columns() const - { - return !_columns_option.wrong_columns().empty(); - } - - - string Command::ListSnapshots::Options::type_error() const - { - return _("Unknown type of snapshots."); - } - + const vector EnumInfo::names({ "all", "single", "pre-post" }); - string Command::ListSnapshots::Options::columns_error() const - { - return _columns_option.error(); - } - - } } diff --git a/client/Command/ListSnapshots/Options.h b/client/Command/ListSnapshots/Options.h index 0bc1d36d..587b5c35 100644 --- a/client/Command/ListSnapshots/Options.h +++ b/client/Command/ListSnapshots/Options.h @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] SUSE LLC + * Copyright (c) [2019-2020] SUSE LLC * * All Rights Reserved. * @@ -59,31 +59,18 @@ namespace snapper static const std::vector ALL_COLUMNS; - enum ListMode { LM_ALL, LM_SINGLE, LM_PRE_POST }; + enum class ListMode { ALL, SINGLE, PRE_POST }; static std::string help_text(); Options(GetOpts& parser); - ListMode list_mode() const - { - return _list_mode; - } - - bool disable_used_space() const - { - return _disable_used_space; - } - - bool all_configs() const - { - return _all_configs; - } + ListMode list_mode() const { return _list_mode; } + bool disable_used_space() const { return _disable_used_space; } + bool all_configs() const { return _all_configs; } std::vector columns(GlobalOptions::OutputFormat format) const; - virtual std::vector errors() const override; - private: void parse_options(); @@ -100,14 +87,6 @@ namespace snapper std::vector pre_post_mode_columns(GlobalOptions::OutputFormat format) const; - bool wrong_type() const; - - bool wrong_columns() const; - - std::string type_error() const; - - std::string columns_error() const; - ListMode _list_mode; bool _disable_used_space; @@ -119,6 +98,9 @@ namespace snapper }; } + + template <> struct EnumInfo { static const vector names; }; + } #endif diff --git a/client/Command/ListSnapshots/SnappersData.cc b/client/Command/ListSnapshots/SnappersData.cc index fda2770b..dab91b3b 100644 --- a/client/Command/ListSnapshots/SnappersData.cc +++ b/client/Command/ListSnapshots/SnappersData.cc @@ -79,20 +79,20 @@ namespace snapper { switch (command().options().list_mode()) { - case Options::ListMode::LM_ALL: + case Options::ListMode::ALL: { selected.push_back(&snapshot); } break; - case Options::ListMode::LM_SINGLE: + case Options::ListMode::SINGLE: { if (snapshot.getType() == SINGLE) selected.push_back(&snapshot); } break; - case Options::ListMode::LM_PRE_POST: + case Options::ListMode::PRE_POST: { ProxySnapshots::const_iterator post_it = find_post(snapshot, snapshots); @@ -293,7 +293,7 @@ namespace snapper string Command::ListSnapshots::SnappersData::date_value(const ProxySnapshot& snapshot) const { - if (command().options().list_mode() == Options::ListMode::LM_PRE_POST) + if (command().options().list_mode() == Options::ListMode::PRE_POST) return snapshot_date(snapshot); return snapshot.isCurrent() ? "" : snapshot_date(snapshot); diff --git a/client/Command/ListSnapshots/SnappersData/Table.cc b/client/Command/ListSnapshots/SnappersData/Table.cc index 424214c4..d88dbdc8 100644 --- a/client/Command/ListSnapshots/SnappersData/Table.cc +++ b/client/Command/ListSnapshots/SnappersData/Table.cc @@ -75,7 +75,7 @@ namespace snapper return _("Subvolume"); if (column == Options::Columns::NUMBER) - return list_mode == Options::LM_PRE_POST ? _("Pre #") : _("#"); + return list_mode == Options::ListMode::PRE_POST ? _("Pre #") : _("#"); if (column == Options::Columns::DEFAULT) return _("Default"); @@ -87,7 +87,7 @@ namespace snapper return _("Type"); if (column == Options::Columns::DATE) - return list_mode == Options::LM_PRE_POST ? _("Pre Date") : _("Date"); + return list_mode == Options::ListMode::PRE_POST ? _("Pre Date") : _("Date"); if (column == Options::Columns::USER) return _("User"); diff --git a/client/GlobalOptions.cc b/client/GlobalOptions.cc index 7a168ac3..5265f0e7 100644 --- a/client/GlobalOptions.cc +++ b/client/GlobalOptions.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] SUSE LLC + * Copyright (c) [2019-2020] SUSE LLC * * All Rights Reserved. * @@ -36,27 +36,24 @@ namespace snapper namespace { - const string CSV_OPTION = "csv"; - - const string JSON_OPTION = "json"; - const string DEFAULT_CONFIG = "root"; const string DEFAULT_ROOT = "/"; - const option OPTIONS[15] = { + const option OPTIONS[] = { { "quiet", no_argument, 0, 'q' }, { "verbose", no_argument, 0, 'v' }, { "utc", no_argument, 0, 0 }, { "iso", no_argument, 0, 0 }, { "table-style", required_argument, 0, 't' }, - { "machine-readable", required_argument, 0, 0}, - { "csvout", no_argument, 0, 0}, - { "jsonout", no_argument, 0, 0}, - { "separator", required_argument, 0, 0}, + { "machine-readable", required_argument, 0, 0 }, + { "csvout", no_argument, 0, 0 }, + { "jsonout", no_argument, 0, 0 }, + { "separator", required_argument, 0, 0 }, { "config", required_argument, 0, 'c' }, { "no-dbus", no_argument, 0, 0 }, { "root", required_argument, 0, 'r' }, + { "ambit", required_argument, 0, 'a' }, { "version", no_argument, 0, 0 }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } @@ -80,14 +77,16 @@ namespace snapper + _("\t--config, -c \t\tSet name of config to use.") + '\n' + _("\t--no-dbus\t\t\tOperate without DBus.") + '\n' + _("\t--root, -r \t\tOperate on target root (works only without DBus).") + '\n' + + _("\t--ambit, -a ambit\t\tOperate in the specified ambit.") + '\n' + _("\t--version\t\t\tPrint version and exit.") + '\n'; } - GlobalOptions::GlobalOptions(GetOpts& parser) : - Options(parser) + GlobalOptions::GlobalOptions(GetOpts& parser) + : Options(parser), _ambit(Ambit::AUTO) { parse_options(); + check_options(); _quiet = has_option("quiet"); _verbose = has_option("verbose"); @@ -101,6 +100,7 @@ namespace snapper _separator = separator_value(); _config = config_value(); _root = root_value(); + _ambit = ambit_value(); } @@ -110,139 +110,123 @@ namespace snapper } - vector GlobalOptions::errors() const + void + GlobalOptions::check_options() const { - vector detected_errors; + if (has_option("root") && !has_option("no-dbus")) + { + string error =_("root argument can be used only together with no-dbus.\n" + "Try 'snapper --help' for more information."); - if (wrong_table_style()) - detected_errors.push_back(table_style_error()); + SN_THROW(OptionsException(error)); + } + } - if (wrong_machine_readable()) - detected_errors.push_back(machine_readable_error()); - if (missing_no_dbus()) - detected_errors.push_back(missing_no_dbus_error()); + TableLineStyle + GlobalOptions::table_style_value() const + { + if (!has_option("table-style")) + return TableFormatter::default_style(); - return detected_errors; - } + string str = get_argument("table-style"); + unsigned long value = stoul(str); + if (value >= Table::numStyles) + { + string error = sformat(_("Invalid table style %s."), str.c_str()) + '\n' + + sformat(_("Use an integer number from %d to %d."), 0, Table::numStyles - 1); - TableLineStyle GlobalOptions::table_style_value() const - { - if (has_option("table-style") && !wrong_table_style()) - return (TableLineStyle) table_style_raw(); + SN_THROW(OptionsException(error)); + } - return TableFormatter::default_style(); + return (TableLineStyle)(value); } - GlobalOptions::OutputFormat GlobalOptions::output_format_value() const + GlobalOptions::OutputFormat + GlobalOptions::output_format_value() const { - if (has_option("csvout") || machine_readable_value() == CSV_OPTION) + if (has_option("csvout")) return OutputFormat::CSV; - if (has_option("jsonout") || machine_readable_value() == JSON_OPTION) + if (has_option("jsonout")) return OutputFormat::JSON; - return OutputFormat::TABLE; - } + if (!has_option("machine-readable")) + return OutputFormat::TABLE; + string str = get_argument("machine-readable"); - string GlobalOptions::machine_readable_value() const - { - if (has_option("machine-readable")) - return get_option("machine-readable")->second; + OutputFormat output_format; + if (!toValue(str, output_format, false)) + { + string error = sformat(_("Invalid machine readable format %s."), str.c_str()) + '\n' + + sformat(_("Use %s, %s or %s."), toString(OutputFormat::TABLE).c_str(), + toString(OutputFormat::CSV).c_str(), toString(OutputFormat::JSON).c_str()); - return ""; + SN_THROW(OptionsException(error)); + } + + return output_format; } - string GlobalOptions::separator_value() const + string + GlobalOptions::separator_value() const { if (has_option("separator")) - return get_option("separator")->second; + return get_argument("separator"); return CsvFormatter::default_separator(); } - string GlobalOptions::config_value() const + string + GlobalOptions::config_value() const { if (has_option("config")) - return get_option("config")->second; + return get_argument("config"); return DEFAULT_CONFIG; } - string GlobalOptions::root_value() const + string + GlobalOptions::root_value() const { if (has_option("root")) - return get_option("root")->second; + return get_argument("root"); return DEFAULT_ROOT; } - unsigned int GlobalOptions::table_style_raw() const - { - return stoul(get_option("table-style")->second); - } - - - bool GlobalOptions::wrong_table_style() const - { - if (!has_option("table-style")) - return false; - - if (table_style_raw() >= Table::numStyles) - return true; - - return false; - } - - - bool GlobalOptions::wrong_machine_readable() const + GlobalOptions::Ambit + GlobalOptions::ambit_value() const { - if (!has_option("machine-readable")) - return false; - - string value = machine_readable_value(); + if (!has_option("ambit")) + return Ambit::AUTO; - if (value != CSV_OPTION && value != JSON_OPTION) - return true; + string str = get_argument("ambit"); - return false; - } + Ambit ambit; + if (!toValue(str, ambit, false)) + { + string error = sformat(_("Invalid ambit %s."), str.c_str()) + '\n' + + sformat(_("Use %s, %s or %s."), toString(Ambit::AUTO).c_str(), + toString(Ambit::CLASSIC).c_str(), toString(Ambit::TRANSACTIONAL).c_str()); + SN_THROW(OptionsException(error)); + } - bool GlobalOptions::missing_no_dbus() const - { - return has_option("root") && !has_option("no-dbus"); + return ambit; } + } - string GlobalOptions::table_style_error() const - { - return sformat(_("Invalid table style %d."), table_style_raw()) + " " + - sformat(_("Use an integer number from %d to %d."), 0, Table::numStyles - 1); - } - - - string GlobalOptions::machine_readable_error() const - { - string format = machine_readable_value(); - - return sformat(_("Invalid machine readable format %s."), format.c_str()) + " " + - sformat(_("Use %s or %s."), CSV_OPTION.c_str(), JSON_OPTION.c_str()); - } - + const vector EnumInfo::names({ "table", "csv", "json" }); - string GlobalOptions::missing_no_dbus_error() const - { - return _("root argument can be used only together with no-dbus.\n" - "Try 'snapper --help' for more information."); - } + const vector EnumInfo::names({ "auto", "classic", "transactional" }); - } } diff --git a/client/GlobalOptions.h b/client/GlobalOptions.h index 89c16b94..86177946 100644 --- a/client/GlobalOptions.h +++ b/client/GlobalOptions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] SUSE LLC + * Copyright (c) [2019-2020] SUSE LLC * * All Rights Reserved. * @@ -24,6 +24,8 @@ #include +#include + #include "client/Options.h" #include "client/utils/GetOpts.h" #include "client/utils/Table.h" @@ -38,132 +40,64 @@ namespace snapper public: - enum OutputFormat { TABLE, CSV, JSON }; + enum class OutputFormat { TABLE, CSV, JSON }; + enum class Ambit { AUTO, CLASSIC, TRANSACTIONAL }; - static std::string help_text(); + static string help_text(); GlobalOptions(GetOpts& parser); - virtual std::vector errors() const override; - - bool quiet() const - { - return _quiet; - } - - bool verbose() const - { - return _verbose; - } - - bool utc() const - { - return _utc; - } - - bool iso() const - { - return _iso; - } - - bool no_dbus() const - { - return _no_dbus; - } - - bool version() const - { - return _version; - } - - bool help() const - { - return _help; - } - - TableLineStyle table_style() const - { - return _table_style; - } - - OutputFormat output_format() const - { - return _output_format; - } - - string separator() const - { - return _separator; - } - - string config() const - { - return _config; - } - - - string root() const - { - return _root; - } + bool quiet() const { return _quiet; } + bool verbose() const { return _verbose; } + bool utc() const { return _utc; } + bool iso() const { return _iso; } + bool no_dbus() const { return _no_dbus; } + bool version() const { return _version; } + bool help() const { return _help; } + TableLineStyle table_style() const { return _table_style; } + OutputFormat output_format() const { return _output_format; } + string separator() const { return _separator; } + string config() const { return _config; } + string root() const { return _root; } + Ambit ambit() { return _ambit; } + + void set_ambit(Ambit ambit) { _ambit = ambit; } private: void parse_options(); + void check_options() const; TableLineStyle table_style_value() const; - OutputFormat output_format_value() const; - - std::string machine_readable_value() const; - - std::string separator_value() const; - - std::string config_value() const; - - std::string root_value() const; - - unsigned int table_style_raw() const; - - bool wrong_table_style() const; - - bool wrong_machine_readable() const; - - bool missing_no_dbus() const; - - std::string table_style_error() const; - - std::string machine_readable_error() const; - - std::string missing_no_dbus_error() const; + string separator_value() const; + string config_value() const; + string root_value() const; + Ambit ambit_value() const; bool _quiet; - bool _verbose; - bool _utc; - bool _iso; - bool _no_dbus; - bool _version; - bool _help; - TableLineStyle _table_style; - OutputFormat _output_format; - string _separator; - string _config; - string _root; + Ambit _ambit; }; } + + + template <> struct EnumInfo { static const vector names; }; + + template <> struct EnumInfo { static const vector names; }; + } -#endif \ No newline at end of file +#endif diff --git a/client/Options.cc b/client/Options.cc index 0f2f4449..8e3aea8c 100644 --- a/client/Options.cc +++ b/client/Options.cc @@ -31,33 +31,22 @@ namespace snapper namespace cli { - Options::Options(GetOpts& parser) : - _parser(parser), _options() + Options::Options(GetOpts& parser) + : _parser(parser), _options() {} - Options::~Options() - {} - - - bool Options::has_option(const string option_name) const - { - GetOpts::parsed_opts::const_iterator option = get_option(option_name); - - return option != _options.end(); - } - - - GetOpts::parsed_opts::const_iterator - Options::get_option(const string option_name) const + bool + Options::has_option(const string& name) const { - return _options.find(option_name); + return _options.find(name) != _options.end(); } - bool Options::has_errors() const + const string& + Options::get_argument(const string& name) const { - return !errors().empty(); + return _options.find(name)->second; } } diff --git a/client/Options.h b/client/Options.h index 10bfe1dd..7386d6e1 100644 --- a/client/Options.h +++ b/client/Options.h @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019] SUSE LLC + * Copyright (c) [2019-2020] SUSE LLC * * All Rights Reserved. * @@ -25,10 +25,22 @@ #include #include +#include + #include "client/utils/GetOpts.h" namespace snapper { + using std::string; + using std::vector; + + + struct OptionsException : public Exception + { + explicit OptionsException(const string& msg) : Exception(msg) {} + }; + + namespace cli { @@ -39,18 +51,13 @@ namespace snapper Options(GetOpts& parser); - virtual bool has_errors() const; - - virtual std::vector errors() const = 0; - - virtual ~Options(); + virtual ~Options() {} protected: - bool has_option(const std::string option_name) const; + bool has_option(const string& name) const; - GetOpts::parsed_opts::const_iterator - get_option(const std::string option_name) const; + const string& get_argument(const string& name) const; GetOpts& _parser; @@ -61,4 +68,4 @@ namespace snapper } } -#endif \ No newline at end of file +#endif diff --git a/client/proxy-dbus.cc b/client/proxy-dbus.cc index 928da45b..9feab6fb 100644 --- a/client/proxy-dbus.cc +++ b/client/proxy-dbus.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) [2016-2019] SUSE LLC + * Copyright (c) [2016-2020] SUSE LLC * * All Rights Reserved. * @@ -124,6 +124,15 @@ ProxySnapshotsDbus::getDefault() } +ProxySnapshots::iterator +ProxySnapshotsDbus::getActive() +{ + pair tmp = command_get_active_snapshot(conn(), configName()); + + return tmp.first ? find(tmp.second) : end(); +} + + ProxySnapshots::const_iterator ProxySnapshotsDbus::getActive() const { diff --git a/client/proxy-dbus.h b/client/proxy-dbus.h index 6a2acd74..20df6216 100644 --- a/client/proxy-dbus.h +++ b/client/proxy-dbus.h @@ -1,5 +1,5 @@ /* - * Copyright (c) [2016-2019] SUSE LLC + * Copyright (c) [2016-2020] SUSE LLC * * All Rights Reserved. * @@ -96,6 +96,7 @@ public: virtual iterator getDefault() override; virtual const_iterator getDefault() const override; + virtual iterator getActive() override; virtual const_iterator getActive() const override; DBus::Connection& conn() const; diff --git a/client/proxy-lib.cc b/client/proxy-lib.cc index c5bf341a..aa8157ed 100644 --- a/client/proxy-lib.cc +++ b/client/proxy-lib.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) [2016-2019] SUSE LLC + * Copyright (c) [2016-2020] SUSE LLC * * All Rights Reserved. * @@ -48,6 +48,17 @@ ProxySnapshotsLib::getDefault() const } +ProxySnapshots::iterator +ProxySnapshotsLib::getActive() +{ + Snapshots& snapshots = backref->snapper->getSnapshots(); + + Snapshots::const_iterator tmp = snapshots.getActive(); + + return tmp != snapshots.end() ? find(tmp->getNum()) : end(); +} + + ProxySnapshots::const_iterator ProxySnapshotsLib::getActive() const { diff --git a/client/proxy-lib.h b/client/proxy-lib.h index 3602e905..e3b9a6d7 100644 --- a/client/proxy-lib.h +++ b/client/proxy-lib.h @@ -1,5 +1,5 @@ /* - * Copyright (c) [2016-2019] SUSE LLC + * Copyright (c) [2016-2020] SUSE LLC * * All Rights Reserved. * @@ -82,6 +82,7 @@ public: virtual iterator getDefault() override; virtual const_iterator getDefault() const override; + virtual iterator getActive() override; virtual const_iterator getActive() const override; ProxySnapshotsLib(ProxySnapperLib* backref); diff --git a/client/proxy.h b/client/proxy.h index 606105ec..bf0c1db9 100644 --- a/client/proxy.h +++ b/client/proxy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) [2016-2019] SUSE LLC + * Copyright (c) [2016-2020] SUSE LLC * * All Rights Reserved. * @@ -175,6 +175,7 @@ public: virtual iterator getDefault() = 0; virtual const_iterator getDefault() const = 0; + virtual iterator getActive() = 0; virtual const_iterator getActive() const = 0; iterator find(unsigned int i); diff --git a/client/snapper.cc b/client/snapper.cc index fa76d37c..cec688b1 100644 --- a/client/snapper.cc +++ b/client/snapper.cc @@ -1,6 +1,6 @@ /* * Copyright (c) [2011-2015] Novell, Inc. - * Copyright (c) [2016-2019] SUSE LLC + * Copyright (c) [2016-2020] SUSE LLC * * All Rights Reserved. * @@ -63,7 +63,7 @@ using namespace std; struct Cmd { - typedef void (*cmd_func_t)(cli::GlobalOptions* global_options, ProxySnappers* snappers, + typedef void (*cmd_func_t)(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper); typedef void (*help_func_t)(); @@ -170,9 +170,9 @@ help_list_configs() void -command_list_configs(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*) +command_list_configs(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*) { - cli::Command::ListConfigs command(*global_options, getopts, *snappers); + cli::Command::ListConfigs command(global_options, getopts, *snappers); command.run(); } @@ -192,7 +192,7 @@ help_create_config() void -command_create_config(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*) +command_create_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*) { const struct option options[] = { { "fstype", required_argument, 0, 'f' }, @@ -231,7 +231,7 @@ command_create_config(cli::GlobalOptions* global_options, ProxySnappers* snapper exit(EXIT_FAILURE); } - snappers->createConfig(global_options->config(), subvolume, fstype, template_name); + snappers->createConfig(global_options.config(), subvolume, fstype, template_name); } @@ -245,7 +245,7 @@ help_delete_config() void -command_delete_config(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*) +command_delete_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*) { getopts.parse("delete-config", GetOpts::no_options); if (getopts.hasArgs()) @@ -254,7 +254,7 @@ command_delete_config(cli::GlobalOptions* global_options, ProxySnappers* snapper exit(EXIT_FAILURE); } - snappers->deleteConfig(global_options->config()); + snappers->deleteConfig(global_options.config()); } @@ -266,9 +266,9 @@ help_get_config() void -command_get_config(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*) +command_get_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*) { - cli::Command::GetConfig command(*global_options, getopts, *snappers); + cli::Command::GetConfig command(global_options, getopts, *snappers); command.run(); } @@ -284,7 +284,7 @@ help_set_config() void -command_set_config(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_set_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { getopts.parse("set-config", GetOpts::no_options); if (!getopts.hasArgs()) @@ -307,9 +307,9 @@ help_list() void -command_list(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*) +command_list(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*) { - cli::Command::ListSnapshots command(*global_options, getopts, *snappers); + cli::Command::ListSnapshots command(global_options, getopts, *snappers); command.run(); } @@ -337,7 +337,7 @@ help_create() void -command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_create(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "type", required_argument, 0, 't' }, @@ -360,11 +360,11 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox exit(EXIT_FAILURE); } - enum CreateType { CT_SINGLE, CT_PRE, CT_POST, CT_PRE_POST }; + enum class CreateType { SINGLE, PRE, POST, PRE_POST }; const ProxySnapshots& snapshots = snapper->getSnapshots(); - CreateType type = CT_SINGLE; + CreateType type = CreateType::SINGLE; ProxySnapshots::const_iterator snapshot1 = snapshots.end(); ProxySnapshots::const_iterator snapshot2 = snapshots.end(); bool print_number = false; @@ -377,13 +377,13 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox if ((opt = opts.find("type")) != opts.end()) { if (opt->second == "single") - type = CT_SINGLE; + type = CreateType::SINGLE; else if (opt->second == "pre") - type = CT_PRE; + type = CreateType::PRE; else if (opt->second == "post") - type = CT_POST; + type = CreateType::POST; else if (opt->second == "pre-post") - type = CT_PRE_POST; + type = CreateType::PRE_POST; else { cerr << _("Unknown type of snapshot.") << endl; @@ -409,7 +409,7 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox if ((opt = opts.find("command")) != opts.end()) { command = opt->second; - type = CT_PRE_POST; + type = CreateType::PRE_POST; } if ((opt = opts.find("read-only")) != opts.end()) @@ -421,25 +421,25 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox if ((opt = opts.find("from")) != opts.end()) parent = snapshots.findNum(opt->second); - if (type == CT_POST && snapshot1 == snapshots.end()) + if (type == CreateType::POST && snapshot1 == snapshots.end()) { cerr << _("Missing or invalid pre-number.") << endl; exit(EXIT_FAILURE); } - if (type == CT_PRE_POST && command.empty()) + if (type == CreateType::PRE_POST && command.empty()) { cerr << _("Missing command argument.") << endl; exit(EXIT_FAILURE); } - if (type != CT_SINGLE && !scd.read_only) + if (type != CreateType::SINGLE && !scd.read_only) { cerr << _("Option --read-write only supported for snapshots of type single.") << endl; exit(EXIT_FAILURE); } - if (type != CT_SINGLE && parent != snapshots.getCurrent()) + if (type != CreateType::SINGLE && parent != snapshots.getCurrent()) { cerr << _("Option --from only supported for snapshots of type single.") << endl; exit(EXIT_FAILURE); @@ -447,25 +447,25 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox switch (type) { - case CT_SINGLE: { + case CreateType::SINGLE: { snapshot1 = snapper->createSingleSnapshot(parent, scd); if (print_number) cout << snapshot1->getNum() << endl; } break; - case CT_PRE: { + case CreateType::PRE: { snapshot1 = snapper->createPreSnapshot(scd); if (print_number) cout << snapshot1->getNum() << endl; } break; - case CT_POST: { + case CreateType::POST: { snapshot2 = snapper->createPostSnapshot(snapshot1, scd); if (print_number) cout << snapshot2->getNum() << endl; } break; - case CT_PRE_POST: { + case CreateType::PRE_POST: { snapshot1 = snapper->createPreSnapshot(scd); system(command.c_str()); snapshot2 = snapper->createPostSnapshot(snapshot1, scd); @@ -491,7 +491,7 @@ help_modify() void -command_modify(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_modify(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "description", required_argument, 0, 'd' }, @@ -575,7 +575,7 @@ filter_undeletables(ProxySnapshots& snapshots, vector& void -command_delete(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_delete(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "sync", no_argument, 0, 's' }, @@ -632,7 +632,7 @@ command_delete(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox filter_undeletables(snapshots, nums); - snapper->deleteSnapshots(nums, global_options->verbose()); + snapper->deleteSnapshots(nums, global_options.verbose()); if (sync) snapper->syncFilesystem(); @@ -649,7 +649,7 @@ help_mount() void -command_mount(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_mount(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { getopts.parse("mount", GetOpts::no_options); if (!getopts.hasArgs()) @@ -678,7 +678,7 @@ help_umount() void -command_umount(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_umount(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { getopts.parse("umount", GetOpts::no_options); if (!getopts.hasArgs()) @@ -710,7 +710,7 @@ help_status() void -command_status(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_status(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "output", required_argument, 0, 'o' }, @@ -778,7 +778,7 @@ help_diff() void -command_diff(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_diff(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "input", required_argument, 0, 'i' }, @@ -843,7 +843,7 @@ help_undo() void -command_undo(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_undo(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "input", required_argument, 0, 'i' }, @@ -918,7 +918,7 @@ command_undo(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxyS exit(EXIT_FAILURE); } - if (global_options->verbose()) + if (global_options.verbose()) { switch (it1->action) { @@ -997,7 +997,7 @@ help_rollback() void -command_rollback(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_rollback(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { const struct option options[] = { { "print-number", no_argument, 0, 'p' }, @@ -1046,7 +1046,7 @@ command_rollback(cli::GlobalOptions* global_options, ProxySnappers* snappers, Pr ProxyConfig config = snapper->getConfig(); - const Filesystem* filesystem = getFilesystem(config, global_options->root()); + const Filesystem* filesystem = getFilesystem(config, global_options.root()); if (filesystem->fstype() != "btrfs") { cerr << _("Command 'rollback' only available for btrfs.") << endl; @@ -1065,78 +1065,138 @@ command_rollback(cli::GlobalOptions* global_options, ProxySnappers* snappers, Pr ProxySnapshots::iterator previous_default = snapshots.getDefault(); + if (global_options.ambit() == cli::GlobalOptions::Ambit::AUTO) + { + if (filesystem->isSnapshotReadOnly(previous_default->getNum())) + global_options.set_ambit(cli::GlobalOptions::Ambit::TRANSACTIONAL); + else + global_options.set_ambit(cli::GlobalOptions::Ambit::CLASSIC); + } + + if (!global_options.quiet()) + cout << sformat(_("Ambit is %s."), toString(global_options.ambit()).c_str()) << endl; + if (previous_default != snapshots.end() && scd1.description == default_description1) scd1.description += sformat(" of #%d", previous_default->getNum()); - ProxySnapshots::const_iterator snapshot1 = snapshots.end(); - ProxySnapshots::const_iterator snapshot2 = snapshots.end(); - - if (getopts.numArgs() == 0) + switch (global_options.ambit()) { - if (!global_options->quiet()) - cout << _("Creating read-only snapshot of default subvolume.") << flush; + case cli::GlobalOptions::Ambit::CLASSIC: + { + ProxySnapshots::const_iterator snapshot1 = snapshots.end(); + ProxySnapshots::const_iterator snapshot2 = snapshots.end(); - scd1.read_only = true; - snapshot1 = snapper->createSingleSnapshotOfDefault(scd1); + if (getopts.numArgs() == 0) + { + if (!global_options.quiet()) + cout << _("Creating read-only snapshot of default subvolume.") << flush; - if (!global_options->quiet()) - cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl; + scd1.read_only = true; + snapshot1 = snapper->createSingleSnapshotOfDefault(scd1); - if (!global_options->quiet()) - cout << _("Creating read-write snapshot of current subvolume.") << flush; + if (!global_options.quiet()) + cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl; - ProxySnapshots::const_iterator active = snapshots.getActive(); - if (active != snapshots.end() && scd2.description == default_description2) - scd2.description += sformat(" of #%d", active->getNum()); + if (!global_options.quiet()) + cout << _("Creating read-write snapshot of current subvolume.") << flush; - scd2.read_only = false; - snapshot2 = snapper->createSingleSnapshot(snapshots.getCurrent(), scd2); + ProxySnapshots::const_iterator active = snapshots.getActive(); + if (active != snapshots.end() && scd2.description == default_description2) + scd2.description += sformat(" of #%d", active->getNum()); - if (!global_options->quiet()) - cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl; - } - else - { - ProxySnapshots::const_iterator tmp = snapshots.findNum(getopts.popArg()); + scd2.read_only = false; + snapshot2 = snapper->createSingleSnapshot(snapshots.getCurrent(), scd2); - if (!global_options->quiet()) - cout << _("Creating read-only snapshot of current system.") << flush; + if (!global_options.quiet()) + cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl; + } + else + { + ProxySnapshots::const_iterator tmp = snapshots.findNum(getopts.popArg()); - snapshot1 = snapper->createSingleSnapshot(scd1); + if (!global_options.quiet()) + cout << _("Creating read-only snapshot of current system.") << flush; - if (!global_options->quiet()) - cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl; + snapshot1 = snapper->createSingleSnapshot(scd1); - if (!global_options->quiet()) - cout << sformat(_("Creating read-write snapshot of snapshot %d."), tmp->getNum()) << flush; + if (!global_options.quiet()) + cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl; - if (tmp != snapshots.end() && scd2.description == default_description2) - scd2.description += sformat(" of #%d", tmp->getNum()); + if (!global_options.quiet()) + cout << sformat(_("Creating read-write snapshot of snapshot %d."), tmp->getNum()) << flush; - scd2.read_only = false; - snapshot2 = snapper->createSingleSnapshot(tmp, scd2); + if (tmp != snapshots.end() && scd2.description == default_description2) + scd2.description += sformat(" of #%d", tmp->getNum()); - if (!global_options->quiet()) - cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl; - } + scd2.read_only = false; + snapshot2 = snapper->createSingleSnapshot(tmp, scd2); - if (previous_default != snapshots.end() && previous_default->getCleanup().empty()) - { - SMD smd = previous_default->getSmd(); - smd.cleanup = "number"; - snapper->modifySnapshot(previous_default, smd); - } + if (!global_options.quiet()) + cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl; + } + + if (previous_default != snapshots.end() && previous_default->getCleanup().empty()) + { + SMD smd = previous_default->getSmd(); + smd.cleanup = "number"; + snapper->modifySnapshot(previous_default, smd); + } - if (!global_options->quiet()) - cout << sformat(_("Setting default subvolume to snapshot %d."), snapshot2->getNum()) << endl; + if (!global_options.quiet()) + cout << sformat(_("Setting default subvolume to snapshot %d."), snapshot2->getNum()) << endl; - filesystem->setDefault(snapshot2->getNum()); + filesystem->setDefault(snapshot2->getNum()); - Hooks::rollback(filesystem->snapshotDir(snapshot1->getNum()), - filesystem->snapshotDir(snapshot2->getNum())); + Hooks::rollback(filesystem->snapshotDir(snapshot1->getNum()), + filesystem->snapshotDir(snapshot2->getNum())); - if (print_number) - cout << snapshot2->getNum() << endl; + if (print_number) + cout << snapshot2->getNum() << endl; + } + break; + + case cli::GlobalOptions::Ambit::TRANSACTIONAL: + { + // see bsc #1172273 + + ProxySnapshots::iterator snapshot = snapshots.end(); + + if (getopts.numArgs() == 0) + { + snapshot = snapshots.getActive(); + } + else + { + snapshot = snapshots.findNum(getopts.popArg()); + } + + if (previous_default == snapshot) + { + cerr << _("Active snapshot is already default snapshot.") << endl; + exit(EXIT_FAILURE); + } + + SMD smd = snapshot->getSmd(); + smd.cleanup = ""; + snapper->modifySnapshot(snapshot, smd); + + if (!global_options.quiet()) + cout << sformat(_("Setting default subvolume to snapshot %d."), snapshot->getNum()) << endl; + + filesystem->setDefault(snapshot->getNum()); + + Hooks::rollback(filesystem->snapshotDir(previous_default->getNum()), + filesystem->snapshotDir(snapshot->getNum())); + } + break; + + case cli::GlobalOptions::Ambit::AUTO: + { + cerr << "internal error: ambit is auto" << endl; + exit(EXIT_FAILURE); + } + break; + } } #endif @@ -1152,7 +1212,7 @@ help_setup_quota() void -command_setup_quota(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_setup_quota(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { GetOpts::parsed_opts opts = getopts.parse("setup-quota", GetOpts::no_options); if (getopts.numArgs() != 0) @@ -1175,7 +1235,7 @@ help_cleanup() void -command_cleanup(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_cleanup(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { GetOpts::parsed_opts opts = getopts.parse("cleanup", GetOpts::no_options); if (getopts.numArgs() != 1) @@ -1188,15 +1248,15 @@ command_cleanup(cli::GlobalOptions* global_options, ProxySnappers* snappers, Pro if (cleanup == "number") { - do_cleanup_number(snapper, global_options->verbose()); + do_cleanup_number(snapper, global_options.verbose()); } else if (cleanup == "timeline") { - do_cleanup_timeline(snapper, global_options->verbose()); + do_cleanup_timeline(snapper, global_options.verbose()); } else if (cleanup == "empty-pre-post") { - do_cleanup_empty_pre_post(snapper, global_options->verbose()); + do_cleanup_empty_pre_post(snapper, global_options.verbose()); } else { @@ -1213,7 +1273,7 @@ help_debug() void -command_debug(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*) +command_debug(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*) { getopts.parse("debug", GetOpts::no_options); if (getopts.hasArgs()) @@ -1257,7 +1317,7 @@ print_xa_diff(const string loc_pre, const string loc_post) } void -command_xa_diff(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper) +command_xa_diff(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper) { GetOpts::parsed_opts opts = getopts.parse("xadiff", GetOpts::no_options); if (getopts.numArgs() < 1) @@ -1390,161 +1450,169 @@ main(int argc, char** argv) Cmd("debug", command_debug, help_debug, false) }; - getopts.init(argc, argv); - - cli::GlobalOptions global_options(getopts); - - if (global_options.has_errors()) + try { - cerr << global_options.errors().front() << endl; + getopts.init(argc, argv); - exit(EXIT_FAILURE); - } + cli::GlobalOptions global_options(getopts); - if (global_options.version()) - { - cout << "snapper " << Snapper::compileVersion() << endl; - cout << "flags " << Snapper::compileFlags() << endl; - exit(EXIT_SUCCESS); - } + if (global_options.version()) + { + cout << "snapper " << Snapper::compileVersion() << endl; + cout << "flags " << Snapper::compileFlags() << endl; + exit(EXIT_SUCCESS); + } - if (global_options.help()) - { - help(cmds); - } + if (global_options.help()) + { + help(cmds); + } - if (!getopts.hasArgs()) - { - cerr << _("No command provided.") << endl - << _("Try 'snapper --help' for more information.") << endl; - exit(EXIT_FAILURE); - } + if (!getopts.hasArgs()) + { + cerr << _("No command provided.") << endl + << _("Try 'snapper --help' for more information.") << endl; + exit(EXIT_FAILURE); + } - const char* command = getopts.popArg(); + const char* command = getopts.popArg(); - list::const_iterator cmd = cmds.begin(); - while (cmd != cmds.end() && (cmd->name != command && !contains(cmd->aliases, command))) - ++cmd; + list::const_iterator cmd = cmds.begin(); + while (cmd != cmds.end() && (cmd->name != command && !contains(cmd->aliases, command))) + ++cmd; - if (cmd == cmds.end()) - { - cerr << sformat(_("Unknown command '%s'."), command) << endl - << _("Try 'snapper --help' for more information.") << endl; - exit(EXIT_FAILURE); - } + if (cmd == cmds.end()) + { + cerr << sformat(_("Unknown command '%s'."), command) << endl + << _("Try 'snapper --help' for more information.") << endl; + exit(EXIT_FAILURE); + } - try - { - ProxySnappers snappers(global_options.no_dbus() ? ProxySnappers::createLib(global_options.root()) : - ProxySnappers::createDbus()); + try + { + ProxySnappers snappers(global_options.no_dbus() ? ProxySnappers::createLib(global_options.root()) : + ProxySnappers::createDbus()); - if (cmd->needs_snapper) - (*cmd->cmd_func)(&global_options, &snappers, snappers.getSnapper(global_options.config())); - else - (*cmd->cmd_func)(&global_options, &snappers, nullptr); - } - catch (const DBus::ErrorException& e) - { - SN_CAUGHT(e); + if (cmd->needs_snapper) + (*cmd->cmd_func)(global_options, &snappers, snappers.getSnapper(global_options.config())); + else + (*cmd->cmd_func)(global_options, &snappers, nullptr); + } + catch (const DBus::ErrorException& e) + { + SN_CAUGHT(e); + + if (strcmp(e.name(), "error.unknown_config") == 0 && global_options.config() == "root") + { + cerr << _("The config 'root' does not exist. Likely snapper is not configured.") << endl + << _("See 'man snapper' for further instructions.") << endl; + exit(EXIT_FAILURE); + } - if (strcmp(e.name(), "error.unknown_config") == 0 && global_options.config() == "root") + cerr << error_description(e) << endl; + exit(EXIT_FAILURE); + } + catch (const DBus::FatalException& e) { - cerr << _("The config 'root' does not exist. Likely snapper is not configured.") << endl - << _("See 'man snapper' for further instructions.") << endl; + SN_CAUGHT(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(_("Config '%s' not found."), global_options.config().c_str()) << endl; + exit(EXIT_FAILURE); + } + catch (const InvalidConfigException& e) + { + SN_CAUGHT(e); + cerr << sformat(_("Config '%s' is invalid."), global_options.config().c_str()) << endl; + exit(EXIT_FAILURE); + } + catch (const ListConfigsFailedException& e) + { + SN_CAUGHT(e); + cerr << sformat(_("Listing configs failed (%s)."), e.what()) << endl; + exit(EXIT_FAILURE); + } + catch (const CreateConfigFailedException& e) + { + SN_CAUGHT(e); + cerr << sformat(_("Creating config failed (%s)."), e.what()) << endl; + exit(EXIT_FAILURE); + } + catch (const DeleteConfigFailedException& e) + { + SN_CAUGHT(e); + cerr << sformat(_("Deleting config failed (%s)."), e.what()) << endl; + exit(EXIT_FAILURE); + } + catch (const InvalidConfigdataException& e) + { + SN_CAUGHT(e); + cerr << _("Invalid configdata.") << endl; + exit(EXIT_FAILURE); + } + catch (const AclException& e) + { + SN_CAUGHT(e); + cerr << _("ACL error.") << endl; + exit(EXIT_FAILURE); + } + catch (const IOErrorException& e) + { + SN_CAUGHT(e); + cerr << sformat(_("IO error (%s)."), e.what()) << endl; + exit(EXIT_FAILURE); + } + catch (const InvalidUserException& e) + { + SN_CAUGHT(e); + cerr << _("Invalid user.") << endl; + exit(EXIT_FAILURE); + } + catch (const InvalidGroupException& e) + { + SN_CAUGHT(e); + cerr << _("Invalid group.") << endl; + exit(EXIT_FAILURE); + } + catch (const QuotaException& e) + { + SN_CAUGHT(e); + cerr << sformat(_("Quota error (%s)."), e.what()) << endl; + exit(EXIT_FAILURE); + } + catch (const FreeSpaceException& e) + { + SN_CAUGHT(e); + cerr << sformat(_("Free space error (%s)."), e.what()) << endl; + exit(EXIT_FAILURE); + } + catch (const OptionsException& e) + { + SN_CAUGHT(e); + cerr << e.what() << endl; + exit(EXIT_FAILURE); + } + catch (const Exception& e) + { + SN_CAUGHT(e); + cerr << sformat(_("Error (%s)."), e.what()) << endl; exit(EXIT_FAILURE); } - - cerr << error_description(e) << endl; - exit(EXIT_FAILURE); - } - catch (const DBus::FatalException& e) - { - SN_CAUGHT(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(_("Config '%s' not found."), global_options.config().c_str()) << endl; - exit(EXIT_FAILURE); - } - catch (const InvalidConfigException& e) - { - SN_CAUGHT(e); - cerr << sformat(_("Config '%s' is invalid."), global_options.config().c_str()) << endl; - exit(EXIT_FAILURE); - } - catch (const ListConfigsFailedException& e) - { - SN_CAUGHT(e); - cerr << sformat(_("Listing configs failed (%s)."), e.what()) << endl; - exit(EXIT_FAILURE); - } - catch (const CreateConfigFailedException& e) - { - SN_CAUGHT(e); - cerr << sformat(_("Creating config failed (%s)."), e.what()) << endl; - exit(EXIT_FAILURE); - } - catch (const DeleteConfigFailedException& e) - { - SN_CAUGHT(e); - cerr << sformat(_("Deleting config failed (%s)."), e.what()) << endl; - exit(EXIT_FAILURE); - } - catch (const InvalidConfigdataException& e) - { - SN_CAUGHT(e); - cerr << _("Invalid configdata.") << endl; - exit(EXIT_FAILURE); - } - catch (const AclException& e) - { - SN_CAUGHT(e); - cerr << _("ACL error.") << endl; - exit(EXIT_FAILURE); - } - catch (const IOErrorException& e) - { - SN_CAUGHT(e); - cerr << sformat(_("IO error (%s)."), e.what()) << endl; - exit(EXIT_FAILURE); - } - catch (const InvalidUserException& e) - { - SN_CAUGHT(e); - cerr << _("Invalid user.") << endl; - exit(EXIT_FAILURE); - } - catch (const InvalidGroupException& e) - { - SN_CAUGHT(e); - cerr << _("Invalid group.") << endl; - exit(EXIT_FAILURE); - } - catch (const QuotaException& e) - { - SN_CAUGHT(e); - cerr << sformat(_("Quota error (%s)."), e.what()) << endl; - exit(EXIT_FAILURE); - } - catch (const FreeSpaceException& e) - { - SN_CAUGHT(e); - cerr << sformat(_("Free space error (%s)."), e.what()) << endl; - exit(EXIT_FAILURE); } - catch (const Exception& e) + catch (const OptionsException& e) { SN_CAUGHT(e); - cerr << sformat(_("Error (%s)."), e.what()) << endl; + cerr << e.what() << endl; exit(EXIT_FAILURE); } diff --git a/doc/snapper.xml.in b/doc/snapper.xml.in index 3e42ac08..bb7922c9 100644 --- a/doc/snapper.xml.in +++ b/doc/snapper.xml.in @@ -2,13 +2,13 @@ - 2019-10-14 + 2020-06-15 snapper 8 - 2019-10-14 + 2020-06-15 @VERSION@ Filesystem Snapshot Management @@ -270,6 +270,13 @@ Operate on target root. Only works together with no-dbus and only for some commands. + + + + Operate in the specified ambit. Can be used to override the ambit detection. + Allowed ambits are auto, classic and transactional. + + @@ -738,6 +745,9 @@ The rollback command also sets the description, the cleanup algorithm and some userdata unless the values are specified on the command line. This will automate cleanup of snapshots created by rollbacks. + In other ambits than classic the rollback command does what is required + to do a rollback. Anyway it is recommended to use specific programs in that + case. diff --git a/package/snapper.changes b/package/snapper.changes index 8b39b00c..7b989949 100644 --- a/package/snapper.changes +++ b/package/snapper.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Jun 16 18:31:47 CEST 2020 - aschnell@suse.com + +- special rollback for transactional server (bsc#1172273) +- version 0.8.10 + ------------------------------------------------------------------- Mon Apr 06 16:22:29 CEST 2020 - aschnell@suse.com diff --git a/snapper/Enum.h b/snapper/Enum.h index 7928b405..519f4a42 100644 --- a/snapper/Enum.h +++ b/snapper/Enum.h @@ -63,7 +63,7 @@ namespace snapper if ((size_t)(value) >= names.size()) throw OutOfRangeException(); - return names[value]; + return names[(size_t)(value)]; }