[pdns] Add patch to fix Remote backend
Morten Stevens
mstevens at fedoraproject.org
Sat Aug 31 18:24:54 UTC 2013
commit 51c71b42c80ce12917570e2dc337cee96bcb53e7
Author: Morten Stevens <mstevens at imt-systems.com>
Date: Sat Aug 31 20:24:07 2013 +0200
Add patch to fix Remote backend
pdns-fix-backend-remote.patch | 573 +++++++++++++++++++++++++++++++++++++++++
pdns.spec | 7 +-
2 files changed, 579 insertions(+), 1 deletions(-)
---
diff --git a/pdns-fix-backend-remote.patch b/pdns-fix-backend-remote.patch
new file mode 100644
index 0000000..3874f22
--- /dev/null
+++ b/pdns-fix-backend-remote.patch
@@ -0,0 +1,573 @@
+diff --git a/modules/remotebackend/Makefile.am b/modules/remotebackend/Makefile.am
+index c4bf579..04d110a 100644
+--- a/modules/remotebackend/Makefile.am
++++ b/modules/remotebackend/Makefile.am
+@@ -31,7 +31,7 @@ libtestremotebackend_la_SOURCES=../../pdns/dnsbackend.hh ../../pdns/dnsbackend.c
+ ../../pdns/aes/dns_random.cc ../../pdns/packetcache.hh ../../pdns/packetcache.cc \
+ ../../pdns/aes/aescpp.h ../../pdns/dns.hh ../../pdns/dns.cc ../../pdns/json.hh ../../pdns/json.cc \
+ ../../pdns/aes/aescrypt.c ../../pdns/aes/aes.h ../../pdns/aes/aeskey.c ../../pdns/aes/aes_modes.c ../../pdns/aes/aesopt.h \
+- ../../pdns/aes/aestab.c ../../pdns/aes/aestab.h ../../pdns/aes/brg_endian.h ../../pdns/aes/brg_types.h ../pipebackend/coprocess.cc \
++ ../../pdns/aes/aestab.c ../../pdns/aes/aestab.h ../../pdns/aes/brg_endian.h ../../pdns/aes/brg_types.h \
+ remotebackend.hh remotebackend.cc unixconnector.cc httpconnector.cc pipeconnector.cc
+
+ libtestremotebackend_la_CFLAGS=$(BOOST_CPPFLAGS) @THREADFLAGS@ $(LIBCURL_CFLAGS) -g -O0 -I../../pdns
+diff --git a/modules/remotebackend/pipeconnector.cc b/modules/remotebackend/pipeconnector.cc
+index 9e28980..f86fd28 100644
+--- a/modules/remotebackend/pipeconnector.cc
++++ b/modules/remotebackend/pipeconnector.cc
+@@ -1,3 +1,5 @@
++#include <sys/types.h>
++#include <sys/wait.h>
+ #include "remotebackend.hh"
+
+ PipeConnector::PipeConnector(std::map<std::string,std::string> options) {
+@@ -7,26 +9,92 @@
+ }
+ this->command = options.find("command")->second;
+ this->options = options;
+- this->coproc = NULL;
++ d_timeout=2000;
++
++ if (options.find("timeout") != options.end()) {
++ d_timeout = boost::lexical_cast<int>(options.find("timeout")->second);
++ }
++
++ d_pid = -1;
++ d_fp = NULL;
+ launch();
+ }
+
+ PipeConnector::~PipeConnector(){
+- if (this->coproc != NULL)
+- delete coproc;
++ int status;
++ // just in case...
++ if (d_pid == -1) return;
++
++ if(!waitpid(d_pid, &status, WNOHANG)) {
++ kill(d_pid, 9);
++ waitpid(d_pid, &status, 0);
++ }
++
++ close(d_fd1[1]);
++ if (d_fp != NULL) fclose(d_fp);
+ }
+
+ void PipeConnector::launch() {
+- if (coproc != NULL) return;
++ // no relaunch
++ if (d_pid > 0 && checkStatus()) return;
++
++ std::vector <std::string> v;
++ split(v, command, is_any_of(" "));
++
++ const char *argv[v.size()+1];
++ argv[v.size()]=0;
++
++ for (size_t n = 0; n < v.size(); n++)
++ argv[n]=v[n].c_str();
++
++ signal(SIGPIPE, SIG_IGN);
++
++ if(access(argv[0],X_OK)) // check before fork so we can throw
++ throw AhuException("Command '"+string(argv[0])+"' cannot be executed: "+stringerror());
++
++ if(pipe(d_fd1)<0 || pipe(d_fd2)<0)
++ throw AhuException("Unable to open pipe for coprocess: "+string(strerror(errno)));
++
++ if((d_pid=fork())<0)
++ throw AhuException("Unable to fork for coprocess: "+stringerror());
++ else if(d_pid>0) { // parent speaking
++ close(d_fd1[0]);
++ Utility::setCloseOnExec(d_fd1[1]);
++ close(d_fd2[1]);
++ Utility::setCloseOnExec(d_fd2[0]);
++ if(!(d_fp=fdopen(d_fd2[0],"r")))
++ throw AhuException("Unable to associate a file pointer with pipe: "+stringerror());
++ setbuf(d_fp,0); // no buffering please, confuses select
++ }
++ else if(!d_pid) { // child
++ signal(SIGCHLD, SIG_DFL); // silence a warning from perl
++ close(d_fd1[1]);
++ close(d_fd2[0]);
++
++ if(d_fd1[0]!= 0) {
++ dup2(d_fd1[0], 0);
++ close(d_fd1[0]);
++ }
++
++ if(d_fd2[1]!= 1) {
++ dup2(d_fd2[1], 1);
++ close(d_fd2[1]);
++ }
++
++ // stdin & stdout are now connected, fire up our coprocess!
++
++ if(execv(argv[0], const_cast<char * const *>(argv))<0) // now what
++ exit(123);
++
++ /* not a lot we can do here. We shouldn't return because that will leave a forked process around.
++ no way to log this either - only thing we can do is make sure that our parent catches this soonest! */
++ }
++
+ rapidjson::Value val;
+ rapidjson::Document init,res;
+- int timeout=2000;
+- if (options.find("timeout") != options.end()) {
+- timeout = boost::lexical_cast<int>(options.find("timeout")->second);
+- }
+- coproc = new CoProcess(this->command, timeout);
+ init.SetObject();
+ val = "initialize";
++
+ init.AddMember("method",val, init.GetAllocator());
+ val.SetObject();
+ init.AddMember("parameters", val, init.GetAllocator());
+@@ -44,42 +112,83 @@ void PipeConnector::launch() {
+
+ int PipeConnector::send_message(const rapidjson::Document &input)
+ {
+- std::string data;
++ std::string line;
++ line = makeStringFromDocument(input);
++ launch();
+
+- data = makeStringFromDocument(input);
++ line.append(1,'\n');
+
+- launch();
+- try {
+- coproc->send(data);
+- return 1;
++ unsigned int sent=0;
++ int bytes;
++
++ // writen routine - socket may not accept al data in one go
++ while(sent<line.size()) {
++ bytes=write(d_fd1[1],line.c_str()+sent,line.length()-sent);
++ if(bytes<0)
++ throw AhuException("Writing to coprocess failed: "+std::string(strerror(errno)));
++
++ sent+=bytes;
+ }
+- catch(AhuException &ae) {
+- delete coproc;
+- coproc=NULL;
+- throw;
+- }
++ return sent;
+ }
+
+ int PipeConnector::recv_message(rapidjson::Document &output)
+ {
++ std::string receive;
+ rapidjson::GenericReader<rapidjson::UTF8<> , rapidjson::MemoryPoolAllocator<> > r;
+ std::string tmp;
+ std::string s_output;
+-
+ launch();
+- try {
+- while(1) {
+- coproc->receive(tmp);
+- s_output.append(tmp);
+- rapidjson::StringStream ss(s_output.c_str());
+- output.ParseStream<0>(ss);
+- if (output.HasParseError() == false)
+- return s_output.size();
+- }
+- } catch(AhuException &ae) {
+- L<<Logger::Warning<<"[pipeconnector] "<<" unable to receive data from coprocess. "<<ae.reason<<endl;
+- delete coproc;
+- coproc = NULL;
+- throw;
++
++ while(1) {
++ receive.clear();
++ if(d_timeout) {
++ struct timeval tv;
++ tv.tv_sec = d_timeout/1000;
++ tv.tv_usec = (d_timeout % 1000) * 1000;
++ fd_set rds;
++ FD_ZERO(&rds);
++ FD_SET(fileno(d_fp),&rds);
++ int ret=select(fileno(d_fp)+1,&rds,0,0,&tv);
++ if(ret<0)
++ throw AhuException("Error waiting on data from coprocess: "+stringerror());
++ if(!ret)
++ throw AhuException("Timeout waiting for data from coprocess");
++ }
++
++ if(!stringfgets(d_fp, receive))
++ throw AhuException("Child closed pipe");
++
++ s_output.append(receive);
++ rapidjson::StringStream ss(s_output.c_str());
++ output.ParseStream<0>(ss);
++ if (output.HasParseError() == false)
++ return s_output.size();
+ }
++ return 0;
++}
++
++bool PipeConnector::checkStatus()
++{
++ int status;
++ int ret=waitpid(d_pid, &status, WNOHANG);
++ if(ret<0)
++ throw AhuException("Unable to ascertain status of coprocess "+itoa(d_pid)+" from "+itoa(getpid())+": "+string(strerror(errno)));
++ else if(ret) {
++ if(WIFEXITED(status)) {
++ int ret=WEXITSTATUS(status);
++ throw AhuException("Coprocess exited with code "+itoa(ret));
++ }
++ if(WIFSIGNALED(status)) {
++ int sig=WTERMSIG(status);
++ string reason="CoProcess died on receiving signal "+itoa(sig);
++#ifdef WCOREDUMP
++ if(WCOREDUMP(status))
++ reason+=". Dumped core";
++#endif
++
++ throw AhuException(reason);
++ }
++ }
++ return true;
+ }
+diff --git a/modules/remotebackend/remotebackend.cc b/modules/remotebackend/remotebackend.cc
+index 91d426a..7adedf4 100644
+--- a/modules/remotebackend/remotebackend.cc
++++ b/modules/remotebackend/remotebackend.cc
+@@ -49,11 +49,14 @@ bool Connector::recv(rapidjson::Document &value) {
+ RemoteBackend::RemoteBackend(const std::string &suffix)
+ {
+ setArgPrefix("remote"+suffix);
+- build(getArg("connection-string"));
++
++ this->d_connstr = getArg("connection-string");
+ this->d_result = NULL;
+ this->d_dnssec = mustDo("dnssec");
+ this->d_index = -1;
+ this->d_trxid = 0;
++
++ build();
+ }
+
+ RemoteBackend::~RemoteBackend() {
+@@ -62,11 +65,40 @@ bool Connector::recv(rapidjson::Document &value) {
+ }
+ }
+
++bool RemoteBackend::send(rapidjson::Document &value) {
++ try {
++ return connector->send(value);
++ } catch (AhuException &ex) {
++ L<<Logger::Error<<"Exception caught when sending: "<<ex.reason<<std::endl;
++ } catch (...) {
++ L<<Logger::Error<<"Exception caught when sending"<<std::endl;
++ }
++
++ delete this->connector;
++ build();
++ return false;
++}
++
++bool RemoteBackend::recv(rapidjson::Document &value) {
++ try {
++ return connector->recv(value);
++ } catch (AhuException &ex) {
++ L<<Logger::Error<<"Exception caught when receiving: "<<ex.reason<<std::endl;
++ } catch (...) {
++ L<<Logger::Error<<"Exception caught when receiving"<<std::endl;;
++ }
++
++ delete this->connector;
++ build();
++ return false;
++}
++
++
+ /**
+ * Builds connector based on options
+ * Currently supports unix,pipe and http
+ */
+-int RemoteBackend::build(const std::string &connstr) {
++int RemoteBackend::build() {
+ std::vector<std::string> parts;
+ std::string type;
+ std::string opts;
+@@ -74,12 +106,12 @@ int RemoteBackend::build(const std::string &connstr) {
+
+ // connstr is of format "type:options"
+ size_t pos;
+- pos = connstr.find_first_of(":");
++ pos = d_connstr.find_first_of(":");
+ if (pos == std::string::npos)
+ throw AhuException("Invalid connection string: malformed");
+
+- type = connstr.substr(0, pos);
+- opts = connstr.substr(pos+1);
++ type = d_connstr.substr(0, pos);
++ opts = d_connstr.substr(pos+1);
+
+ // tokenize the string on comma
+ stringtok(parts, opts, ",");
+@@ -155,7 +187,7 @@ void RemoteBackend::lookup(const QType &qtype, const std::string &qdomain, DNSPa
+
+ d_result = new rapidjson::Document();
+
+- if (connector->send(query) == false || connector->recv(*d_result) == false) {
++ if (this->send(query) == false || this->recv(*d_result) == false) {
+ delete d_result;
+ return;
+ }
+@@ -186,7 +218,7 @@ bool RemoteBackend::list(const std::string &target, int domain_id) {
+
+ d_result = new rapidjson::Document();
+
+- if (connector->send(query) == false || connector->recv(*d_result) == false) {
++ if (this->send(query) == false || this->recv(*d_result) == false) {
+ delete d_result;
+ return false;
+ }
+@@ -245,7 +277,7 @@ bool RemoteBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::strin
+ JSON_ADD_MEMBER(parameters, "qname", qname.c_str(), query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ unhashed = getString(answer["result"]["unhashed"]);
+@@ -266,13 +298,13 @@ bool RemoteBackend::getDomainMetadata(const std::string& name, const std::string
+ JSON_ADD_MEMBER(parameters, "kind", kind.c_str(), query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false)
++ if (this->send(query) == false)
+ return false;
+
+ meta.clear();
+
+ // not mandatory to implement
+- if (connector->recv(answer) == false)
++ if (this->recv(answer) == false)
+ return true;
+
+ if (answer["result"].IsArray()) {
+@@ -301,7 +333,7 @@ bool RemoteBackend::setDomainMetadata(const string& name, const std::string& kin
+ parameters.AddMember("value", val, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return getBool(answer["result"]);
+@@ -321,7 +353,7 @@ bool RemoteBackend::getDomainKeys(const std::string& name, unsigned int kind, st
+ JSON_ADD_MEMBER(parameters, "kind", kind, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ keys.clear();
+@@ -351,7 +383,7 @@ bool RemoteBackend::removeDomainKey(const string& name, unsigned int id) {
+ JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+@@ -374,7 +406,7 @@ int RemoteBackend::addDomainKey(const string& name, const KeyData& key) {
+ parameters.AddMember("key", jkey, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return getInt(answer["result"]);
+@@ -394,7 +426,7 @@ bool RemoteBackend::activateDomainKey(const string& name, unsigned int id) {
+ JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+@@ -414,7 +446,7 @@ bool RemoteBackend::deactivateDomainKey(const string& name, unsigned int id) {
+ JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+@@ -436,7 +468,7 @@ bool RemoteBackend::getTSIGKey(const std::string& name, std::string* algorithm,
+ JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ if (algorithm != NULL)
+@@ -459,7 +491,7 @@ bool RemoteBackend::getDomainInfo(const string &domain, DomainInfo &di) {
+ JSON_ADD_MEMBER(parameters, "name", domain.c_str(), query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ // make sure we got zone & kind
+@@ -506,7 +538,7 @@ void RemoteBackend::setNotified(uint32_t id, uint32_t serial) {
+ JSON_ADD_MEMBER(parameters, "serial", serial, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false) {
++ if (this->send(query) == false || this->recv(answer) == false) {
+ L<<Logger::Error<<kBackendId<<"Failed to execute RPC for RemoteBackend::setNotified("<<id<<","<<serial<<")"<<endl;
+ }
+ }
+@@ -541,7 +573,7 @@ bool RemoteBackend::superMasterBackend(const string &ip, const string &domain, c
+
+ *ddb = 0;
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ // we are the backend
+@@ -565,7 +597,7 @@ bool RemoteBackend::createSlaveDomain(const string &ip, const string &domain, co
+ JSON_ADD_MEMBER(parameters, "account", account.c_str(), query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+ }
+@@ -600,7 +632,7 @@ bool RemoteBackend::replaceRRSet(uint32_t domain_id, const string& qname, const
+ parameters.AddMember("rrset", rj_rrset, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+@@ -630,7 +662,7 @@ bool RemoteBackend::feedRecord(const DNSResourceRecord &rr, string *ordername) {
+
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true; // XXX FIXME this API should not return 'true' I think -ahu
+ }
+@@ -651,7 +683,7 @@ bool RemoteBackend::feedEnts(int domain_id, set<string>& nonterm) {
+ parameters.AddMember("nonterm", nts, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+ }
+@@ -677,7 +709,7 @@ bool RemoteBackend::feedEnts3(int domain_id, const string &domain, set<string> &
+ parameters.AddMember("nonterm", nts, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+ }
+@@ -696,7 +728,7 @@ bool RemoteBackend::startTransaction(const string &domain, int domain_id) {
+
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false) {
++ if (this->send(query) == false || this->recv(answer) == false) {
+ d_trxid = -1;
+ return false;
+ }
+@@ -714,7 +746,7 @@ bool RemoteBackend::commitTransaction() {
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+ d_trxid = -1;
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+ }
+@@ -730,7 +762,7 @@ bool RemoteBackend::abortTransaction() {
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+ d_trxid = -1;
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+ }
+@@ -759,7 +791,7 @@ bool RemoteBackend::calculateSOASerial(const string& domain, const SOAData& sd,
+ parameters.AddMember("sd", soadata, query.GetAllocator());
+ query.AddMember("parameters", parameters, query.GetAllocator());
+
+- if (connector->send(query) == false || connector->recv(answer) == false)
++ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ serial = getInt64(answer["result"]);
+diff --git a/modules/remotebackend/remotebackend.hh b/modules/remotebackend/remotebackend.hh
+index 18b6a97..2f2d717 100644
+--- a/modules/remotebackend/remotebackend.hh
++++ b/modules/remotebackend/remotebackend.hh
+@@ -92,9 +92,15 @@ class PipeConnector: public Connector {
+ private:
+
+ void launch();
+- CoProcess *coproc;
++ bool checkStatus();
++
+ std::string command;
+ std::map<std::string,std::string> options;
++
++ int d_fd1[2], d_fd2[2];
++ int d_pid;
++ int d_timeout;
++ FILE *d_fp;
+ };
+
+ class RemoteBackend : public DNSBackend
+@@ -133,12 +139,13 @@ class RemoteBackend : public DNSBackend
+ static DNSBackend *maker();
+
+ private:
+- int build(const std::string &connstr);
++ int build();
+ Connector *connector;
+ bool d_dnssec;
+ rapidjson::Document *d_result;
+ int d_index;
+ int64_t d_trxid;
++ std::string d_connstr;
+
+ bool getBool(rapidjson::Value &value);
+ int getInt(rapidjson::Value &value);
+@@ -146,5 +153,8 @@ class RemoteBackend : public DNSBackend
+ int64_t getInt64(rapidjson::Value &value);
+ std::string getString(rapidjson::Value &value);
+ double getDouble(rapidjson::Value &value);
++
++ bool send(rapidjson::Document &value);
++ bool recv(rapidjson::Document &value);
+ };
+ #endif
+
diff --git a/pdns.spec b/pdns.spec
index a698ba3..8b53898 100644
--- a/pdns.spec
+++ b/pdns.spec
@@ -3,7 +3,7 @@
Name: pdns
Version: 3.3
-Release: 4%{?dist}
+Release: 5%{?dist}
Summary: A modern, advanced and high performance authoritative-only nameserver
Group: System Environment/Daemons
License: GPLv2
@@ -11,6 +11,7 @@ URL: http://powerdns.com
Source0: http://downloads.powerdns.com/releases/%{name}-%{version}.tar.gz
Source1: pdns.service
Patch0: pdns-default-config.patch
+Patch1: pdns-fix-backend-remote.patch
Requires(pre): shadow-utils
Requires(post): systemd-sysv
@@ -113,6 +114,7 @@ This package contains the SQLite backend for %{name}
%prep
%setup -q
%patch0 -p1 -b .default-config-patch
+%patch1 -p1 -b .fix-backend-remote
%build
autoreconf -v -f -i
@@ -232,6 +234,9 @@ exit 0
%{_libdir}/%{name}/libgsqlite3backend.so
%changelog
+* Sat Aug 31 2013 Morten Stevens <mstevens at imt-systems.com> - 3.3-5
+- Add patch to fix Remote backend
+
* Wed Aug 21 2013 Morten Stevens <mstevens at imt-systems.com> - 3.3-4
- Add Remote backend
More information about the scm-commits
mailing list