]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- allow to change config via DBus and with command line tool
authorArvin Schnell <aschnell@suse.de>
Thu, 25 Jul 2013 13:39:16 +0000 (15:39 +0200)
committerArvin Schnell <aschnell@suse.de>
Thu, 25 Jul 2013 13:39:16 +0000 (15:39 +0200)
13 files changed:
client/commands.cc
client/commands.h
client/snapper.cc
doc/dbus-protocol.txt
doc/snapper.xml.in
package/snapper.changes
server/Client.cc
server/Client.h
server/MetaSnapper.cc
server/MetaSnapper.h
snapper/AsciiFile.cc
snapper/AsciiFile.h
snapper/Snapper.h

index 127880a8b2889279304a31cd8e937ceb6a540576..8123f3058ca311110d5192f316d25a3fe466ad47 100644 (file)
@@ -63,6 +63,19 @@ command_get_xconfig(DBus::Connection& conn, const string& config_name)
 }
 
 
+void
+command_set_xconfig(DBus::Connection& conn, const string& config_name,
+                   const map<string, string>& raw)
+{
+    DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "SetConfig");
+
+    DBus::Hoho hoho(call);
+    hoho << config_name << raw;
+
+    conn.send_with_reply_and_block(call);
+}
+
+
 void
 command_create_xconfig(DBus::Connection& conn, const string& config_name, const string& subvolume,
                       const string& fstype, const string& template_name)
index 7fe966471ef03cabd46c6f2c140720742db83cc0..51d1319bb28e93c03b2f8146b227cbece9185d47 100644 (file)
@@ -39,6 +39,10 @@ command_list_xconfigs(DBus::Connection& conn);
 XConfigInfo
 command_get_xconfig(DBus::Connection& conn, const string& config_name);
 
+void
+command_set_xconfig(DBus::Connection& conn, const string& config_name,
+                   const map<string, string>& raw);
+
 void
 command_create_xconfig(DBus::Connection& conn, const string& config_name, const string& subvolume,
                       const string& fstype, const string& template_name);
index daf95ccc9151382aa213409b513ab5a5a0287f80..54f34b22c26abc9da2f3f811878027024476d014 100644 (file)
@@ -25,6 +25,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
 #include <iostream>
 #include <boost/algorithm/string.hpp>
 
@@ -34,6 +36,7 @@
 #include <snapper/AsciiFile.h>
 #include <snapper/SystemCmd.h>
 #include <snapper/SnapperDefines.h>
+#include <snapper/XAttributes.h>
 
 #include "utils/text.h"
 #include "utils/Table.h"
 #include "commands.h"
 #include "cleanup.h"
 
-#ifdef ENABLE_XATTRS
-    #include <sys/types.h>
-    #include <sys/stat.h>
-    #include <fcntl.h>
-
-    #include <snapper/XAttributes.h>
-#endif
 
 using namespace snapper;
 using namespace std;
@@ -324,6 +320,94 @@ command_delete_config(DBus::Connection& conn)
 }
 
 
+void
+help_get_config()
+{
+    cout << _("  Get config:") << endl
+        << _("\tsnapper get-config") << endl
+        << endl;
+}
+
+
+void
+command_get_config(DBus::Connection& conn)
+{
+    getopts.parse("get-config", GetOpts::no_options);
+    if (getopts.hasArgs())
+    {
+       cerr << _("Command 'get-config' does not take arguments.") << endl;
+       exit(EXIT_FAILURE);
+    }
+
+    Table table;
+
+    TableHeader header;
+    header.add(_("Key"));
+    header.add(_("Value"));
+    table.setHeader(header);
+
+    XConfigInfo ci = command_get_xconfig(conn, config_name);
+
+    for (map<string, string>::const_iterator it = ci.raw.begin(); it != ci.raw.end(); ++it)
+    {
+       TableRow row;
+       row.add(it->first);
+       row.add(it->second);
+       table.add(row);
+    }
+
+    cout << table;
+}
+
+
+void
+help_set_config()
+{
+    cout << _("  Set config:") << endl
+        << _("\tsnapper set-config <configdata>") << endl
+        << endl;
+}
+
+
+void
+command_set_config(DBus::Connection& conn)
+{
+    getopts.parse("set-config", GetOpts::no_options);
+    if (!getopts.hasArgs())
+    {
+       cerr << _("Command 'set-config' needs at least one argument.") << endl;
+       exit(EXIT_FAILURE);
+    }
+
+    map<string, string> raw;
+
+    while (getopts.hasArgs())
+    {
+       string arg = getopts.popArg();
+
+       string::size_type pos = arg.find("=");
+       if (pos == string::npos)
+       {
+           cerr << _("Invalid configdata.") << endl;
+           exit(EXIT_FAILURE);
+       }
+
+       string key = boost::trim_copy(arg.substr(0, pos));
+       string value = boost::trim_copy(arg.substr(pos + 1));
+
+       if (key.empty())
+       {
+           cerr << _("Invalid configdata.") << endl;
+           exit(EXIT_FAILURE);
+       }
+
+       raw[key] = value;
+    }
+
+    command_set_xconfig(conn, config_name, raw);
+}
+
+
 void
 help_list()
 {
@@ -1114,6 +1198,7 @@ command_debug(DBus::Connection& conn)
 
 
 #ifdef ENABLE_XATTRS
+
 void
 help_xa_diff()
 {
@@ -1171,6 +1256,7 @@ command_xa_diff(DBus::Connection& conn)
         }
     }
 }
