From: Arvin Schnell Date: Fri, 27 Apr 2012 10:08:18 +0000 (+0200) Subject: - work on dbus interface X-Git-Tag: v0.1.3~234 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2a3349fd91f1ccaf6081e85ecb0ec5bb112b42d6;p=thirdparty%2Fsnapper.git - work on dbus interface --- diff --git a/client/Makefile.am b/client/Makefile.am index 8341a6f9..1ea75e60 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -2,6 +2,8 @@ # Makefile.am for snapper/tools/client # +SUBDIRS = utils + INCLUDES = -I$(top_srcdir) -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include @@ -12,5 +14,5 @@ snapper_SOURCES = \ types.cc types.h \ commands.cc commands.h -snapper_LDADD = ../snapper/libsnapper.la ../tools/utils/libutils.la ../dbus/libdbus.la -ldbus-1 +snapper_LDADD = ../snapper/libsnapper.la utils/libutils.la ../dbus/libdbus.la -ldbus-1 diff --git a/client/commands.cc b/client/commands.cc index e1a688ff..d08836a4 100644 --- a/client/commands.cc +++ b/client/commands.cc @@ -67,22 +67,120 @@ command_list_xsnapshots(DBus::Connection& conn, const string& config_name) unsigned int -command_create_xsnapshot(DBus::Connection& conn, const string& config_name, XSnapshotType type, - unsigned int prenum, const string& description, const string& cleanup, - const map& userdata) +command_create_single_xsnapshot(DBus::Connection& conn, const string& config_name, + const string& description, const string& cleanup, + const map& userdata) { DBus::MessageMethodCall call("org.opensuse.snapper", "/org/opensuse/snapper", - "org.opensuse.snapper", "CreateSnapshot"); + "org.opensuse.snapper", "CreateSingleSnapshot"); DBus::Hoho hoho(call); - hoho << config_name << type << prenum << description << cleanup << userdata; + hoho << config_name << description << cleanup << userdata; DBus::Message reply = conn.send_and_reply_and_block(call); unsigned int number; - + + DBus::Hihi hihi(reply); + hihi >> number; + + return number; +} + + +unsigned int +command_create_pre_xsnapshot(DBus::Connection& conn, const string& config_name, + const string& description, const string& cleanup, + const map& userdata) +{ + DBus::MessageMethodCall call("org.opensuse.snapper", "/org/opensuse/snapper", + "org.opensuse.snapper", "CreatePreSnapshot"); + + DBus::Hoho hoho(call); + hoho << config_name << description << cleanup << userdata; + + DBus::Message reply = conn.send_and_reply_and_block(call); + + unsigned int number; + + DBus::Hihi hihi(reply); + hihi >> number; + + return number; +} + + +unsigned int +command_create_post_xsnapshot(DBus::Connection& conn, const string& config_name, + unsigned int prenum, const string& description, + const string& cleanup, const map& userdata) +{ + DBus::MessageMethodCall call("org.opensuse.snapper", "/org/opensuse/snapper", + "org.opensuse.snapper", "CreatePostSnapshot"); + + DBus::Hoho hoho(call); + hoho << config_name << prenum << description << cleanup << userdata; + + DBus::Message reply = conn.send_and_reply_and_block(call); + + unsigned int number; + DBus::Hihi hihi(reply); hihi >> number; return number; } + + +void +command_create_xcomparison(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2) +{ + DBus::MessageMethodCall call("org.opensuse.snapper", "/org/opensuse/snapper", + "org.opensuse.snapper", "CreateComparison"); + + DBus::Hoho hoho(call); + hoho << config_name << number1 << number2; + + DBus::Message reply = conn.send_and_reply_and_block(call); +} + + +list +command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2) +{ + DBus::MessageMethodCall call("org.opensuse.snapper", "/org/opensuse/snapper", + "org.opensuse.snapper", "GetFiles"); + + DBus::Hoho hoho(call); + hoho << config_name << number1 << number2; + + DBus::Message reply = conn.send_and_reply_and_block(call); + + DBus::Hihi hihi(reply); + list files; + hihi >> files; + + return files; +} + + +vector +command_get_xdiff(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2, const string& filename, const string& options) +{ + DBus::MessageMethodCall call("org.opensuse.snapper", "/org/opensuse/snapper", + "org.opensuse.snapper", "GetDiff"); + + DBus::Hoho hoho(call); + hoho << config_name << number1 << number2 << filename << options; + + DBus::Message reply = conn.send_and_reply_and_block(call); + + DBus::Hihi hihi(reply); + vector files; + hihi >> files; + + return files; +} diff --git a/client/commands.h b/client/commands.h index dbb16cc8..43d4a372 100644 --- a/client/commands.h +++ b/client/commands.h @@ -27,10 +27,12 @@ #include #include +#include #include #include using std::string; +using std::vector; using std::list; using std::map; @@ -44,7 +46,29 @@ list command_list_xsnapshots(DBus::Connection& conn, const string& config_name); unsigned int -command_create_xsnapshot(DBus::Connection& conn, const string& config_name, XSnapshotType type, - unsigned int prenum, const string& description, const string& cleanup, - const map& userdata); +command_create_single_xsnapshot(DBus::Connection& conn, const string& config_name, + const string& description, const string& cleanup, + const map& userdata); + +unsigned int +command_create_pre_xsnapshot(DBus::Connection& conn, const string& config_name, + const string& description, const string& cleanup, + const map& userdata); + +unsigned int +command_create_post_xsnapshot(DBus::Connection& conn, const string& config_name, + unsigned int prenum, const string& description, + const string& cleanup, const map& userdata); + +void +command_create_xcomparison(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2); + +list +command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2); + +vector +command_get_xdiff(DBus::Connection& conn, const string& config_name, unsigned int number1, + unsigned int number2, const string& filename, const string& options); diff --git a/client/snapper.cc b/client/snapper.cc index a50e5cf4..c15b02e8 100644 --- a/client/snapper.cc +++ b/client/snapper.cc @@ -28,19 +28,14 @@ #include #include "config.h" -#include #include -#include -#include -#include #include #include -#include #include #include -#include "tools/utils/Table.h" -#include "tools/utils/GetOpts.h" +#include "utils/Table.h" +#include "utils/GetOpts.h" #include "commands.h" @@ -58,14 +53,10 @@ bool verbose = false; string config_name = "root"; bool disable_filters = false; -Snapper* sh = NULL; - -Snapshots::iterator +unsigned int read_num(const string& str) { - Snapshots& snapshots = sh->getSnapshots(); - istringstream s(str); unsigned int num = 0; s >> num; @@ -76,18 +67,11 @@ read_num(const string& str) 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; + return num; } -pair +pair read_nums(const string& str) { string::size_type pos = str.find(".."); @@ -97,16 +81,16 @@ read_nums(const string& str) exit(EXIT_FAILURE); } - Snapshots::iterator snap1 = read_num(str.substr(0, pos)); - Snapshots::iterator snap2 = read_num(str.substr(pos + 2)); + unsigned int num1 = read_num(str.substr(0, pos)); + unsigned int num2 = read_num(str.substr(pos + 2)); - if (snap1 == snap2) + if (num1 == num2) { cerr << _("Identical snapshots.") << endl; exit(EXIT_FAILURE); } - return pair(snap1, snap2); + return pair(num1, num2); } @@ -228,7 +212,7 @@ help_create_config() void -command_create_config() +command_create_config(DBus::Connection& conn) { const struct option options[] = { { "fstype", required_argument, 0, 'f' }, @@ -289,7 +273,7 @@ help_delete_config() void -command_delete_config() +command_delete_config(DBus::Connection& conn) { getopts.parse("delete-config", GetOpts::no_options); if (getopts.hasArgs()) @@ -323,7 +307,7 @@ help_list() void -command_list() +command_list(DBus::Connection& conn) { const struct option options[] = { { "type", required_argument, 0, 't' }, @@ -373,17 +357,17 @@ command_list() header.add(_("Userdata")); table.setHeader(header); - const Snapshots& snapshots = sh->getSnapshots(); - for (Snapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) + list snapshots = command_list_xsnapshots(conn, config_name); + for (list::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(), false, false)); - row.add(it1->getCleanup()); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); + row.add(/*toString(*/ decString((int)(it1->type))); + row.add(decString(it1->num)); + row.add(it1->type == XPOST ? decString(it1->pre_num) : ""); + row.add(it1->num == 0 ? "" : datetime(it1->date, false, false)); + row.add(it1->cleanup); + row.add(it1->description); + row.add(show_userdata(it1->userdata)); table.add(row); } } @@ -398,17 +382,17 @@ command_list() header.add(_("Userdata")); table.setHeader(header); - const Snapshots& snapshots = sh->getSnapshots(); - for (Snapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) + list snapshots = command_list_xsnapshots(conn, config_name); + for (list::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) { - // if (it1->getType() != SINGLE) - // continue; + if (it1->type != XSINGLE) + continue; TableRow row; - row.add(decString(it1->getNum())); - row.add(it1->isCurrent() ? "" : datetime(it1->getDate(), false, false)); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); + row.add(decString(it1->num)); + row.add(it1->num == 0 ? "" : datetime(it1->date, false, false)); + row.add(it1->description); + row.add(show_userdata(it1->userdata)); table.add(row); } } @@ -425,23 +409,26 @@ command_list() header.add(_("Userdata")); table.setHeader(header); - const Snapshots& snapshots = sh->getSnapshots(); - for (Snapshots::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) + list snapshots = command_list_xsnapshots(conn, config_name); + for (list::const_iterator it1 = snapshots.begin(); it1 != snapshots.end(); ++it1) { - // if (it1->getType() != PRE) - // continue; + if (it1->type != XPRE) + continue; + list::const_iterator it2; + /* 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(), false, false)); - row.add(datetime(it2->getDate(), false, false)); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); + row.add(decString(it1->num)); + row.add(decString(it2->num)); + row.add(datetime(it1->date, false, false)); + row.add(datetime(it2->date, false, false)); + row.add(it1->description); + row.add(show_userdata(it1->userdata)); table.add(row); } } @@ -471,7 +458,7 @@ help_create() void -command_create() +command_create(DBus::Connection& conn) { const struct option options[] = { { "type", required_argument, 0, 't' }, @@ -493,10 +480,8 @@ command_create() enum CreateType { CT_SINGLE, CT_PRE, CT_POST, CT_PRE_POST }; - const Snapshots& snapshots = sh->getSnapshots(); - CreateType type = CT_SINGLE; - Snapshots::const_iterator snap1 = snapshots.end(); + unsigned int num1 = 0; bool print_number = false; string description; string cleanup; @@ -523,7 +508,7 @@ command_create() } if ((opt = opts.find("pre-number")) != opts.end()) - snap1 = read_num(opt->second); + num1 = read_num(opt->second); if ((opt = opts.find("print-number")) != opts.end()) print_number = true; @@ -543,7 +528,7 @@ command_create() type = CT_PRE_POST; } - if (type == CT_POST && (snap1 == snapshots.end() || snap1->isCurrent())) + if (type == CT_POST && (num1 == 0)) { cerr << _("Missing or invalid pre-number.") << endl; exit(EXIT_FAILURE); @@ -560,48 +545,34 @@ command_create() switch (type) { case CT_SINGLE: { - Snapshots::iterator snap1 = sh->createSingleSnapshot(description); - snap1->setCleanup(cleanup); - snap1->setUserdata(userdata); - snap1->flushInfo(); + unsigned int num1 = command_create_single_xsnapshot(conn, config_name, description, + cleanup, userdata); if (print_number) - cout << snap1->getNum() << endl; + cout << num1 << endl; } break; case CT_PRE: { - Snapshots::iterator snap1 = sh->createPreSnapshot(description); - snap1->setCleanup(cleanup); - snap1->setUserdata(userdata); - snap1->flushInfo(); + unsigned int num1 = command_create_pre_xsnapshot(conn, config_name, description, + cleanup, userdata); if (print_number) - cout << snap1->getNum() << endl; + cout << num1 << endl; } break; case CT_POST: { - Snapshots::iterator snap2 = sh->createPostSnapshot(description, snap1); - snap2->setCleanup(cleanup); - snap2->setUserdata(userdata); - snap2->flushInfo(); + unsigned int num2 = command_create_post_xsnapshot(conn, config_name, num1, description, + cleanup, userdata); if (print_number) - cout << snap2->getNum() << endl; - sh->startBackgroundComparsion(snap1, snap2); + cout << num2 << endl; } break; case CT_PRE_POST: { - Snapshots::iterator snap1 = sh->createPreSnapshot(description); - snap1->setCleanup(cleanup); - snap1->setUserdata(userdata); - snap1->flushInfo(); - + unsigned int num1 = command_create_pre_xsnapshot(conn, config_name, description, + cleanup, userdata); system(command.c_str()); - - Snapshots::iterator snap2 = sh->createPostSnapshot("", snap1); - snap2->setCleanup(cleanup); - snap2->setUserdata(userdata); - snap2->flushInfo(); + unsigned int num2 = command_create_post_xsnapshot(conn, config_name, num1, "", + cleanup, userdata); if (print_number) - cout << snap1->getNum() << ".." << snap2->getNum() << endl; - sh->startBackgroundComparsion(snap1, snap2); + cout << num1 << ".." << num2 << endl; } break; } } @@ -628,7 +599,7 @@ help_modify() void -command_modify() +command_modify(DBus::Connection& conn) { const struct option options[] = { { "description", required_argument, 0, 'd' }, @@ -649,7 +620,7 @@ command_modify() { while (getopts.hasArgs()) { - Snapshots::iterator snapshot = read_num(getopts.popArg()); + Snapshots::iterator snapshot; // = read_num(getopts.popArg()); GetOpts::parsed_opts::const_iterator opt; @@ -688,7 +659,7 @@ help_delete() void -command_delete() +command_delete(DBus::Connection& conn) { getopts.parse("delete", GetOpts::no_options); if (!getopts.hasArgs()) @@ -701,9 +672,9 @@ command_delete() { while (getopts.hasArgs()) { - Snapshots::iterator snapshot = read_num(getopts.popArg()); + Snapshots::iterator snapshot; // = read_num(getopts.popArg()); - sh->deleteSnapshot(snapshot); + // sh->deleteSnapshot(snapshot); } } catch (const IllegalSnapshotException& e) @@ -724,7 +695,7 @@ help_mount() void -command_mount() +command_mount(DBus::Connection& conn) { getopts.parse("mount", GetOpts::no_options); if (!getopts.hasArgs()) @@ -737,7 +708,7 @@ command_mount() { while (getopts.hasArgs()) { - Snapshots::iterator snapshot = read_num(getopts.popArg()); + Snapshots::iterator snapshot; // = read_num(getopts.popArg()); snapshot->mountFilesystemSnapshot(); } @@ -760,7 +731,7 @@ help_umount() void -command_umount() +command_umount(DBus::Connection& conn) { getopts.parse("mount", GetOpts::no_options); if (!getopts.hasArgs()) @@ -773,7 +744,7 @@ command_umount() { while (getopts.hasArgs()) { - Snapshots::iterator snapshot = read_num(getopts.popArg()); + Snapshots::iterator snapshot; // = read_num(getopts.popArg()); snapshot->umountFilesystemSnapshot(); } @@ -799,7 +770,7 @@ help_status() void -command_status() +command_status(DBus::Connection& conn) { const struct option options[] = { { "output", required_argument, 0, 'o' }, @@ -815,11 +786,11 @@ command_status() GetOpts::parsed_opts::const_iterator opt; - pair snaps(read_nums(getopts.popArg())); + pair snaps(read_nums(getopts.popArg())); - Comparison comparison(sh, snaps.first, snaps.second); + command_create_xcomparison(conn, config_name, snaps.first, snaps.second); - const Files& files = comparison.getFiles(); + list files = command_get_xfiles(conn, config_name, snaps.first, snaps.second); FILE* file = stdout; @@ -833,9 +804,8 @@ command_status() } } - for (Files::const_iterator it = files.begin(); it != files.end(); ++it) - fprintf(file, "%s %s\n", statusToString(it->getPreToPostStatus()).c_str(), - it->getAbsolutePath(LOC_SYSTEM).c_str()); + for (list::const_iterator it = files.begin(); it != files.end(); ++it) + fprintf(file, "%s %s\n", it->status.c_str(), it->filename.c_str()); // TODO abs filename if (file != stdout) fclose(file); @@ -852,25 +822,26 @@ help_diff() void -command_diff() +command_diff(DBus::Connection& conn) { GetOpts::parsed_opts opts = getopts.parse("diff", GetOpts::no_options); GetOpts::parsed_opts::const_iterator opt; - pair snaps(read_nums(getopts.popArg())); + pair snaps(read_nums(getopts.popArg())); - Comparison comparison(sh, snaps.first, snaps.second); + command_create_xcomparison(conn, config_name, snaps.first, snaps.second); - const Files& files = comparison.getFiles(); + list files = command_get_xfiles(conn, config_name, snaps.first, snaps.second); if (getopts.numArgs() == 0) { - for (Files::const_iterator it1 = files.begin(); it1 != files.end(); ++it1) + for (list::const_iterator it1 = files.begin(); it1 != files.end(); ++it1) { - vector lines = it1->getDiff("--unified --new-file"); + vector lines = command_get_xdiff(conn, config_name, snaps.first, snaps.second, + it1->filename, "--unified --new-file"); for (vector::const_iterator it2 = lines.begin(); it2 != lines.end(); ++it2) - cout << it2->c_str() << endl; + cout << it2->c_str() << endl; } } else @@ -879,6 +850,7 @@ command_diff() { string name = getopts.popArg(); + /* Files::const_iterator tmp = files.findAbsolutePath(name); if (tmp == files.end()) continue; @@ -886,6 +858,7 @@ command_diff() vector lines = tmp->getDiff("--unified --new-file"); for (vector::const_iterator it2 = lines.begin(); it2 != lines.end(); ++it2) cout << it2->c_str() << endl; + */ } } } @@ -904,7 +877,7 @@ help_undo() void -command_undo() +command_undo(DBus::Connection& conn) { const struct option options[] = { { "input", required_argument, 0, 'i' }, @@ -918,7 +891,7 @@ command_undo() exit(EXIT_FAILURE); } - pair snaps(read_nums(getopts.popArg())); + pair snaps(read_nums(getopts.popArg())); FILE* file = NULL; @@ -934,15 +907,15 @@ command_undo() } } - if (snaps.first->isCurrent()) + if (snaps.first == 0) { cerr << _("Invalid snapshots.") << endl; exit(EXIT_FAILURE); } - Comparison comparison(sh, snaps.first, snaps.second); + command_create_xcomparison(conn, config_name, snaps.first, snaps.second); - Files& files = comparison.getFiles(); + list files = command_get_xfiles(conn, config_name, snaps.first, snaps.second); if (file) { @@ -966,6 +939,7 @@ command_undo() name.erase(0, pos + 1); } + /* Files::iterator it = files.findAbsolutePath(name); if (it == files.end()) { @@ -974,14 +948,17 @@ command_undo() } it->setUndo(true); + */ } } else { if (getopts.numArgs() == 0) { + /* for (Files::iterator it = files.begin(); it != files.end(); ++it) it->setUndo(true); + */ } else { @@ -989,15 +966,17 @@ command_undo() { string name = getopts.popArg(); + /* Files::iterator tmp = files.findAbsolutePath(name); if (tmp == files.end()) continue; tmp->setUndo(true); + */ } } } - + /* UndoStatistic rs = comparison.getUndoStatistic(); if (rs.empty()) @@ -1010,6 +989,7 @@ command_undo() << endl; comparison.doUndo(); + */ } @@ -1023,7 +1003,7 @@ help_cleanup() void -command_cleanup() +command_cleanup(DBus::Connection& conn) { const struct option options[] = { { 0, 0, 0, 0 } @@ -1040,15 +1020,15 @@ command_cleanup() if (cleanup == "number") { - sh->doCleanupNumber(); + // sh->doCleanupNumber(); } else if (cleanup == "timeline") { - sh->doCleanupTimeline(); + // sh->doCleanupTimeline(); } else if (cleanup == "empty-pre-post") { - sh->doCleanupEmptyPrePost(); + // sh->doCleanupEmptyPrePost(); } else { @@ -1138,19 +1118,18 @@ main(int argc, char** argv) initDefaultLogger(); cmds["list-configs"] = command_list_configs; - // cmds["create-config"] = command_create_config; - // cmds["delete-config"] = command_delete_config; - // cmds["list"] = command_list; - // cmds["create"] = command_create; - // cmds["modify"] = command_modify; - // cmds["delete"] = command_delete; - // cmds["mount"] = command_mount; - // cmds["umount"] = command_umount; - // cmds["status"] = command_status; - // cmds["diff"] = command_diff; - // cmds["undochange"] = command_undo; - // cmds["cleanup"] = command_cleanup; - // cmds["help"] = command_help; + cmds["create-config"] = command_create_config; + cmds["delete-config"] = command_delete_config; + cmds["list"] = command_list; + cmds["create"] = command_create; + cmds["modify"] = command_modify; + cmds["delete"] = command_delete; + cmds["mount"] = command_mount; + cmds["umount"] = command_umount; + cmds["status"] = command_status; + cmds["diff"] = command_diff; + cmds["undochange"] = command_undo; + cmds["cleanup"] = command_cleanup; const struct option options[] = { { "quiet", no_argument, 0, 'q' }, @@ -1222,49 +1201,15 @@ main(int argc, char** argv) exit(EXIT_FAILURE); } - DBus::Connection conn(DBUS_BUS_SYSTEM); - - if (cmd->first == "help" || cmd->first == "list-configs" || - cmd->first == "create-config" || cmd->first == "delete-config") + if (cmd->first == "help") { - (*cmd->second)(conn); + command_help(); } else { - try - { - sh = createSnapper(config_name, disable_filters); - } - catch (const ConfigNotFoundException& e) - { - cerr << sformat(_("Config '%s' not found."), config_name.c_str()) << endl; - exit(EXIT_FAILURE); - } - catch (const InvalidConfigException& e) - { - cerr << sformat(_("Config '%s' is invalid."), config_name.c_str()) << endl; - exit(EXIT_FAILURE); - } + DBus::Connection conn(DBUS_BUS_SYSTEM); - if (!quiet) - { - sh->setCompareCallback(&compare_callback_impl); - sh->setUndoCallback(&undo_callback_impl); - } - - try - { - (*cmd->second)(conn); - } - catch (const SnapperException& e) - { - y2err("caught final exception"); - cerr << sformat(_("Command failed (%s). See log for more information."), - e.what()) << endl; - exit(EXIT_FAILURE); - } - - deleteSnapper(sh); + (*cmd->second)(conn); } exit(EXIT_SUCCESS); diff --git a/client/types.cc b/client/types.cc index 66f34408..2234db6f 100644 --- a/client/types.cc +++ b/client/types.cc @@ -32,7 +32,7 @@ namespace DBus { const char* TypeInfo::signature = "(ss)"; - const char* TypeInfo::signature = "(uqusa{ss})"; + const char* TypeInfo::signature = "(uquusa{ss})"; const char* TypeInfo::signature = "(ssb)"; const char* TypeInfo::signature = "(sb)"; @@ -61,7 +61,8 @@ namespace DBus operator>>(Hihi& hihi, XSnapshot& data) { hihi.open_recurse(); - hihi >> data.num >> data.type >> data.date >> data.description >> data.userdata; + hihi >> data.num >> data.type >> data.pre_num >> data.date >> data.description + >> data.userdata; hihi.close_recurse(); return hihi; } @@ -95,4 +96,3 @@ namespace DBus } } - diff --git a/client/types.h b/client/types.h index 92f2497f..9c821a2b 100644 --- a/client/types.h +++ b/client/types.h @@ -45,15 +45,17 @@ struct XConfigInfo }; -enum XSnapshotType { SINGLE, PRE, POST }; +enum XSnapshotType { XSINGLE, XPRE, XPOST }; struct XSnapshot { - unsigned int num; XSnapshotType type; - unsigned int date; + unsigned int num; + time_t date; + unsigned int pre_num; string description; + string cleanup; map userdata; }; diff --git a/tools/utils/.gitignore b/client/utils/.gitignore similarity index 100% rename from tools/utils/.gitignore rename to client/utils/.gitignore diff --git a/tools/utils/GetOpts.cc b/client/utils/GetOpts.cc similarity index 100% rename from tools/utils/GetOpts.cc rename to client/utils/GetOpts.cc diff --git a/tools/utils/GetOpts.h b/client/utils/GetOpts.h similarity index 100% rename from tools/utils/GetOpts.h rename to client/utils/GetOpts.h diff --git a/tools/utils/Makefile.am b/client/utils/Makefile.am similarity index 82% rename from tools/utils/Makefile.am rename to client/utils/Makefile.am index 96ab5075..2bba6317 100644 --- a/tools/utils/Makefile.am +++ b/client/utils/Makefile.am @@ -1,5 +1,5 @@ # -# Makefile.am for snapper/tools/utils +# Makefile.am for snapper/client/utils # INCLUDES = -I$(top_srcdir) diff --git a/tools/utils/Table.cc b/client/utils/Table.cc similarity index 100% rename from tools/utils/Table.cc rename to client/utils/Table.cc diff --git a/tools/utils/Table.h b/client/utils/Table.h similarity index 100% rename from tools/utils/Table.h rename to client/utils/Table.h diff --git a/tools/utils/console.cc b/client/utils/console.cc similarity index 100% rename from tools/utils/console.cc rename to client/utils/console.cc diff --git a/tools/utils/console.h b/client/utils/console.h similarity index 100% rename from tools/utils/console.h rename to client/utils/console.h diff --git a/tools/utils/text.cc b/client/utils/text.cc similarity index 100% rename from tools/utils/text.cc rename to client/utils/text.cc diff --git a/tools/utils/text.h b/client/utils/text.h similarity index 100% rename from tools/utils/text.h rename to client/utils/text.h diff --git a/configure.in b/configure.in index e997df6f..cb1f6263 100644 --- a/configure.in +++ b/configure.in @@ -54,10 +54,10 @@ AC_OUTPUT( bindings/Makefile bindings/python/Makefile tools/Makefile - tools/utils/Makefile dbus/Makefile server/Makefile client/Makefile + client/utils/Makefile scripts/Makefile data/Makefile doc/Makefile diff --git a/dbus/DBusConnection.cc b/dbus/DBusConnection.cc index ed860fed..bcf4359a 100644 --- a/dbus/DBusConnection.cc +++ b/dbus/DBusConnection.cc @@ -20,6 +20,7 @@ */ +#include #include #include #include diff --git a/examples/python/create.py b/examples/python/create.py index 9360dfc0..36505950 100755 --- a/examples/python/create.py +++ b/examples/python/create.py @@ -8,5 +8,5 @@ snapper = dbus.Interface(bus.get_object('org.opensuse.snapper', '/org/opensuse/s dbus_interface='org.opensuse.snapper') -print snapper.CreateSnapshot("root", 0, 0, "test", "", { "tid" : "456" }) +print snapper.CreateSingleSnapshot("root", "test", "", { "id" : "123" }) diff --git a/examples/python/list.py b/examples/python/list.py index 71d9b127..eab9f54b 100755 --- a/examples/python/list.py +++ b/examples/python/list.py @@ -11,8 +11,8 @@ snapper = dbus.Interface(bus.get_object('org.opensuse.snapper', '/org/opensuse/s snapshots = snapper.ListSnapshots("root") for snapshot in snapshots: - print snapshot[0], snapshot[1], snapshot[2], snapshot[3], - for k, v in snapshot[4].items(): + print snapshot[0], snapshot[1], snapshot[2], snapshot[3], snapshot[4], + for k, v in snapshot[5].items(): print "%s=%s" % (k, v), print diff --git a/scripts/zypp-plugin.py b/scripts/zypp-plugin.py index 19d7a5da..a663bfe6 100755 --- a/scripts/zypp-plugin.py +++ b/scripts/zypp-plugin.py @@ -2,7 +2,7 @@ from os import readlink, getppid from os.path import basename -from subprocess import Popen, PIPE +from dbus import SystemBus, Interface from zypp_plugin import Plugin class MyPlugin(Plugin): @@ -11,19 +11,20 @@ class MyPlugin(Plugin): exe = basename(readlink("/proc/%d/exe" % getppid())) - args = ["snapper", "create", "--type=pre", "--print-number", - "--cleanup-algorithm=number", "--description=zypp(%s)" % exe] - self.o = Popen(args, stdout=PIPE).communicate()[0].strip() + num1 = snapper.CreatePreSnapshot("root", "zypp(%s)" % exe, "number") self.ack() def PLUGINEND(self, headers, body): - args = ["snapper", "create", "--type=post", "--pre-number=%s" % self.o, - "--cleanup-algorithm=number"] - Popen(args) + num2 = snapper.CreatePostSnapshot("root", num1, "", "number") self.ack() +bus = SystemBus() + +snapper = Interface(get_object('org.opensuse.snapper', '/org/opensuse/snapper'), + dbus_interface='org.opensuse.snapper') + plugin = MyPlugin() plugin.main() diff --git a/server/Client.cc b/server/Client.cc index 8cd2e252..2ec50d81 100644 --- a/server/Client.cc +++ b/server/Client.cc @@ -57,7 +57,7 @@ Client::find_comparison(Snapper* snapper, Snapshots::const_iterator snapshot1, return *it; } - return NULL; + throw NoComparison(); } diff --git a/server/Client.h b/server/Client.h index 73e904a2..b1ba3dfb 100644 --- a/server/Client.h +++ b/server/Client.h @@ -38,6 +38,13 @@ using namespace std; using namespace snapper; +struct NoComparison : public std::exception +{ + explicit NoComparison() throw() {} + virtual const char* what() const throw() { return "no comparison"; } +}; + + class Client { public: diff --git a/server/Types.cc b/server/Types.cc index 798b4e6c..e5be7bfe 100644 --- a/server/Types.cc +++ b/server/Types.cc @@ -26,7 +26,7 @@ namespace DBus { const char* TypeInfo::signature = "(ss)"; - const char* TypeInfo::signature = "(uqusa{ss})"; + const char* TypeInfo::signature = "(uquusa{ss})"; const char* TypeInfo::signature = "(ssb)"; const char* TypeInfo::signature = "(sb)"; @@ -63,7 +63,7 @@ namespace DBus operator<<(Hoho& hoho, const Snapshot& data) { hoho.open_struct(); - hoho << data.getNum() << data.getType() << data.getDate() + hoho << data.getNum() << data.getType() << data.getPreNum() << data.getDate() << data.getDescription() << data.getUserdata(); hoho.close_struct(); return hoho; diff --git a/server/snapperd.cc b/server/snapperd.cc index 6db57da7..36042ac6 100644 --- a/server/snapperd.cc +++ b/server/snapperd.cc @@ -27,7 +27,6 @@ #include #include -#include #include #include @@ -92,9 +91,24 @@ reply_to_introspect(DBus::Connection& conn, DBus::Message& msg) " \n" " \n" - " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + + " \n" " \n" - " \n" " \n" " \n" " \n" @@ -218,8 +232,6 @@ void send_signal_config_created(DBus::Connection& conn, const string& config_name, const string& subvolume) { - cout << "sending signal ConfigCreated" << endl; - DBus::MessageSignal msg("/org/opensuse/snapper", "org.opensuse.snapper", "ConfigCreated"); DBus::Hoho hoho(msg); @@ -231,14 +243,12 @@ send_signal_config_created(DBus::Connection& conn, const string& config_name, void send_signal_snapshot_created(DBus::Connection& conn, const string& config_name, - unsigned int number) + unsigned int num) { - cout << "sending signal SnapshotCreated" << endl; - DBus::MessageSignal msg("/org/opensuse/snapper", "org.opensuse.snapper", "SnapshotCreated"); DBus::Hoho hoho(msg); - hoho << config_name << number; + hoho << config_name << num; conn.send(msg); } @@ -246,14 +256,12 @@ send_signal_snapshot_created(DBus::Connection& conn, const string& config_name, void send_signal_snapshot_deleted(DBus::Connection& conn, const string& config_name, - unsigned int number) + unsigned int num) { - cout << "sending signal SnapshotDeleted" << endl; - DBus::MessageSignal msg("/org/opensuse/snapper", "org.opensuse.snapper", "SnapshotDeleted"); DBus::Hoho hoho(msg); - hoho << config_name << number; + hoho << config_name << num; conn.send(msg); } @@ -262,8 +270,6 @@ send_signal_snapshot_deleted(DBus::Connection& conn, const string& config_name, void reply_to_command_list_configs(DBus::Connection& conn, DBus::Message& msg) { - cout << "command ListConfigs" << endl; - list config_infos = Snapper::getConfigs(); DBus::MessageMethodReturn reply(msg); @@ -278,16 +284,16 @@ reply_to_command_list_configs(DBus::Connection& conn, DBus::Message& msg) void reply_to_command_create_config(DBus::Connection& conn, DBus::Message& msg) { - cout << "command CreateConfigs" << endl; - - check_permission(conn, msg); - string config_name; string subvolume; DBus::Hihi hihi(msg); hihi >> config_name >> subvolume; + y2mil("ListSnapshots config_name:" << config_name << " subvolume:" << subvolume); + + check_permission(conn, msg); + DBus::MessageMethodReturn reply(msg); conn.send(reply); @@ -299,14 +305,12 @@ reply_to_command_create_config(DBus::Connection& conn, DBus::Message& msg) void reply_to_command_lock_config(DBus::Connection& conn, DBus::Message& msg) { - cout << "command LockConfig" << endl; - string config_name; DBus::Hihi hihi(msg); hihi >> config_name; - cout << "Method called with " << config_name << endl; + y2mil("LockConfig config_name:" << config_name); check_permission(conn, msg, config_name); @@ -323,14 +327,12 @@ reply_to_command_lock_config(DBus::Connection& conn, DBus::Message& msg) void reply_to_command_unlock_config(DBus::Connection& conn, DBus::Message& msg) { - cout << "command UnlockConfig" << endl; - string config_name; DBus::Hihi hihi(msg); hihi >> config_name; - cout << "Method called with " << config_name << endl; + y2mil("UnlockConfig config_name:" << config_name); check_permission(conn, msg, config_name); @@ -347,14 +349,12 @@ reply_to_command_unlock_config(DBus::Connection& conn, DBus::Message& msg) void reply_to_command_list_snapshots(DBus::Connection& conn, DBus::Message& msg) { - cout << "command ListSnapshots" << endl; - string config_name; DBus::Hihi hihi(msg); hihi >> config_name; - cout << "Method called with " << config_name << endl; + y2mil("ListSnapshots config_name:" << config_name); check_permission(conn, msg, config_name); @@ -370,21 +370,18 @@ reply_to_command_list_snapshots(DBus::Connection& conn, DBus::Message& msg) void -reply_to_command_create_snapshot(DBus::Connection& conn, DBus::Message& msg) +reply_to_command_create_single_snapshot(DBus::Connection& conn, DBus::Message& msg) { - cout << "command CreateSnapshots" << endl; - string config_name; - SnapshotType type; - unsigned int prenum; string description; string cleanup; map userdata; DBus::Hihi hihi(msg); - hihi >> config_name >> type >> prenum >> description >> cleanup >> userdata; + hihi >> config_name >> description >> cleanup >> userdata; - cout << "Method called with " << config_name << endl; + y2mil("CreateSingleSnapshot config_name:" << config_name << " description:" << description << + " cleanup:" << cleanup); check_permission(conn, msg, config_name); @@ -392,7 +389,6 @@ reply_to_command_create_snapshot(DBus::Connection& conn, DBus::Message& msg) Snapper* snapper = getSnapper(config_name); - // TODO type Snapshots::iterator snap1 = snapper->createSingleSnapshot(description); snap1->setCleanup(cleanup); snap1->setUserdata(userdata); @@ -408,17 +404,95 @@ reply_to_command_create_snapshot(DBus::Connection& conn, DBus::Message& msg) void -reply_to_command_delete_snapshot(DBus::Connection& conn, DBus::Message& msg) +reply_to_command_create_pre_snapshot(DBus::Connection& conn, DBus::Message& msg) { - cout << "command DeleteSnapshots" << endl; + string config_name; + string description; + string cleanup; + map userdata; + + DBus::Hihi hihi(msg); + hihi >> config_name >> description >> cleanup >> userdata; + + y2mil("CreatePreSnapshot config_name:" << config_name << " description:" << description << + " cleanup:" << cleanup); + + check_permission(conn, msg, config_name); + + DBus::MessageMethodReturn reply(msg); + + Snapper* snapper = getSnapper(config_name); + + Snapshots::iterator snap1 = snapper->createPreSnapshot(description); + snap1->setCleanup(cleanup); + snap1->setUserdata(userdata); + snap1->flushInfo(); + + DBus::Hoho hoho(reply); + hoho << snap1->getNum(); + + conn.send(reply); + + send_signal_snapshot_created(conn, config_name, snap1->getNum()); +} + +void +reply_to_command_create_post_snapshot(DBus::Connection& conn, DBus::Message& msg) +{ string config_name; - unsigned int number; + unsigned int pre_num; + string description; + string cleanup; + map userdata; + + DBus::Hihi hihi(msg); + hihi >> config_name >> pre_num >> description >> cleanup >> userdata; + + y2mil("CreatePostSnapshot config_name:" << config_name << " pre_num:" << pre_num << + " description:" << description << " cleanup:" << cleanup); + + check_permission(conn, msg, config_name); + + DBus::MessageMethodReturn reply(msg); + + Snapper* snapper = getSnapper(config_name); + + Snapshots& snapshots = snapper->getSnapshots(); + + Snapshots::iterator snap1 = snapshots.find(pre_num); + if (snap1 == snapshots.end()) + { + DBus::MessageError reply(msg, "error.invalid", DBUS_ERROR_FAILED); + conn.send(reply); + return; + } + + Snapshots::iterator snap2 = snapper->createPostSnapshot(description, snap1); + snap2->setCleanup(cleanup); + snap2->setUserdata(userdata); + snap2->flushInfo(); + + DBus::Hoho hoho(reply); + hoho << snap2->getNum(); + + conn.send(reply); + + send_signal_snapshot_created(conn, config_name, snap2->getNum()); +} + + + +void +reply_to_command_delete_snapshot(DBus::Connection& conn, DBus::Message& msg) +{ + string config_name; + unsigned int num; DBus::Hihi hihi(msg); - hihi >> config_name >> number; + hihi >> config_name >> num; - cout << "Method called with " << config_name << endl; + y2mil("DeleteSnapshot config_name:" << config_name << " num:" << num); check_permission(conn, msg, config_name); check_lock(conn, msg, config_name); @@ -431,7 +505,7 @@ reply_to_command_delete_snapshot(DBus::Connection& conn, DBus::Message& msg) conn.send(reply); - send_signal_snapshot_deleted(conn, config_name, number); + send_signal_snapshot_deleted(conn, config_name, num); } @@ -454,22 +528,21 @@ protected: void reply_to_command_create_comparison(DBus::Connection& conn, DBus::Message& msg) { - cout << "command CreateComparison" << endl; - string config_name; - dbus_uint32_t number1, number2; + dbus_uint32_t num1, num2; DBus::Hihi hihi(msg); - hihi >> config_name >> number1 >> number2; + hihi >> config_name >> num1 >> num2; - cout << "Method called with " << config_name << " " << number1 << " " << number2 << endl; + y2mil("CreateComparison config_name:" << config_name << " num1:" << num1 << + " num2:" << num2); check_permission(conn, msg, config_name); Snapper* snapper = getSnapper(config_name); Snapshots& snapshots = snapper->getSnapshots(); - Snapshots::const_iterator snapshot1 = snapshots.find(number1); - Snapshots::const_iterator snapshot2 = snapshots.find(number2); + Snapshots::const_iterator snapshot1 = snapshots.find(num1); + Snapshots::const_iterator snapshot2 = snapshots.find(num2); Comparison* comparison = new Comparison(snapper, snapshot1, snapshot2, true); // TODO try, catch @@ -501,15 +574,7 @@ Comparing::operator()() void Comparing::done() { - const Files& files = comparison->getFiles(); - cout << comparison->getFiles().size() << endl; - - for (Files::const_iterator it = files.begin(); it != files.end(); ++it) - cout << statusToString(it->getPreToPostStatus()) << " " - << it->getAbsolutePath(LOC_SYSTEM) << endl; - DBus::Hoho hoho(*reply); - hoho << (dbus_uint32_t) comparison->getFiles().size(); conn->send(*reply); delete reply; @@ -519,15 +584,14 @@ Comparing::done() void reply_to_command_get_files(DBus::Connection& conn, DBus::Message& msg) { - cout << "command GetFiles" << endl; - string config_name; - dbus_uint32_t number1, number2; + dbus_uint32_t num1, num2; DBus::Hihi hihi(msg); - hihi >> config_name >> number1 >> number2; + hihi >> config_name >> num1 >> num2; - cout << "Method called with " << config_name << " " << number1 << " " << number2 << endl; + y2mil("GetFiles config_name:" << config_name << " num1:" << num1 << " num2:" << + num2); check_permission(conn, msg, config_name); @@ -538,13 +602,8 @@ reply_to_command_get_files(DBus::Connection& conn, DBus::Message& msg) Clients::iterator it = clients.find(sender); assert(it != clients.end()); - Comparison* comparison = it->find_comparison(config_name, number1, number2); - - if (!comparison || !comparison->isInitialized()) - { - // error - } - + Comparison* comparison = it->find_comparison(config_name, num1, num2); + const Files& files = comparison->getFiles(); DBus::Hoho hoho(reply); @@ -557,18 +616,17 @@ reply_to_command_get_files(DBus::Connection& conn, DBus::Message& msg) void reply_to_command_set_undo(DBus::Connection& conn, DBus::Message& msg) { - cout << "command SetUndo" << endl; - string config_name; - dbus_uint32_t number1, number2; + dbus_uint32_t num1, num2; list u; DBus::Hihi hihi(msg); - hihi >> config_name >> number1 >> number2 >> u; + hihi >> config_name >> num1 >> num2 >> u; check_permission(conn, msg, config_name); - cout << "Method called with " << config_name << " " << number1 << " " << number2 << endl; + y2mil("SetUndo config_name:" << config_name << " num1:" << num1 << " num2:" << + num2); string sender = msg.get_sender(); @@ -577,12 +635,7 @@ reply_to_command_set_undo(DBus::Connection& conn, DBus::Message& msg) Clients::iterator it = clients.find(sender); assert(it != clients.end()); - Comparison* comparison = it->find_comparison(config_name, number1, number2); - - if (!comparison || !comparison->isInitialized()) - { - // error - } + Comparison* comparison = it->find_comparison(config_name, num1, num2); Files& files = comparison->getFiles(); @@ -600,17 +653,16 @@ reply_to_command_set_undo(DBus::Connection& conn, DBus::Message& msg) void reply_to_command_get_diff(DBus::Connection& conn, DBus::Message& msg) { - cout << "command GetDiff" << endl; - string config_name; - dbus_uint32_t number1, number2; + dbus_uint32_t num1, num2; string filename; string options; DBus::Hihi hihi(msg); - hihi >> config_name >> number1 >> number2 >> filename >> options; + hihi >> config_name >> num1 >> num2 >> filename >> options; - cout << "Method called with " << config_name << " " << number1 << " " << number2 << endl; + y2mil("GetDiff config_name:" << config_name << " num1:" << num1 << " num2:" << + num2 << " filename:" << filename << " options:" << options); check_permission(conn, msg, config_name); @@ -619,12 +671,7 @@ reply_to_command_get_diff(DBus::Connection& conn, DBus::Message& msg) Clients::iterator it = clients.find(sender); assert(it != clients.end()); - Comparison* comparison = it->find_comparison(config_name, number1, number2); - - if (!comparison || !comparison->isInitialized()) - { - // error - } + Comparison* comparison = it->find_comparison(config_name, num1, num2); Files& files = comparison->getFiles(); @@ -644,8 +691,6 @@ reply_to_command_get_diff(DBus::Connection& conn, DBus::Message& msg) void reply_to_command_debug(DBus::Connection& conn, DBus::Message& msg) { - cout << "command Debug" << endl; - // check_permission(conn, msg); DBus::MessageMethodReturn reply(msg); @@ -721,8 +766,12 @@ dispatch(DBus::Connection& conn, DBus::Message& msg) reply_to_command_unlock_config(conn, msg); else if (msg.is_method_call("org.opensuse.snapper", "ListSnapshots")) reply_to_command_list_snapshots(conn, msg); - else if (msg.is_method_call("org.opensuse.snapper", "CreateSnapshot")) - reply_to_command_create_snapshot(conn, msg); + else if (msg.is_method_call("org.opensuse.snapper", "CreateSingleSnapshot")) + reply_to_command_create_single_snapshot(conn, msg); + else if (msg.is_method_call("org.opensuse.snapper", "CreatePreSnapshot")) + reply_to_command_create_pre_snapshot(conn, msg); + else if (msg.is_method_call("org.opensuse.snapper", "CreatePostSnapshot")) + reply_to_command_create_post_snapshot(conn, msg); else if (msg.is_method_call("org.opensuse.snapper", "DeleteSnapshot")) reply_to_command_delete_snapshot(conn, msg); else if (msg.is_method_call("org.opensuse.snapper", "CreateComparison")) @@ -734,19 +783,29 @@ dispatch(DBus::Connection& conn, DBus::Message& msg) else if (msg.is_method_call("org.opensuse.snapper", "GetDiff")) reply_to_command_get_diff(conn, msg); } - catch (DBus::MarshallingException) + catch (const DBus::MarshallingException& e) { DBus::MessageError reply(msg, "error.marshalling", DBUS_ERROR_FAILED); conn.send(reply); } - catch (Permissions) + catch (const Permissions& e) + { + DBus::MessageError reply(msg, "error.no_permissions", DBUS_ERROR_FAILED); + conn.send(reply); + } + catch (const Lock& e) + { + DBus::MessageError reply(msg, "error.config_locked", DBUS_ERROR_FAILED); + conn.send(reply); + } + catch (const NoComparison& e) { - DBus::MessageError reply(msg, "error.permissions", DBUS_ERROR_FAILED); + DBus::MessageError reply(msg, "error.no_comparisons", DBUS_ERROR_FAILED); conn.send(reply); } - catch (Lock) + catch (const IllegalSnapshotException& e) { - DBus::MessageError reply(msg, "error.locked", DBUS_ERROR_FAILED); + DBus::MessageError reply(msg, "error.illegal_snapshot", DBUS_ERROR_FAILED); conn.send(reply); } } diff --git a/tools/.gitignore b/tools/.gitignore index 31198865..bbbb2da8 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1,4 +1,2 @@ compare-dirs.o compare-dirs -snapper.o -snapper diff --git a/tools/Makefile.am b/tools/Makefile.am index 0db42e8e..3950e46b 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -2,8 +2,6 @@ # Makefile.am for snapper/tools # -SUBDIRS = utils - INCLUDES = -I$(top_srcdir) @@ -14,9 +12,3 @@ toolsbin_PROGRAMS = compare-dirs compare_dirs_SOURCES = compare-dirs.cc compare_dirs_LDADD = ../snapper/libsnapper.la - -bin_PROGRAMS = snapper - -snapper_SOURCES = snapper.cc -snapper_LDADD = ../snapper/libsnapper.la utils/libutils.la - diff --git a/tools/snapper.cc b/tools/snapper.cc deleted file mode 100644 index 47a275fc..00000000 --- a/tools/snapper.cc +++ /dev/null @@ -1,1267 +0,0 @@ -/* - * Copyright (c) 2011-2012 Novell, Inc. - * - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, contact Novell, Inc. - * - * To contact Novell about this file by physical or electronic mail, you may - * find current contact information at www.novell.com. - */ - - -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utils/Table.h" -#include "utils/GetOpts.h" - -using namespace snapper; -using namespace std; - - -typedef void (*cmd_fnc)(); -map cmds; - -GetOpts getopts; - -bool quiet = false; -bool verbose = false; -string config_name = "root"; -bool disable_filters = false; - -Snapper* sh = NULL; - - -Snapshots::iterator -read_num(const string& str) -{ - Snapshots& snapshots = sh->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; -} - - -pair -read_nums(const string& str) -{ - string::size_type pos = str.find(".."); - if (pos == string::npos) - { - cerr << _("Invalid snapshots.") << endl; - exit(EXIT_FAILURE); - } - - Snapshots::iterator snap1 = read_num(str.substr(0, pos)); - Snapshots::iterator snap2 = read_num(str.substr(pos + 2)); - - if (snap1 == snap2) - { - cerr << _("Identical snapshots.") << endl; - exit(EXIT_FAILURE); - } - - return pair(snap1, snap2); -} - - -map -read_userdata(const string& s, const map& old = map()) -{ - map userdata = old; - - list tmp; - boost::split(tmp, s, boost::is_any_of(","), boost::token_compress_on); - if (tmp.empty()) - { - cerr << _("Invalid userdata.") << endl; - exit(EXIT_FAILURE); - } - - for (list::const_iterator it = tmp.begin(); it != tmp.end(); ++it) - { - string::size_type pos = it->find("="); - if (pos == string::npos) - { - cerr << _("Invalid userdata.") << endl; - exit(EXIT_FAILURE); - } - - string key = boost::trim_copy(it->substr(0, pos)); - string value = boost::trim_copy(it->substr(pos + 1)); - - if (key.empty()) - { - cerr << _("Invalid userdata.") << endl; - exit(EXIT_FAILURE); - } - - if (value.empty()) - userdata.erase(key); - else - userdata[key] = value; - } - - return userdata; -} - - -string -show_userdata(const map& userdata) -{ - string s; - - for (map::const_iterator it = userdata.begin(); it != userdata.end(); ++it) - { - if (!s.empty()) - s += ", "; - s += it->first + "=" + it->second; - } - - return s; -} - - -void -help_list_configs() -{ - cout << _(" List configs:") << endl - << _("\tsnapper list-configs") << endl - << endl; -} - - -void -command_list_configs() -{ - getopts.parse("list-configs", GetOpts::no_options); - if (getopts.hasArgs()) - { - cerr << _("Command 'list-configs' does not take arguments.") << endl; - exit(EXIT_FAILURE); - } - - Table table; - - TableHeader header; - header.add(_("Config")); - header.add(_("Subvolume")); - table.setHeader(header); - - try - { - list config_infos = Snapper::getConfigs(); - for (list::const_iterator it = config_infos.begin(); it != config_infos.end(); ++it) - { - TableRow row; - row.add(it->config_name); - row.add(it->subvolume); - table.add(row); - } - } - catch (const ListConfigsFailedException& e) - { - cerr << sformat(_("Listing configs failed (%s)."), e.what()) << endl; - exit(EXIT_FAILURE); - } - - cout << table; -} - - -void -help_create_config() -{ - cout << _(" Create config:") << endl - << _("\tsnapper create-config ") << endl - << endl - << _(" Options for 'create-config' command:") << endl - << _("\t--fstype, -f \t\tManually set filesystem type.") << endl - << _("\t--template, -t \t\tName of config template to use.") << endl - << endl; -} - - -void -command_create_config() -{ - const struct option options[] = { - { "fstype", required_argument, 0, 'f' }, - { "template", required_argument, 0, 't' }, - { 0, 0, 0, 0 } - }; - - GetOpts::parsed_opts opts = getopts.parse("create-config", options); - if (getopts.numArgs() != 1) - { - cerr << _("Command 'create-config' needs one argument.") << endl; - exit(EXIT_FAILURE); - } - - string subvolume = realpath(getopts.popArg()); - if (subvolume.empty()) - { - cerr << _("Invalid subvolume.") << endl; - exit(EXIT_FAILURE); - } - - string fstype = ""; - string template_name = "default"; - - GetOpts::parsed_opts::const_iterator opt; - - if ((opt = opts.find("fstype")) != opts.end()) - fstype = opt->second; - - if ((opt = opts.find("template")) != opts.end()) - template_name = opt->second; - - if (fstype.empty() && !Snapper::detectFstype(subvolume, fstype)) - { - cerr << _("Detecting filesystem type failed.") << endl; - exit(EXIT_FAILURE); - } - - try - { - Snapper::createConfig(config_name, subvolume, fstype, template_name); - } - catch (const CreateConfigFailedException& e) - { - cerr << sformat(_("Creating config failed (%s)."), e.what()) << endl; - exit(EXIT_FAILURE); - } -} - - -void -help_delete_config() -{ - cout << _(" Delete config:") << endl - << _("\tsnapper delete-config") << endl - << endl; -} - - -void -command_delete_config() -{ - getopts.parse("delete-config", GetOpts::no_options); - if (getopts.hasArgs()) - { - cerr << _("Command 'delete-config' does not take arguments.") << endl; - exit(EXIT_FAILURE); - } - - try - { - Snapper::deleteConfig(config_name); - } - catch (const DeleteConfigFailedException& e) - { - cerr << sformat(_("Deleting config failed (%s)."), e.what()) << endl; - exit(EXIT_FAILURE); - } -} - - -void -help_list() -{ - cout << _(" List snapshots:") << endl - << _("\tsnapper list") << endl - << endl - << _(" Options for 'list' command:") << endl - << _("\t--type, -t \t\tType of snapshots to list.") << endl - << endl; -} - - -void -command_list() -{ - const struct option options[] = { - { "type", required_argument, 0, 't' }, - { 0, 0, 0, 0 } - }; - - GetOpts::parsed_opts opts = getopts.parse("list", options); - if (getopts.hasArgs()) - { - cerr << _("Command 'list' does not take arguments.") << endl; - exit(EXIT_FAILURE); - } - - enum ListMode { LM_ALL, LM_SINGLE, LM_PRE_POST }; - ListMode list_mode = LM_ALL; - - GetOpts::parsed_opts::const_iterator opt; - - if ((opt = opts.find("type")) != opts.end()) - { - if (opt->second == "all") - list_mode = LM_ALL; - else if (opt->second == "single") - list_mode = LM_SINGLE; - else if (opt->second == "pre-post") - list_mode = LM_PRE_POST; - else - { - cerr << _("Unknown type of snapshots.") << endl; - exit(EXIT_FAILURE); - } - } - - Table table; - - switch (list_mode) - { - case LM_ALL: - { - TableHeader header; - header.add(_("Type")); - header.add(_("#")); - header.add(_("Pre #")); - header.add(_("Date")); - header.add(_("Cleanup")); - header.add(_("Description")); - header.add(_("Userdata")); - table.setHeader(header); - - const Snapshots& snapshots = sh->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(), false, false)); - row.add(it1->getCleanup()); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); - table.add(row); - } - } - break; - - case LM_SINGLE: - { - TableHeader header; - header.add(_("#")); - header.add(_("Date")); - header.add(_("Description")); - header.add(_("Userdata")); - table.setHeader(header); - - const Snapshots& snapshots = sh->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(), false, false)); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); - table.add(row); - } - } - break; - - case LM_PRE_POST: - { - TableHeader header; - header.add(_("Pre #")); - header.add(_("Post #")); - header.add(_("Pre Date")); - header.add(_("Post Date")); - header.add(_("Description")); - header.add(_("Userdata")); - table.setHeader(header); - - const Snapshots& snapshots = sh->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(), false, false)); - row.add(datetime(it2->getDate(), false, false)); - row.add(it1->getDescription()); - row.add(show_userdata(it1->getUserdata())); - table.add(row); - } - } - break; - } - - cout << table; -} - - -void -help_create() -{ - cout << _(" Create snapshot:") << endl - << _("\tsnapper create") << endl - << endl - << _(" Options for 'create' command:") << endl - << _("\t--type, -t \t\tType for snapshot.") << endl - << _("\t--pre-number \t\tNumber of corresponding pre snapshot.") << endl - << _("\t--print-number, -p\t\tPrint number of created snapshot.") << endl - << _("\t--description, -d \tDescription for snapshot.") << endl - << _("\t--cleanup-algorithm, -c \tCleanup algorithm for snapshot.") << endl - << _("\t--userdata, -u \tUserdata for snapshot.") << endl - << _("\t--command \tRun command and create pre and post snapshots.") << endl - << endl; -} - - -void -command_create() -{ - const struct option options[] = { - { "type", required_argument, 0, 't' }, - { "pre-number", required_argument, 0, 0 }, - { "print-number", no_argument, 0, 'p' }, - { "description", required_argument, 0, 'd' }, - { "cleanup-algorithm", required_argument, 0, 'c' }, - { "userdata", required_argument, 0, 'u' }, - { "command", required_argument, 0, 0 }, - { 0, 0, 0, 0 } - }; - - GetOpts::parsed_opts opts = getopts.parse("create", options); - if (getopts.hasArgs()) - { - cerr << _("Command 'create' does not take arguments.") << endl; - exit(EXIT_FAILURE); - } - - enum CreateType { CT_SINGLE, CT_PRE, CT_POST, CT_PRE_POST }; - - const Snapshots& snapshots = sh->getSnapshots(); - - CreateType type = CT_SINGLE; - Snapshots::const_iterator snap1 = snapshots.end(); - bool print_number = false; - string description; - string cleanup; - map userdata; - string command; - - GetOpts::parsed_opts::const_iterator opt; - - if ((opt = opts.find("type")) != opts.end()) - { - if (opt->second == "single") - type = CT_SINGLE; - else if (opt->second == "pre") - type = CT_PRE; - else if (opt->second == "post") - type = CT_POST; - else if (opt->second == "pre-post") - type = CT_PRE_POST; - else - { - cerr << _("Unknown type of snapshot.") << endl; - exit(EXIT_FAILURE); - } - } - - if ((opt = opts.find("pre-number")) != opts.end()) - snap1 = read_num(opt->second); - - if ((opt = opts.find("print-number")) != opts.end()) - print_number = true; - - if ((opt = opts.find("description")) != opts.end()) - description = opt->second; - - if ((opt = opts.find("cleanup-algorithm")) != opts.end()) - cleanup = opt->second; - - if ((opt = opts.find("userdata")) != opts.end()) - userdata = read_userdata(opt->second); - - if ((opt = opts.find("command")) != opts.end()) - { - command = opt->second; - type = CT_PRE_POST; - } - - if (type == CT_POST && (snap1 == snapshots.end() || snap1->isCurrent())) - { - cerr << _("Missing or invalid pre-number.") << endl; - exit(EXIT_FAILURE); - } - - if (type == CT_PRE_POST && command.empty()) - { - cerr << _("Missing command argument.") << endl; - exit(EXIT_FAILURE); - } - - try - { - switch (type) - { - case CT_SINGLE: { - Snapshots::iterator snap1 = sh->createSingleSnapshot(description); - snap1->setCleanup(cleanup); - snap1->setUserdata(userdata); - snap1->flushInfo(); - if (print_number) - cout << snap1->getNum() << endl; - } break; - - case CT_PRE: { - Snapshots::iterator snap1 = sh->createPreSnapshot(description); - snap1->setCleanup(cleanup); - snap1->setUserdata(userdata); - snap1->flushInfo(); - if (print_number) - cout << snap1->getNum() << endl; - } break; - - case CT_POST: { - Snapshots::iterator snap2 = sh->createPostSnapshot(description, snap1); - snap2->setCleanup(cleanup); - snap2->setUserdata(userdata); - snap2->flushInfo(); - if (print_number) - cout << snap2->getNum() << endl; - sh->startBackgroundComparsion(snap1, snap2); - } break; - - case CT_PRE_POST: { - Snapshots::iterator snap1 = sh->createPreSnapshot(description); - snap1->setCleanup(cleanup); - snap1->setUserdata(userdata); - snap1->flushInfo(); - - system(command.c_str()); - - Snapshots::iterator snap2 = sh->createPostSnapshot("", snap1); - snap2->setCleanup(cleanup); - snap2->setUserdata(userdata); - snap2->flushInfo(); - if (print_number) - cout << snap1->getNum() << ".." << snap2->getNum() << endl; - sh->startBackgroundComparsion(snap1, snap2); - } break; - } - } - catch (const InvalidUserdataException& e) - { - cerr << _("Invalid userdata.") << endl; - exit(EXIT_FAILURE); - } -} - - -void -help_modify() -{ - cout << _(" Modify snapshot:") << endl - << _("\tsnapper modify ") << endl - << endl - << _(" Options for 'modify' command:") << endl - << _("\t--description, -d \tDescription for snapshot.") << endl - << _("\t--cleanup-algorithm, -c \tCleanup algorithm for snapshot.") << endl - << _("\t--userdata, -u \tUserdata for snapshot.") << endl - << endl; -} - - -void -command_modify() -{ - const struct option options[] = { - { "description", required_argument, 0, 'd' }, - { "cleanup-algorithm", required_argument, 0, 'c' }, - { "userdata", required_argument, 0, 'u' }, - { 0, 0, 0, 0 } - }; - - GetOpts::parsed_opts opts = getopts.parse("modify", options); - - if (!getopts.hasArgs()) - { - cerr << _("Command 'modify' needs at least one argument.") << endl; - exit(EXIT_FAILURE); - } - - try - { - while (getopts.hasArgs()) - { - Snapshots::iterator snapshot = read_num(getopts.popArg()); - - GetOpts::parsed_opts::const_iterator opt; - - if ((opt = opts.find("description")) != opts.end()) - snapshot->setDescription(opt->second); - - if ((opt = opts.find("cleanup-algorithm")) != opts.end()) - snapshot->setCleanup(opt->second); - - if ((opt = opts.find("userdata")) != opts.end()) - snapshot->setUserdata(read_userdata(opt->second, snapshot->getUserdata())); - - snapshot->flushInfo(); - } - } - catch (const IllegalSnapshotException& e) - { - cerr << _("Invalid snapshot.") << endl; - exit(EXIT_FAILURE); - } - catch (const InvalidUserdataException& e) - { - cerr << _("Invalid userdata.") << endl; - exit(EXIT_FAILURE); - } -} - - -void -help_delete() -{ - cout << _(" Delete snapshot:") << endl - << _("\tsnapper delete ") << endl - << endl; -} - - -void -command_delete() -{ - getopts.parse("delete", GetOpts::no_options); - if (!getopts.hasArgs()) - { - cerr << _("Command 'delete' needs at least one argument.") << endl; - exit(EXIT_FAILURE); - } - - try - { - while (getopts.hasArgs()) - { - Snapshots::iterator snapshot = read_num(getopts.popArg()); - - sh->deleteSnapshot(snapshot); - } - } - catch (const IllegalSnapshotException& e) - { - cerr << _("Invalid snapshot.") << endl; - exit(EXIT_FAILURE); - } -} - - -void -help_mount() -{ - cout << _(" Mount snapshot:") << endl - << _("\tsnapper mount ") << endl - << endl; -} - - -void -command_mount() -{ - getopts.parse("mount", GetOpts::no_options); - if (!getopts.hasArgs()) - { - cerr << _("Command 'mount' needs at least one argument.") << endl; - exit(EXIT_FAILURE); - } - - try - { - while (getopts.hasArgs()) - { - Snapshots::iterator snapshot = read_num(getopts.popArg()); - - snapshot->mountFilesystemSnapshot(); - } - } - catch (const IllegalSnapshotException& e) - { - cerr << _("Invalid snapshot.") << endl; - exit(EXIT_FAILURE); - } -} - - -void -help_umount() -{ - cout << _(" Umount snapshot:") << endl - << _("\tsnapper umount ") << endl - << endl; -} - - -void -command_umount() -{ - getopts.parse("mount", GetOpts::no_options); - if (!getopts.hasArgs()) - { - cerr << _("Command 'mount' needs at least one argument.") << endl; - exit(EXIT_FAILURE); - } - - try - { - while (getopts.hasArgs()) - { - Snapshots::iterator snapshot = read_num(getopts.popArg()); - - snapshot->umountFilesystemSnapshot(); - } - } - catch (const IllegalSnapshotException& e) - { - cerr << _("Invalid snapshot.") << endl; - exit(EXIT_FAILURE); - } -} - - -void -help_status() -{ - cout << _(" Comparing snapshots:") << endl - << _("\tsnapper status ..") << endl - << endl - << _(" Options for 'status' command:") << endl - << _("\t--output, -o \t\tSave status to file.") << endl - << endl; -} - - -void -command_status() -{ - const struct option options[] = { - { "output", required_argument, 0, 'o' }, - { 0, 0, 0, 0 } - }; - - GetOpts::parsed_opts opts = getopts.parse("status", options); - if (getopts.numArgs() != 1) - { - cerr << _("Command 'status' needs one argument.") << endl; - exit(EXIT_FAILURE); - } - - GetOpts::parsed_opts::const_iterator opt; - - pair snaps(read_nums(getopts.popArg())); - - Comparison comparison(sh, snaps.first, snaps.second); - - const Files& files = comparison.getFiles(); - - FILE* file = stdout; - - if ((opt = opts.find("output")) != opts.end()) - { - file = fopen(opt->second.c_str(), "w"); - if (!file) - { - cerr << sformat(_("Opening file '%s' failed."), opt->second.c_str()) << endl; - exit(EXIT_FAILURE); - } - } - - for (Files::const_iterator it = files.begin(); it != files.end(); ++it) - fprintf(file, "%s %s\n", statusToString(it->getPreToPostStatus()).c_str(), - it->getAbsolutePath(LOC_SYSTEM).c_str()); - - if (file != stdout) - fclose(file); -} - - -void -help_diff() -{ - cout << _(" Comparing snapshots:") << endl - << _("\tsnapper diff .. [files]") << endl - << endl; -} - - -void -command_diff() -{ - GetOpts::parsed_opts opts = getopts.parse("diff", GetOpts::no_options); - - GetOpts::parsed_opts::const_iterator opt; - - pair snaps(read_nums(getopts.popArg())); - - Comparison comparison(sh, snaps.first, snaps.second); - - const Files& files = comparison.getFiles(); - - if (getopts.numArgs() == 0) - { - for (Files::const_iterator it1 = files.begin(); it1 != files.end(); ++it1) - { - vector lines = it1->getDiff("--unified --new-file"); - for (vector::const_iterator it2 = lines.begin(); it2 != lines.end(); ++it2) - cout << it2->c_str() << endl; - } - } - else - { - while (getopts.numArgs() > 0) - { - string name = getopts.popArg(); - - Files::const_iterator tmp = files.findAbsolutePath(name); - if (tmp == files.end()) - continue; - - vector lines = tmp->getDiff("--unified --new-file"); - for (vector::const_iterator it2 = lines.begin(); it2 != lines.end(); ++it2) - cout << it2->c_str() << endl; - } - } -} - - -void -help_undo() -{ - cout << _(" Undo changes:") << endl - << _("\tsnapper undochange .. [files]") << endl - << endl - << _(" Options for 'undochange' command:") << endl - << _("\t--input, -i \t\tRead files for which to undo changes from file.") << endl - << endl; -} - - -void -command_undo() -{ - const struct option options[] = { - { "input", required_argument, 0, 'i' }, - { 0, 0, 0, 0 } - }; - - GetOpts::parsed_opts opts = getopts.parse("undochange", options); - if (getopts.numArgs() < 1) - { - cerr << _("Command 'undochange' needs at least one argument.") << endl; - exit(EXIT_FAILURE); - } - - pair snaps(read_nums(getopts.popArg())); - - FILE* file = NULL; - - GetOpts::parsed_opts::const_iterator opt; - - if ((opt = opts.find("input")) != opts.end()) - { - file = fopen(opt->second.c_str(), "r"); - if (!file) - { - cerr << sformat(_("Opening file '%s' failed."), opt->second.c_str()) << endl; - exit(EXIT_FAILURE); - } - } - - if (snaps.first->isCurrent()) - { - cerr << _("Invalid snapshots.") << endl; - exit(EXIT_FAILURE); - } - - Comparison comparison(sh, snaps.first, snaps.second); - - Files& files = comparison.getFiles(); - - if (file) - { - AsciiFileReader asciifile(file); - - string line; - while (asciifile.getline(line)) - { - if (line.empty()) - continue; - - string name = line; - - // strip optional status - if (name[0] != '/') - { - string::size_type pos = name.find(" "); - if (pos == string::npos) - continue; - - name.erase(0, pos + 1); - } - - Files::iterator it = files.findAbsolutePath(name); - if (it == files.end()) - { - cerr << sformat(_("File '%s' not found."), name.c_str()) << endl; - exit(EXIT_FAILURE); - } - - it->setUndo(true); - } - } - else - { - if (getopts.numArgs() == 0) - { - for (Files::iterator it = files.begin(); it != files.end(); ++it) - it->setUndo(true); - } - else - { - while (getopts.numArgs() > 0) - { - string name = getopts.popArg(); - - Files::iterator tmp = files.findAbsolutePath(name); - if (tmp == files.end()) - continue; - - tmp->setUndo(true); - } - } - } - - UndoStatistic rs = comparison.getUndoStatistic(); - - if (rs.empty()) - { - cout << "nothing to do" << endl; - return; - } - - cout << "create:" << rs.numCreate << " modify:" << rs.numModify << " delete:" << rs.numDelete - << endl; - - comparison.doUndo(); -} - - -void -help_cleanup() -{ - cout << _(" Cleanup snapshots:") << endl - << _("\tsnapper cleanup ") << endl - << endl; -} - - -void -command_cleanup() -{ - const struct option options[] = { - { 0, 0, 0, 0 } - }; - - GetOpts::parsed_opts opts = getopts.parse("cleanup", options); - if (getopts.numArgs() != 1) - { - cerr << _("Command 'cleanup' needs one arguments.") << endl; - exit(EXIT_FAILURE); - } - - string cleanup = getopts.popArg(); - - if (cleanup == "number") - { - sh->doCleanupNumber(); - } - else if (cleanup == "timeline") - { - sh->doCleanupTimeline(); - } - else if (cleanup == "empty-pre-post") - { - sh->doCleanupEmptyPrePost(); - } - else - { - cerr << sformat(_("Unknown cleanup algorithm '%s'."), cleanup.c_str()) << endl; - exit(EXIT_FAILURE); - } -} - - -void -command_help() -{ - getopts.parse("help", GetOpts::no_options); - if (getopts.hasArgs()) - { - cerr << _("Command 'help' does not take arguments.") << endl; - exit(EXIT_FAILURE); - } - - cout << _("usage: snapper [--global-options] [--command-options] [command-arguments]") << endl - << endl; - - cout << _(" Global options:") << endl - << _("\t--quiet, -q\t\t\tSuppress normal output.") << endl - << _("\t--verbose, -v\t\t\tIncrease verbosity.") << endl - << _("\t--table-style, -t