Accepting request 234828 from Kernel:kdump

Fix service failures after online/offline CPU under systemd.
URL-decode the target URL. (forwarded request 234827 from ptesarik)

OBS-URL: https://build.opensuse.org/request/show/234828
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/kdump?expand=0&rev=70
This commit is contained in:
Stephan Kulow 2014-05-23 06:05:19 +00:00 committed by Git OBS Bridge
commit b277353440
4 changed files with 880 additions and 0 deletions

145
kdump-fix-udev-rules.patch Normal file
View File

@ -0,0 +1,145 @@
From: Petr Tesarik <ptesarik@suse.cz>
Subject: Avoid entering failed state on CPU hotplug
References: bnc#874992, bnc#809209
Patch-mainline: scheduled for v0.8.13
When more than 5 CPUs are quickly offlined or onlined, the kdump
service enters and remains in a "failed state".
This issue appears to be caused by systemd's service start rate
limit default [more than 5 times within 10 seconds per
systemd.service(5) man page] being exceeded due to the udev
initiated kdump service restart for every CPU offline or online
operation.
Avoid the problem by preventing the systemd rate limit threshold
encounter by flushing the reset rate counter prior to each CPU
offline and online related kdump service restart.
Additionally, limit the restart to IBM POWER, because other
systems do not appear to be affected by bnc 389658.
And the z/Architecture do not need a restart on memory hotplug
either, so the udev rules are not needed at all.
Signed-off-by: Petr Tesarik <ptesarik@suse.cz>
diff --git a/70-kdump.rules b/70-kdump.rules
deleted file mode 100644
index c215f23..0000000
--- a/70-kdump.rules
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Kdump core headers needs to be regnerated if the CPUs or memory changes.
-# For this, reload kdump.
-#
-# Novell Bug #389658
-#
-
-SUBSYSTEM=="cpu", ACTION=="online", PROGRAM="/etc/init.d/boot.kdump try-restart"
-SUBSYSTEM=="cpu", ACTION=="offline", PROGRAM="/etc/init.d/boot.kdump try-restart"
-SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/etc/init.d/boot.kdump try-restart"
-SUBSYSTEM=="memory", ACTION=="remove", PROGRAM="/etc/init.d/boot.kdump try-restart"
-
diff --git a/70-kdump.rules.in b/70-kdump.rules.in
new file mode 100644
index 0000000..0ec2127
--- /dev/null
+++ b/70-kdump.rules.in
@@ -0,0 +1,37 @@
+@if @ARCH@ s390 s390x
+#
+# For s390x the ELF header is created in the kdump kernel and therefore
+# no kdump udev rules are required.
+#
+@else
+#
+# Kdump core headers needs to be regnerated if the CPUs or memory changes.
+# For this, reload kdump.
+#
+# Novell Bug #389658
+#
+
+TEST=="/usr/bin/systemctl", GOTO="kdump_systemd"
+
+@if @ARCH@ ppc ppc64 ppc64le
+SUBSYSTEM=="cpu", ACTION=="online", RUN+="/etc/init.d/boot.kdump try-restart"
+SUBSYSTEM=="cpu", ACTION=="offline", RUN+="/etc/init.d/boot.kdump try-restart"
+@endif
+SUBSYSTEM=="memory", ACTION=="add", RUN+="/etc/init.d/boot.kdump try-restart"
+SUBSYSTEM=="memory", ACTION=="remove", RUN+="/etc/init.d/boot.kdump try-restart"
+
+GOTO="kdump_end"
+
+# Systemd limits service start rate, so if udev events are emitted too
+# often, kdump will enter failed state, unless the counter is reset here.
+LABEL="kdump_systemd"
+
+@if @ARCH@ ppc ppc64 ppc64le
+SUBSYSTEM=="cpu", ACTION=="online", RUN+="/usr/bin/systemctl reset-failed kdump", RUN+="/usr/bin/systemctl try-restart kdump"
+SUBSYSTEM=="cpu", ACTION=="offline", RUN+="/usr/bin/systemctl reset-failed kdump", RUN+="/usr/bin/systemctl try-restart kdump"
+@endif
+SUBSYSTEM=="memory", ACTION=="add", RUN+="/usr/bin/systemctl reset-failed kdump", RUN+="/usr/bin/systemctl try-restart kdump"
+SUBSYSTEM=="memory", ACTION=="remove", RUN+="/usr/bin/systemctl reset-failed kdump", RUN+="/usr/bin/systemctl try-restart kdump"
+
+LABEL="kdump_end"
+@endif
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 59c4607..e10afa9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,7 +26,7 @@ SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
cmake_minimum_required(VERSION 2.6.2)
set (PACKAGE_STRING "kdump")
-set (PACKAGE_VERSION "0.8.12")
+set (PACKAGE_VERSION "0.8.13")
include_directories("${PROJECT_BINARY_DIR}")
@@ -195,8 +195,26 @@ INSTALL(FILES
/var/adm/fillup-templates/
)
+ADD_CUSTOM_COMMAND(
+ OUTPUT
+ 70-kdump.rules
+ COMMAND
+ ARCH=${CMAKE_SYSTEM_PROCESSOR}
+ awk -f ${CMAKE_CURRENT_SOURCE_DIR}/process_cond.awk
+ ${CMAKE_CURRENT_SOURCE_DIR}/70-kdump.rules.in
+ > ${CMAKE_CURRENT_BINARY_DIR}/70-kdump.rules
+ DEPENDS
+ 70-kdump.rules.in
+)
+ADD_CUSTOM_TARGET(
+ kdump.rules
+ ALL
+ DEPENDS
+ 70-kdump.rules
+)
+
INSTALL(FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/70-kdump.rules
+ ${CMAKE_CURRENT_BINARY_DIR}/70-kdump.rules
DESTINATION
/etc/udev/rules.d
)
diff --git a/process_cond.awk b/process_cond.awk
index 82ffe92..d6f966b 100755
--- a/process_cond.awk
+++ b/process_cond.awk
@@ -5,7 +5,12 @@
ENVIRON[var[1]] \
substr($0, RSTART + RLENGTH)
stack[sp++] = remove
- remove = remove || ($2 != $3)
+ condition = 0
+ for (i = 3; i <= NF; i++) {
+ if ($2 == $i)
+ condition = 1
+ }
+ remove = remove || !condition
skip = 1
}
/^@else\>/ {

718
kdump-urldecode.patch Normal file
View File

@ -0,0 +1,718 @@
From: Petr Tesarik <ptesarik@suse.cz>
Subject: Perform percent decoding on target URL
References: bnc#869590
Patch-mainline: scheduled for v0.8.13
Signed-off-by: Petr Tesarik <ptesarik@suse.cz>
diff --git a/kdumptool/CMakeLists.txt b/kdumptool/CMakeLists.txt
index 81ce47e..9a5bc1a 100644
--- a/kdumptool/CMakeLists.txt
+++ b/kdumptool/CMakeLists.txt
@@ -142,3 +142,8 @@ add_executable(testprocess
testprocess.cc
)
target_link_libraries(testprocess common ${EXTRA_LIBS})
+
+add_executable(testurldecode
+ testurldecode.cc
+)
+target_link_libraries(testurldecode common ${EXTRA_LIBS})
diff --git a/kdumptool/stringutil.cc b/kdumptool/stringutil.cc
index 807a30a..70d2dc5 100644
--- a/kdumptool/stringutil.cc
+++ b/kdumptool/stringutil.cc
@@ -270,6 +270,19 @@ void Stringutil::digest_base64(const void *buf, size_t len,
#endif // HAVE_LIBSSL
+// -----------------------------------------------------------------------------
+int Stringutil::hex2int(char c)
+ throw (KError)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ throw KError(string("Stringutil::hex2int: '") + c + "' is not a hex digit");
+}
+
//}}}
//{{{ KString ------------------------------------------------------------------
@@ -333,6 +346,27 @@ bool KString::endsWith(const string &part) const
return strcmp(c_str() + size() - part.size(), part.c_str()) == 0;
}
+// -----------------------------------------------------------------------------
+KString &KString::decodeURL(bool formenc)
+ throw()
+{
+ iterator src, dst;
+ for (src = dst = begin(); src != end(); ++src) {
+ char c1, c2;
+ if (*src == '%' && end() - src >= 2 &&
+ isxdigit(c1 = src[1]) && isxdigit(c2 = src[2])) {
+ *dst++ = (Stringutil::hex2int(c1) << 4) |
+ Stringutil::hex2int(c2);
+ src += 2;
+ } else if (formenc && *src == '+')
+ *dst++ = ' ';
+ else
+ *dst++ = *src;
+ }
+ resize(dst - begin());
+ return *this;
+}
+
//}}}
// vim: set sw=4 ts=4 fdm=marker et: :collapseFolds=1:
diff --git a/kdumptool/stringutil.h b/kdumptool/stringutil.h
index 321ab59..4dad735 100644
--- a/kdumptool/stringutil.h
+++ b/kdumptool/stringutil.h
@@ -200,6 +200,9 @@ class Stringutil {
throw (KError);
#endif // HAVE_LIBSSL
+
+ static int hex2int(char c)
+ throw (KError);
};
//}}}
@@ -289,6 +292,14 @@ class KString : public std::string {
bool endsWith(const std::string &part) const
throw ();
+ /**
+ * Perform URL decoding on the string.
+ *
+ * @param[in] formenc if @c true, translate '+' into spaces
+ * @return reference to this object (after decoding)
+ */
+ KString &decodeURL(bool formenc = false)
+ throw();
};
//}}}
diff --git a/kdumptool/testurldecode.cc b/kdumptool/testurldecode.cc
new file mode 100644
index 0000000..36e639f
--- /dev/null
+++ b/kdumptool/testurldecode.cc
@@ -0,0 +1,60 @@
+/*
+ * (c) 2014, Petr Tesarik <ptesarik@suse.de>, SUSE LINUX Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <iostream>
+#include <cstdlib>
+
+#include "global.h"
+#include "stringutil.h"
+#include "debug.h"
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+// -----------------------------------------------------------------------------
+int main(int argc, char *argv[])
+{
+ Debug::debug()->setStderrLevel(Debug::DL_TRACE);
+ bool formenc = false;
+
+ try {
+ int i = 1;
+ if (i < argc && KString(argv[i]) == "-f") {
+ formenc = true;
+ ++i;
+ }
+
+ bool addspace = false;
+ while (i < argc) {
+ KString arg(argv[i]);
+ if (addspace)
+ cout << ' ';
+ cout << arg.decodeURL(formenc);
+ addspace = true;
+ ++i;
+ }
+ cout << endl;
+
+ } catch(const std::exception &ex) {
+ cerr << "Fatal exception: " << ex.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/kdumptool/urlparser.cc b/kdumptool/urlparser.cc
index 095415e..fda09ea 100644
--- a/kdumptool/urlparser.cc
+++ b/kdumptool/urlparser.cc
@@ -86,166 +86,147 @@ string URLParser::protocol2string(URLParser::Protocol protocol)
}
// -----------------------------------------------------------------------------
+string URLParser::extractScheme(string::iterator &it,
+ const string::const_iterator &end)
+{
+ string::iterator const start = it;
+
+ if (it == m_url.end() || !isalpha(*it))
+ return string();
+
+ do {
+ ++it;
+ if (it == m_url.end()) {
+ it = start;
+ return string();
+ }
+ } while (*it != ':' && *it != '/' && *it != '?' && *it != '#');
+
+ if (*it != ':') {
+ it = start;
+ return string();
+ }
+
+ return string(start, it++);
+}
+
+// -----------------------------------------------------------------------------
+string URLParser::extractAuthority(string::iterator &it,
+ const string::const_iterator &end)
+{
+ if (end - it < 2 || it[0] != '/' || it[1] != '/')
+ return string();
+
+ it += 2;
+ string::iterator const start = it;
+ while (*it != '/' && *it != '?' && *it != '#')
+ ++it;
+
+ return string(start, it);
+}
+
+// -----------------------------------------------------------------------------
URLParser::URLParser(const std::string &url)
throw (KError)
: m_url(url), m_port(-1)
{
Debug::debug()->trace("URLParser::URLParser(%s)", url.c_str());
- if (url.size() == 0)
- throw KError("URL must be longer than 0 characters.");
-
- // local files that don't have URL syntax
- // we support that for backward-compatibility
- if (url[0] == '/') {
- m_protocol = PROT_FILE;
- m_path = url;
- return;
- }
+ string::iterator it = m_url.begin();
//
- // get the protocol
+ // extract the three main URL componenets
//
+ string scheme = extractScheme(it, m_url.end());
+ string authority = extractAuthority(it, m_url.end());
+ m_path.assign(it, m_url.end());
+ // TODO: query and fragment are not handled
- string::size_type first_colon = url.find(':');
- if (first_colon == string::npos)
- throw KError("The URL does not contain any protocol.");
- string proto_part = url.substr(0, first_colon);
- Debug::debug()->trace("Setting protocol to %s", proto_part.c_str());
- m_protocol = string2protocol(proto_part);
-
- if (url.size() < (first_colon + 3) ||
- url[first_colon+1] != '/' ||
- url[first_colon+2] != '/')
- throw KError("protocol: must be followed by '//'.");
+ if (m_path.empty() || m_path[0] != '/')
+ throw KError("URLParser: Only absolute paths are supported.");
//
- // call the parse methods matching for the protocol
+ // parse the authority part
//
- if (m_protocol == PROT_FILE) {
- m_path = url.substr(first_colon+3);
- } else if (m_protocol == PROT_NFS) {
- parseNFSUrl(url.substr(first_colon+3));
- } else if (m_protocol == PROT_SFTP || m_protocol == PROT_SSH ||
- m_protocol == PROT_FTP || m_protocol == PROT_CIFS) {
- parseFTPUrl(url.substr(first_colon+3));
- } else
- throw KError("Invalid protocol: " +
- Stringutil::number2string(m_protocol) + ".");
+ // Look for (optional) port
+ it = authority.end();
+ while (it != authority.begin() && isdigit(it[-1]))
+ --it;
+ if (it != authority.begin() && it[-1] == ':') {
+ string port(it, authority.end());
+ authority.resize(it - authority.begin() - 1);
- Debug::debug()->dbg("URL parsed as: protocol=%s, host=%s, port=%d, "
- "username=%s, password=%s, path=%s",
- getProtocolAsString().c_str(),
- getHostname().c_str(), getPort(), getUsername().c_str(),
- getPassword().c_str(), getPath().c_str());
+ if (port.size() > 0)
+ m_port = Stringutil::string2number(port);
+ }
-}
+ // look for userinfo
+ string::size_type last_at = authority.rfind('@');
+ if (last_at != string::npos) {
+ m_hostname = authority.substr(last_at+1);
+ authority.resize(last_at);
+
+ // now separate user and password
+ string::size_type first_colon = authority.find(':');
+ if (first_colon != string::npos) {
+ m_username = authority.substr(0, first_colon);
+ m_password = authority.substr(first_colon+1);
+ } else
+ m_username = authority;
+ } else
+ m_hostname = authority;
-// -----------------------------------------------------------------------------
-void URLParser::parseUserPassHostPort(const string &userpasshostport)
- throw (KError)
-{
- // now scan for an '@' to separate userhost from hostport
- string::size_type last_at = userpasshostport.rfind('@');
- string userhost;
- string hostport;
- if (last_at == string::npos) {
- hostport = userpasshostport;
-
- switch (m_protocol) {
- case PROT_FTP:
- m_username = FTP_DEFAULT_USER;
- break;
-
- case PROT_SFTP:
- case PROT_SSH:
- m_username = SFTP_DEFAULT_USER;
- break;
-
- default:
- // do nothing but make the compiler happy
- break;
- }
+ //
+ // undo percent encoding
+ //
+ m_hostname.decodeURL();
+ m_password.decodeURL();
+ m_username.decodeURL();
+ m_path.decodeURL();
+ //
+ // guess the scheme, if omitted
+ //
+ if (scheme.empty()) {
+ if (m_hostname.empty() || m_hostname == "localhost") {
+ m_protocol = PROT_FILE;
+ Debug::debug()->trace("URL looks like a local file");
+ } else {
+ m_protocol = PROT_NFS;
+ Debug::debug()->trace("URL looks like a remote file");
+ }
} else {
- string userpass = userpasshostport.substr(0, last_at);
- hostport = userpasshostport.substr(last_at+1);
-
- // now separate user and passwort
- string::size_type firstcolon = userpass.find(':');
- if (firstcolon != string::npos) {
- m_username = userpass.substr(0, firstcolon);
- m_password = userpass.substr(firstcolon+1);
- } else
- m_username = userpass;
+ Debug::debug()->trace("Scheme explicitly set to %s", scheme.c_str());
+ m_protocol = string2protocol(scheme);
}
- // look for a literal IPv6 addresses
- string::size_type last_colon = hostport.rfind(':');
- if (hostport[0] == '[') {
- string::size_type bracket = hostport.find(']');
- if (bracket != string::npos && bracket > last_colon)
- last_colon = string::npos;
- }
-
- // and separate host and port
- if (last_colon != string::npos) {
- m_hostname = hostport.substr(0, last_colon);
- string portstr = hostport.substr(last_colon+1);
- if (portstr.size() > 0)
- m_port = Stringutil::string2number(portstr);
- } else
- m_hostname = hostport;
-}
-
-// -----------------------------------------------------------------------------
-void URLParser::parseNFSUrl(const string &partUrl)
- throw (KError)
-{
- Debug::debug()->trace("URLParser::parseNFSUrl(%s)", partUrl.c_str());
-
- // look for the first '/'
- string::size_type first_slash = partUrl.find('/');
- if (first_slash == string::npos)
- throw KError("NFS URL must contain at least one '/'.");
+ //
+ // protocol-specific defaults
+ //
- m_hostname = partUrl.substr(0, first_slash);
+ if (m_protocol == PROT_FILE && m_hostname == "localhost")
+ m_hostname.clear();
- string::size_type last_colon = m_hostname.rfind(':');
- if (m_hostname[0] == '[') {
- string::size_type bracket = m_hostname.find(']');
- if (bracket != string::npos && bracket > last_colon)
- last_colon = string::npos;
+ if (m_username.empty()) {
+ if (m_protocol == PROT_FTP)
+ m_username = FTP_DEFAULT_USER;
+ else if (m_protocol == PROT_SFTP || m_protocol == PROT_SSH)
+ m_username = SFTP_DEFAULT_USER;
}
- if (last_colon != string::npos) {
- string hostport = m_hostname;
- m_hostname = hostport.substr(0, last_colon);
- string portstring = hostport.substr(last_colon+1);
- if (portstring.size() > 0)
- m_port = Stringutil::string2number(hostport.substr(last_colon+1));
- }
-
- m_path = partUrl.substr(first_slash);
-}
-
-// -----------------------------------------------------------------------------
-void URLParser::parseFTPUrl(const string &partUrl)
- throw (KError)
-{
- Debug::debug()->trace("URLParser::parseFTPUrl(%s)", partUrl.c_str());
- // look for the first '/' to separate the host name part from the
- // path name
- string::size_type first_slash = partUrl.find('/');
- if (first_slash == string::npos)
- throw KError(getProtocolAsString() +
- " URL must contain at least one '/'.");
+ //
+ // sanity checks
+ //
+ if (m_protocol == PROT_FILE && !m_hostname.empty())
+ throw KError("File protocol cannot specify a remote host");
- parseUserPassHostPort(partUrl.substr(0, first_slash));
+ Debug::debug()->dbg("URL parsed as: protocol=%s, host=%s, port=%d, "
+ "username=%s, password=%s, path=%s",
+ getProtocolAsString().c_str(),
+ getHostname().c_str(), getPort(), getUsername().c_str(),
+ getPassword().c_str(), getPath().c_str());
- // and the rest is the path
- m_path = partUrl.substr(first_slash);
}
// -----------------------------------------------------------------------------
diff --git a/kdumptool/urlparser.h b/kdumptool/urlparser.h
index aac01e7..94aab27 100644
--- a/kdumptool/urlparser.h
+++ b/kdumptool/urlparser.h
@@ -26,6 +26,7 @@
#include "global.h"
#include "optionparser.h"
#include "subcommand.h"
+#include "stringutil.h"
//{{{ URLParser ----------------------------------------------------------------
@@ -158,29 +159,32 @@ class URLParser {
static std::string protocol2string(Protocol protocol)
throw (KError);
- protected:
-
- void parseCifsUrl(const std::string &partUrl)
- throw (KError);
-
- void parseNFSUrl(const std::string &partUrl)
- throw (KError);
-
- void parseUserPassHostPort(const std::string &userpasshostport)
- throw (KError);
-
- void parseFTPUrl(const std::string &partUrl)
- throw (KError);
-
private:
- std::string m_url;
+ std::string m_url;
Protocol m_protocol;
- std::string m_hostname;
- std::string m_password;
- std::string m_username;
+ KString m_hostname;
+ KString m_password;
+ KString m_username;
int m_port;
- std::string m_path;
- std::string m_share;
+ KString m_path;
+
+ /**
+ * Extract scheme from a string
+ *
+ * @param[in,out] it starting position (updated if scheme is found)
+ * @param[in] end end of input string
+ */
+ std::string extractScheme(std::string::iterator &it,
+ const std::string::const_iterator &end);
+
+ /**
+ * Extract authority from a string
+ *
+ * @param[in,out] it starting position (updated if authority is found)
+ * @param[in] end end of input string
+ */
+ std::string extractAuthority(std::string::iterator &it,
+ const std::string::const_iterator &end);
};
//}}}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 41c222b..0b35466 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -60,3 +60,7 @@ ADD_TEST(delete_dumps
ADD_TEST(process
${CMAKE_CURRENT_SOURCE_DIR}/process.sh
${CMAKE_BINARY_DIR}/kdumptool/testprocess)
+
+ADD_TEST(urldecode
+ ${CMAKE_CURRENT_SOURCE_DIR}/testurldecode.sh
+ ${CMAKE_BINARY_DIR}/kdumptool/testurldecode)
diff --git a/tests/testurldecode.sh b/tests/testurldecode.sh
new file mode 100755
index 0000000..a8076b4
--- /dev/null
+++ b/tests/testurldecode.sh
@@ -0,0 +1,163 @@
+#!/bin/bash
+#
+# (c) 2014, Petr Tesarik <ptesarik@suse.de>, SUSE LINUX Products GmbH
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+# Check that results match expectation
+# {{{
+function check()
+{
+ local arg="$1"
+ local expect="$2"
+ local result="$3"
+ if [ "$result" != "$expect" ] ; then
+ echo "failed string: $arg"
+ echo "Expected:"
+ echo "$expect"
+ echo "Result:"
+ echo "$result"
+ errornumber=$(( errornumber + 1 ))
+ fi
+}
+# }}}
+
+#
+# Program {{{
+#
+
+# number of tested characters for random tests
+NTEST=100
+
+URLDECODE=$1
+HEXDUMP="od -Ax -tx1"
+
+if [ -z "$URLDECODE" ] ; then
+ echo "Usage: $0 urldecode"
+ exit 1
+fi
+
+errornumber=0
+
+# TEST #1: Random uppercase %-sequences
+
+ARG=
+EXPECT=
+i=0
+while [ $i -lt $NTEST ]
+do
+ ch=$(( $RANDOM % 256 ))
+ hex=$( printf "%02X" $ch )
+ ARG="$ARG%$hex"
+ EXPECT="$EXPECT\\x$hex"
+ i=$(( i + 1 ))
+done
+EXPECT=$( echo -e "$EXPECT" | $HEXDUMP )
+RESULT=$( "$URLDECODE" "$ARG" | $HEXDUMP )
+check "$ARG" "$EXPECT" "$RESULT"
+
+# TEST #2: Random lowercase %-sequences
+
+ARG=
+EXPECT=
+i=0
+while [ $i -lt $NTEST ]
+do
+ ch=$(( $RANDOM % 256 ))
+ hex=$( printf "%02x" $ch )
+ ARG="$ARG%$hex"
+ EXPECT="$EXPECT\\x$hex"
+ i=$(( i + 1 ))
+done
+EXPECT=$( echo -e "$EXPECT" | $HEXDUMP )
+RESULT=$( "$URLDECODE" "$ARG" | $HEXDUMP )
+check "$ARG" "$EXPECT" "$RESULT"
+
+# TEST #3: Decoding '+'
+
+ARG=" + +begin hello+world end+"
+EXPECT="+ +begin hello+world end+"
+RESULT=$( "$URLDECODE" $ARG )
+check "$ARG" "$EXPECT" "$RESULT"
+
+# now using form decoding
+EXPECT=" begin hello world end "
+RESULT=$( "$URLDECODE" -f $ARG )
+check "$ARG" "$EXPECT" "$RESULT"
+
+# TEST #4: Transitions quoted <-> unquoted
+
+ARG=
+EXPECT=
+i=0
+while [ $i -lt $NTEST ]
+do
+ ch=$(( $RANDOM % 256 ))
+ hex=$( printf "%02x" $ch )
+ case $(( $ch % 3 )) in
+ 0)
+ ARG="$ARG $hex%$hex"
+ EXPECT="$EXPECT $hex\\x$hex"
+ ;;
+
+ 1)
+ ARG="$ARG %$hex$hex"
+ EXPECT="$EXPECT \\x$hex$hex"
+ ;;
+
+ 2)
+ ARG="$ARG $hex%$hex$hex"
+ EXPECT="$EXPECT $hex\\x$hex$hex"
+ ;;
+
+ 3)
+ ARG="$ARG +%$hex+$hex"
+ EXPECT="$EXPECT \\x$hex $hex"
+ ;;
+ esac
+ i=$(( i + 1 ))
+done
+EXPECT=$( echo -e "$EXPECT" | $HEXDUMP )
+RESULT=$( "$URLDECODE" "$ARG" | $HEXDUMP )
+check "$ARG" "$EXPECT" "$RESULT"
+
+# TEST #5: Test invalid sequence
+
+ARG=" %invalid %0invalid %ainvalid %x0invalid %+invalid %0+invalid"
+EXPECT="%invalid %0invalid %ainvalid %x0invalid % invalid %0 invalid"
+RESULT=$( "$URLDECODE" -f $ARG )
+check "$ARG" "$EXPECT" "$RESULT"
+
+# TEST #6: More than two hex digits
+
+ARG="%4567 %456789abcdef0123"
+EXPECT="E67 E6789abcdef0123"
+RESULT=$( "$URLDECODE" $ARG )
+check "$ARG" "$EXPECT" "$RESULT"
+
+# TEST #7: NUL character
+
+ARG="NUL character here: '%00'"
+EXPECT=$( echo -e "NUL character here: '\000'" | $HEXDUMP )
+RESULT=$( "$URLDECODE" $ARG | $HEXDUMP )
+check "$ARG" "$EXPECT" "$RESULT"
+
+exit $errornumber
+
+# }}}
+
+# vim: set sw=4 ts=4 fdm=marker et: :collapseFolds=1:
diff --git a/tests/testurlparser.sh b/tests/testurlparser.sh
index 9cb9f1b..1d05353 100755
--- a/tests/testurlparser.sh
+++ b/tests/testurlparser.sh
@@ -32,6 +32,7 @@ URLS=( "/var/log/dump"
"cifs://bwalle:dontsay@neptunium:/var/log/dump"
"smb://bwalle@192.168.0.70:/var/log"
"cifs://bwalle:dontsay@neptunium:/var/log/dump"
+ "ftp://pt%65sarik:don%27t%20say@fu%6eny+host/var/log/dum%70"
)
# protocol:host:port:user:pass:path
@@ -45,6 +46,7 @@ VALUES=( "file::-1:::/var/log/dump"
"cifs:neptunium:-1:bwalle:dontsay:/var/log/dump"
"cifs:192.168.0.70:-1:bwalle::/var/log"
"cifs:neptunium:-1:bwalle:dontsay:/var/log/dump"
+ "ftp:funny+host:-1:ptesarik:don't say:/var/log/dump"
)
# }}}

View File

@ -1,3 +1,15 @@
-------------------------------------------------------------------
Tue May 20 11:15:40 UTC 2014 - ptesarik@suse.cz
- kdump-urldecode.patch: Perform percent decoding on target URL
(bnc#869590).
-------------------------------------------------------------------
Mon May 19 14:18:27 UTC 2014 - ptesarik@suse.cz
- kdump-fix-udev-rules.patch: Avoid entering failed state on CPU
hotplug (bnc#874992, bnc#809209).
-------------------------------------------------------------------
Fri May 16 17:42:37 UTC 2014 - ptesarik@suse.cz

View File

@ -59,6 +59,8 @@ PreReq: %insserv_prereq %fillup_prereq mkinitrd
Source: %{name}-%{version}.tar.bz2
Source2: %{name}-%{version}-rpmlintrc
Source3: kdump.service
Patch1: %{name}-fix-udev-rules.patch
Patch2: %{name}-urldecode.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build
# rename "kdump-helpers" (10.3) -> "kdump" (11.0/SP2)
Provides: kdump-helpers = %{version}
@ -96,6 +98,9 @@ Authors:
%prep
%setup
%patch1 -p1
%patch2 -p1
chmod +x tests/testurldecode.sh
%build
export CFLAGS="%optflags"