+
 #endif
 
 
@@ -1225,6 +1311,8 @@ help()
     help_list_configs();
     help_create_config();
     help_delete_config();
+    help_get_config();
+    help_set_config();
     help_list();
     help_create();
     help_modify();
@@ -1254,6 +1342,8 @@ main(int argc, char** argv)
     cmds["list-configs"] = command_list_configs;
     cmds["create-config"] = command_create_config;
     cmds["delete-config"] = command_delete_config;
+    cmds["get-config"] = command_get_config;
+    cmds["set-config"] = command_set_config;
     cmds["list"] = command_list;
     cmds["create"] = command_create;
     cmds["modify"] = command_modify;
index 10178a7c106fd089633c8a9029defd26b34b0098..3629aecf48b0afb608fb139eeb0a3d4fd92321c4 100644 (file)
@@ -1,6 +1,7 @@
 
 method ListConfigs
 method GetConfig config-name
+method SetConfig config-name configdata
 
 
 method CreateConfig config-name subvolume fstype template-name
index bb84d2ebd4f06f8b74a04b6eafa1c588fff68c0c..89065f0d7dab398749962195c4a98045207591de 100644 (file)
        </listitem>
       </varlistentry>
 
+      <varlistentry>
+       <term><option>get-config</option></term>
+       <listitem>
+         <para>Displays the settings of the configuration.</para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><option>set-config</option> <replaceable>configdata</replaceable></term>
+       <listitem>
+         <para>Changes the settings of the configuration. The settings
+         <replaceable>configdata</replaceable> are a list of key-value-pairs separated
+         by spaces and the key and value must be separated by an equal sign,
+         e.g. "NUMBER_CLEANUP=yes NUMBER_LIMIT=10". The value of SUBVOLUME and FSTYPE
+         cannot be changed.</para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry>
        <term><option>list [options]</option></term>
        <listitem>
index 13102825d4df8128dd08cd92b8e5027ac4f95938..db60a1beda279d92234020f41586d872f26615a0 100644 (file)
@@ -1,3 +1,8 @@
+-------------------------------------------------------------------
+Thu Jul 25 14:40:31 CEST 2013 - aschnell@suse.de
+
+- allow to change config via DBus and with command line tool
+
 -------------------------------------------------------------------
 Tue Jul 09 14:00:16 CEST 2013 - aschnell@suse.de
 
index 81fc2bfb85a393f4522c842ab1276df4d38d40bf..012b36e18935e1800c4cb9d6a49da6ca11eea882 100644 (file)
@@ -177,6 +177,10 @@ Client::introspect(DBus::Connection& conn, DBus::Message& msg)
        "      <arg name='config-name' type='s'/>\n"
        "    </signal>\n"
 
+       "    <signal name='ConfigModified'>\n"
+       "      <arg name='config-name' type='s'/>\n"
+       "    </signal>\n"
+
        "    <signal name='ConfigDeleted'>\n"
        "      <arg name='config-name' type='s'/>\n"
        "    </signal>\n"
@@ -205,6 +209,11 @@ Client::introspect(DBus::Connection& conn, DBus::Message& msg)
        "      <arg name='data' type='(ssa{ss})' direction='out'/>\n"
        "    </method>\n"
 
+       "    <method name='SetConfig'>\n"
+       "      <arg name='config-name' type='s' direction='in'/>\n"
+       "      <arg name='data' type='(a{ss})' direction='in'/>\n"
+       "    </method>\n"
+
        "    <method name='CreateConfig'>\n"
        "      <arg name='config-name' type='s' direction='in'/>\n"
        "      <arg name='subvolume' type='s' direction='in'/>\n"
@@ -431,6 +440,18 @@ Client::signal_config_created(DBus::Connection& conn, const string& config_name)
 }
 
 
