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:
commit
b277353440
145
kdump-fix-udev-rules.patch
Normal file
145
kdump-fix-udev-rules.patch
Normal 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
718
kdump-urldecode.patch
Normal 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"
|
||||||
|
)
|
||||||
|
# }}}
|
||||||
|
|
@ -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
|
Fri May 16 17:42:37 UTC 2014 - ptesarik@suse.cz
|
||||||
|
|
||||||
|
@ -59,6 +59,8 @@ PreReq: %insserv_prereq %fillup_prereq mkinitrd
|
|||||||
Source: %{name}-%{version}.tar.bz2
|
Source: %{name}-%{version}.tar.bz2
|
||||||
Source2: %{name}-%{version}-rpmlintrc
|
Source2: %{name}-%{version}-rpmlintrc
|
||||||
Source3: kdump.service
|
Source3: kdump.service
|
||||||
|
Patch1: %{name}-fix-udev-rules.patch
|
||||||
|
Patch2: %{name}-urldecode.patch
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||||
# rename "kdump-helpers" (10.3) -> "kdump" (11.0/SP2)
|
# rename "kdump-helpers" (10.3) -> "kdump" (11.0/SP2)
|
||||||
Provides: kdump-helpers = %{version}
|
Provides: kdump-helpers = %{version}
|
||||||
@ -96,6 +98,9 @@ Authors:
|
|||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup
|
%setup
|
||||||
|
%patch1 -p1
|
||||||
|
%patch2 -p1
|
||||||
|
chmod +x tests/testurldecode.sh
|
||||||
|
|
||||||
%build
|
%build
|
||||||
export CFLAGS="%optflags"
|
export CFLAGS="%optflags"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user