+void
+Client::signal_config_modified(DBus::Connection& conn, const string& config_name)
+{
+    DBus::MessageSignal msg(PATH, INTERFACE, "ConfigModified");
+
+    DBus::Hoho hoho(msg);
+    hoho << config_name;
+
+    conn.send(msg);
+}
+
+
 void
 Client::signal_config_deleted(DBus::Connection& conn, const string& config_name)
 {
@@ -501,7 +522,7 @@ Client::list_configs(DBus::Connection& conn, DBus::Message& msg)
     DBus::Hoho hoho(reply);
     hoho.open_array(DBus::TypeInfo<ConfigInfo>::signature);
     for (MetaSnappers::const_iterator it = meta_snappers.begin(); it != meta_snappers.end(); ++it)
-       hoho << it->config_info;
+       hoho << it->getConfigInfo();
     hoho.close_array();
 
     conn.send(reply);
@@ -527,9 +548,36 @@ Client::get_config(DBus::Connection& conn, DBus::Message& msg)
     DBus::MessageMethodReturn reply(msg);
 
     DBus::Hoho hoho(reply);
-    hoho << it->config_info;
+    hoho << it->getConfigInfo();
+
+    conn.send(reply);
+}
+
+
+void
+Client::set_config(DBus::Connection& conn, DBus::Message& msg)
+{
+    string config_name;
+
+    DBus::Hihi hihi(msg);
+    map<string, string> raw;
+    hihi >> config_name >> raw;
+
+    y2deb("SetConfig config_name:" << config_name << " raw:" << raw);
+
+    boost::shared_lock<boost::shared_mutex> lock(big_mutex);
+
+    MetaSnappers::iterator it = meta_snappers.find(config_name);
+
+    check_permission(conn, msg);
+
+    it->setConfigInfo(raw);
+
+    DBus::MessageMethodReturn reply(msg);
 
     conn.send(reply);
+
+    signal_config_modified(conn, config_name);
 }
 
 
@@ -886,7 +934,7 @@ Client::create_post_snapshot(DBus::Connection& conn, DBus::Message& msg)
     snap2->flushInfo();
 
     bool tmp;
-    if (it->config_info.getValue("BACKGROUND_COMPARISON", tmp) && tmp)
+    if (it->getConfigInfo().getValue("BACKGROUND_COMPARISON", tmp) && tmp)
        backgrounds.add_task(it, snap1, snap2);
 
     DBus::MessageMethodReturn reply(msg);
@@ -1222,6 +1270,8 @@ Client::dispatch(DBus::Connection& conn, DBus::Message& msg)
            create_config(conn, msg);
        else if (msg.is_method_call(INTERFACE, "GetConfig"))
            get_config(conn, msg);
+       else if (msg.is_method_call(INTERFACE, "SetConfig"))
+           set_config(conn, msg);
        else if (msg.is_method_call(INTERFACE, "DeleteConfig"))
            delete_config(conn, msg);
        else if (msg.is_method_call(INTERFACE, "LockConfig"))
@@ -1338,6 +1388,11 @@ Client::dispatch(DBus::Connection& conn, DBus::Message& msg)
        DBus::MessageError reply(msg, "error.unknown_file", DBUS_ERROR_FAILED);
        conn.send(reply);
     }
+    catch (const InvalidConfigdataException& e)
+    {
+       DBus::MessageError reply(msg, "error.invalid_configdata", DBUS_ERROR_FAILED);
+       conn.send(reply);
+    }
     catch (const InvalidUserdataException& e)
     {
        DBus::MessageError reply(msg, "error.invalid_userdata", DBUS_ERROR_FAILED);
index 6182cdf6dd671a9e3de49b83fb4414ef3c10b87c..e7932b397cdcf4d17e9731e1cb62644cf186d55f 100644 (file)
@@ -72,6 +72,7 @@ public:
     void check_snapshot_in_use(const MetaSnapper& meta_snapper, unsigned int number) const;
 
     void signal_config_created(DBus::Connection& conn, const string& config_name);
+    void signal_config_modified(DBus::Connection& conn, const string& config_name);
     void signal_config_deleted(DBus::Connection& conn, const string& config_name);
     void signal_snapshot_created(DBus::Connection& conn, const string& config_name,
                                 unsigned int num);
@@ -82,6 +83,7 @@ public:
 
     void list_configs(DBus::Connection& conn, DBus::Message& msg);
     void get_config(DBus::Connection& conn, DBus::Message& msg);
+    void set_config(DBus::Connection& conn, DBus::Message& msg);
     void create_config(DBus::Connection& conn, DBus::Message& msg);
     void delete_config(DBus::Connection& conn, DBus::Message& msg);
     void lock_config(DBus::Connection& conn, DBus::Message& msg);
index f90a06fa1b21a4738d8bd4397bab747287b0efa9..478feeddae28b128e6e1ed95ab953b7960861fa7 100644 (file)
@@ -158,9 +158,40 @@ get_group_uids(const char* groupname, vector<uid_t>& uids)
 }
 
 
-MetaSnapper::MetaSnapper(const ConfigInfo& config_info)
+MetaSnapper::MetaSnapper(ConfigInfo& config_info)
     : config_info(config_info), snapper(NULL)
 {
+    set_permissions();
+}
+
+
+MetaSnapper::~MetaSnapper()
+{
+    delete snapper;
+}
+
+
+void
+MetaSnapper::setConfigInfo(const map<string, string>& raw)
+{
+    if (raw.find("SUBVOLUME") != raw.end() || raw.find("FSTYPE") != raw.end())
+       throw InvalidConfigdataException();
+
+    for (map<string, string>::const_iterator it = raw.begin(); it != raw.end(); ++it)
+       config_info.setValue(it->first, it->second);
+
+    config_info.save();
+
+    if (raw.find("ALLOW_USERS") != raw.end() || raw.find("ALLOW_GROUPS") != raw.end())
+       set_permissions();
+}
+
+
+void
+MetaSnapper::set_permissions()
+{
+    uids.clear();
+
     vector<string> users;
     if (config_info.getValue("ALLOW_USERS", users))
     {
@@ -188,12 +219,6 @@ MetaSnapper::MetaSnapper(const ConfigInfo& config_info)
 }
 
 
-MetaSnapper::~MetaSnapper()
-{
-    delete snapper;
-}
-
-
 Snapper*
 MetaSnapper::getSnapper()
 {
@@ -229,7 +254,7 @@ MetaSnappers::init()
 {
     list<ConfigInfo> config_infos = Snapper::getConfigs();
 
-    for (list<ConfigInfo>::const_iterator it = config_infos.begin(); it != config_infos.end(); ++it)
+    for (list<ConfigInfo>::iterator it = config_infos.begin(); it != config_infos.end(); ++it)
     {
 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
        entries.emplace_back(*it);
index 955fe6f0c5e5ab3c25022c25f669f33ca2a819cb..4afda9e791da8a40fd1cd5c95d36fcd79435e4ec 100644 (file)
@@ -86,12 +86,13 @@ class MetaSnapper : public RefCounter
 {
 public:
 
-    MetaSnapper(const ConfigInfo& config_info);
+    MetaSnapper(ConfigInfo& config_info);
     ~MetaSnapper();
 
     const string& configName() const { return config_info.getConfigName(); }
 
-    const ConfigInfo config_info;
+    const ConfigInfo& getConfigInfo() const { return config_info; }
+    void setConfigInfo(const map<string, string>& raw);
 
     vector<uid_t> uids;
 
@@ -103,6 +104,10 @@ public:
 
 private:
 
+    void set_permissions();
+
+    ConfigInfo config_info;
+
     Snapper* snapper;
 
 };
index 9f8b9fff770b53e1db004957dd9ebcf55f95d260..e3e55eef19468d501c3b236a209bde1fdd5a9f50 100644 (file)
@@ -160,6 +160,14 @@ AsciiFile::save()
     }
 
 
+    void
+    SysconfigFile::save()
+    {
+       if (modified && AsciiFile::save())
+           modified = false;
+    }
+
+
     void
     SysconfigFile::setValue(const string& key, bool value)
     {
index 17fec7373f2033af8748a358467a92700d86c518..9286dd0435dca04e438d89a8abd4b964c4e36b44 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2004-2012] Novell, Inc.
+ * Copyright (c) [2004-2013] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -94,6 +94,8 @@ namespace snapper
        SysconfigFile(const string& name) : AsciiFile(name), modified(false) {}
        ~SysconfigFile() { if (modified) save(); }
 
+       void save();
+
        void setValue(const string& key, bool value);
        bool getValue(const string& key, bool& value) const;
 
index 480881aa41bc2b547021908f546ce77a29b8cc30..6b1672e6f3aefdd28e529213fd2fb02fa4517abb 100644 (file)
@@ -68,6 +68,12 @@ namespace snapper
        virtual const char* what() const throw() { return "invalid config"; }
     };
 
+    struct InvalidConfigdataException : public SnapperException
+    {
+       explicit InvalidConfigdataException() throw() {}
+       virtual const char* what() const throw() { return "invalid configdata"; }
+    };
+
     struct InvalidUserdataException : public SnapperException
     {
        explicit InvalidUserdataException() throw() {}