Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:GA
kdump.2364
kdump-move-SFTP-to-own-file.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File kdump-move-SFTP-to-own-file.patch of Package kdump.2364
From: Petr Tesarik <ptesarik@suse.cz> Date: Mon, 13 Apr 2015 14:53:05 +0200 Subject: Split off SSH transfers from transfer.cc References: FATE#318874, bsc#917747 Patch-mainline: v0.8.16 Git-commit: 97d7fde532b93a87b43db6a5ca15c6980b99c652 Putting all possible transfer classes into a single file is bad design. Start by separating SSH-based transfers into its own file. Signed-off-by: Petr Tesarik <ptesarik@suse.cz> --- kdumptool/CMakeLists.txt | 2 kdumptool/sshtransfer.cc | 466 +++++++++++++++++++++++++++++++++++++++++++++++ kdumptool/sshtransfer.h | 134 +++++++++++++ kdumptool/transfer.cc | 432 ------------------------------------------- kdumptool/transfer.h | 101 ---------- 5 files changed, 603 insertions(+), 532 deletions(-) --- a/kdumptool/CMakeLists.txt +++ b/kdumptool/CMakeLists.txt @@ -52,6 +52,8 @@ SET(COMMON_SRC fileutil.h transfer.cc transfer.h + sshtransfer.cc + sshtransfer.h socket.cc socket.h ledblink.cc --- /dev/null +++ b/kdumptool/sshtransfer.cc @@ -0,0 +1,466 @@ +/* + * (c) 2015, Petr Tesarik <ptesarik@suse.cz>, 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 <string> +#include <cstdlib> +#include <cerrno> + +#if HAVE_LIBSSH2 +# include <libssh2.h> +# include <libssh2_sftp.h> +#endif + +#include "global.h" +#include "debug.h" +#include "configuration.h" +#include "fileutil.h" +#include "dataprovider.h" +#include "process.h" +#include "socket.h" +#include "sshtransfer.h" + +using std::string; +using std::cerr; +using std::endl; + +//{{{ SSHTransfer ------------------------------------------------------------- + +/* -------------------------------------------------------------------------- */ +SSHTransfer::SSHTransfer(const RootDirURLVector &urlv, + const std::string &subdir) + throw (KError) + : URLTransfer(urlv, subdir) +{ + if (urlv.size() > 1) + cerr << "WARNING: First dump target used; rest ignored." << endl; + const RootDirURL &target = urlv.front(); + + Debug::debug()->trace("SSHTransfer::SSHTransfer(%s)", + target.getURL().c_str()); + + string remote; + FilePath fp = target.getPath(); + fp.appendPath(getSubDir()); + remote.assign("mkdir -p ").append(fp); + + SubProcess p; + p.spawn("ssh", makeArgs(remote)); + int status = p.wait(); + if (status != 0) + throw KError("SSHTransfer::SSHTransfer: ssh command failed" + " with status " + Stringutil::number2string(status)); +} + +/* -------------------------------------------------------------------------- */ +SSHTransfer::~SSHTransfer() + throw () +{ + Debug::debug()->trace("SSHTransfer::~SSHTransfer()"); +} + +/* -------------------------------------------------------------------------- */ +void SSHTransfer::perform(DataProvider *dataprovider, + const StringVector &target_files, + bool *directSave) + throw (KError) +{ + Debug::debug()->trace("SSHTransfer::perform(%p, [ \"%s\"%s ])", + dataprovider, target_files.front().c_str(), + target_files.size() > 1 ? ", ..." : ""); + + bool prepared = false; + if (directSave) + *directSave = false; + + RootDirURLVector &urlv = getURLVector(); + const RootDirURL &target = urlv.front(); + + FilePath fp = target.getPath(); + fp.appendPath(getSubDir()).appendPath(target_files.front()); + + string remote; + remote.assign("dd of=").append(fp).append("-incomplete"); + remote.append(" && mv ").append(fp).append("-incomplete ").append(fp); + Debug::debug()->dbg("Remote command: %s", remote.c_str()); + + SubProcess p; + p.setPipeDirection(STDIN_FILENO, SubProcess::ParentToChild); + p.spawn("ssh", makeArgs(remote)); + + int fd = p.getPipeFD(STDIN_FILENO); + try { + dataprovider->prepare(); + prepared = true; + + while (true) { + size_t read_data = dataprovider->getData(m_buffer, BUFSIZ); + + // finished? + if (read_data == 0) + break; + + char *p = m_buffer; + while (read_data) { + ssize_t ret = write(fd, p, read_data); + + if (ret < 0) + throw KSystemError("SSHTransfer::perform: write failed", + errno); + read_data -= ret; + p += ret; + } + } + } catch (...) { + close(fd); + if (prepared) + dataprovider->finish(); + throw; + } + close(fd); + + dataprovider->finish(); + int status = p.wait(); + if (status != 0) + throw KError("SSHTransfer::perform: ssh command failed" + " with status " + Stringutil::number2string(status)); +} + +StringVector SSHTransfer::makeArgs(std::string const &remote) +{ + const RootDirURL &target = getURLVector().front(); + StringVector ret; + + ret.push_back("-F"); + ret.push_back("/kdump/.ssh/config"); + + ret.push_back("-l"); + ret.push_back(target.getUsername()); + + int port = target.getPort(); + if (port != -1) { + ret.push_back("-p"); + ret.push_back(Stringutil::number2string(port)); + } + + ret.push_back(target.getHostname()); + ret.push_back(remote); + + return ret; +} + +//}}} +//{{{ SFTPTransfer ------------------------------------------------------------- + +#if HAVE_LIBSSH2 + +/* -------------------------------------------------------------------------- */ +SFTPTransfer::SFTPTransfer(const RootDirURLVector &urlv, + const std::string &subdir) + throw (KError) + : URLTransfer(urlv, subdir), + m_sshSession(NULL), m_sftp(NULL), m_socket(NULL) +{ + if (urlv.size() > 1) + cerr << "WARNING: First dump target used; rest ignored." << endl; + const RootDirURL &parser = urlv.front(); + + Debug::debug()->trace("SFTPTransfer::SFTPTransfer(%s)", + parser.getURL().c_str()); + + m_sshSession = libssh2_session_init(); + if (!m_sshSession) + throw KError("libssh2_session_init() failed."); + + // set blocking + libssh2_session_set_blocking(m_sshSession, 1); + + // get the correct port + int port = parser.getPort(); + if (port <= 0) + port = Socket::DP_SSH; + + // create the socket and connect + m_socket = new Socket(parser.getHostname(), port, Socket::ST_TCP); + int fd = m_socket->connect(); + + // start it up + int ret = libssh2_session_startup(m_sshSession, fd); + if (ret != 0) { + close(); + throw KError("libssh2_session_startup() failed with "+ + Stringutil::number2string(ret) +"."); + } + + // get the hostkey fingerprints + const char *hostsha1 = + libssh2_hostkey_hash(m_sshSession, LIBSSH2_HOSTKEY_HASH_SHA1); + Debug::debug()->info + ("SSH SHA1 fingerprint: %s", + Stringutil::bytes2hexstr(hostsha1, SHA1SUM_LENGTH, true).c_str()); + + const char *hostmd5 = + libssh2_hostkey_hash(m_sshSession, LIBSSH2_HOSTKEY_HASH_MD5); + Debug::debug()->info + ("SSH MD5 fingerprint: %s", + Stringutil::bytes2hexstr(hostmd5, MD5SUM_LENGTH, true).c_str()); + +#if HAVE_LIBSSL + // check the fingerprints if possible + Configuration *config = Configuration::config(); + const string &hostkey = config->KDUMP_HOST_KEY.value(); + + if (!hostkey.empty() && hostkey != "*") { + char expectmd5[MD5SUM_LENGTH]; + char expectsha1[SHA1SUM_LENGTH]; + Stringutil::digest_base64(hostkey.c_str(), hostkey.size(), + expectmd5, expectsha1); + + if (memcmp(hostsha1, expectsha1, SHA1SUM_LENGTH)) + throw KError("Target host key SHA1 fingerprint mismatch!"); + Debug::debug()->info("SHA1 fingerprint matches"); + + if (memcmp(hostmd5, expectmd5, MD5SUM_LENGTH)) + throw KError("Target host key MD5 fingerprint mismatch!"); + Debug::debug()->info("MD5 fingerprint matches"); + } else + cerr << "WARNING: SSH host key accepted without checking!" << endl; +#endif // HAVE_LIBSSL + + // SSH authentication + bool authenticated = false; + + // username and password + string username = parser.getUsername(); + string password = parser.getPassword(); + + // public and private key + string homedir = getenv("HOME"); + FilePath pubkey; + FilePath privkey; + + // DSA + (pubkey = homedir).appendPath(".ssh").appendPath("id_dsa.pub"); + (privkey = homedir).appendPath(".ssh").appendPath("id_dsa"); + if (!authenticated && pubkey.exists() && privkey.exists()) { + Debug::debug()->dbg("Using private key %s and public key %s", + privkey.c_str(), pubkey.c_str()); + + ret = libssh2_userauth_publickey_fromfile(m_sshSession, + username.c_str(), pubkey.c_str(), privkey.c_str(), + password.c_str()); + if (ret == 0) + authenticated = true; + else + Debug::debug()->dbg("id_dsa: " + "libssh2_userauth_publickey_fromfile() failed with "+ + Stringutil::number2string(ret) + "."); + } + + // RSA + (pubkey = homedir).appendPath(".ssh").appendPath("id_rsa.pub"); + (privkey = homedir).appendPath(".ssh").appendPath("id_rsa"); + if (!authenticated && pubkey.exists() && privkey.exists()) { + Debug::debug()->dbg("Using private key %s and public key %s", + privkey.c_str(), pubkey.c_str()); + + ret = libssh2_userauth_publickey_fromfile(m_sshSession, + username.c_str(), pubkey.c_str(), privkey.c_str(), + password.c_str()); + if (ret == 0) + authenticated = true; + else + Debug::debug()->dbg("id_rsa: " + "libssh2_userauth_publickey_fromfile() failed with "+ + Stringutil::number2string(ret) + "."); + } + + // password + if (!authenticated) { + Debug::debug()->dbg("Using password auth"); + + ret = libssh2_userauth_password(m_sshSession, username.c_str(), + password.c_str()); + if (ret == 0) + authenticated = true; + else + Debug::debug()->dbg("libssh2_userauth_password() failed with "+ + Stringutil::number2string(ret) + "."); + } + + if (!authenticated) { + close(); + throw KError("SSH authentication failed."); + } + + // SFTP session + m_sftp = libssh2_sftp_init(m_sshSession); + if (!m_sftp) { + close(); + throw KError("libssh2_sftp_init() failed with "+ + Stringutil::number2string(ret) + "."); + } + + FilePath fp = parser.getPath(); + mkdir(fp.appendPath(subdir), true); +} + +/* -------------------------------------------------------------------------- */ +SFTPTransfer::~SFTPTransfer() + throw () +{ + Debug::debug()->trace("SFTPTransfer::~SFTPTransfer()"); + + close(); +} + +// ----------------------------------------------------------------------------- +bool SFTPTransfer::exists(const string &file) + throw (KError) +{ + Debug::debug()->trace("SFTPTransfer::exists(%s)", file.c_str()); + + LIBSSH2_SFTP_ATTRIBUTES attrs; + int ret = libssh2_sftp_stat(m_sftp, file.c_str(), &attrs); + + if (ret != 0) { + int errorcode = libssh2_sftp_last_error(m_sftp); + if (errorcode == LIBSSH2_FX_NO_SUCH_FILE) + return false; + else + throw KSFTPError("libssh2_sftp_stat on " + file + " failed.", + errorcode); + } + + return true; +} + +// ----------------------------------------------------------------------------- +void SFTPTransfer::mkdir(const FilePath &dir, bool recursive) + throw (KError) +{ + Debug::debug()->trace("SFTPTransfer::mkdir(%s, %d)", + dir.c_str(), int(recursive)); + + if (!recursive) { + if (!exists(dir)) { + int ret = libssh2_sftp_mkdir(m_sftp, dir.c_str(), 0755); + if (ret != 0) + throw KSFTPError("mkdir of " + dir + " failed.", + libssh2_sftp_last_error(m_sftp)); + } + } else { + string directory = dir; + + // remove trailing '/' if there are any + while (directory[directory.size()-1] == '/') + directory = directory.substr(0, directory.size()-1); + + string::size_type current_slash = 0; + + while (true) { + current_slash = directory.find('/', current_slash+1); + if (current_slash == string::npos) { + mkdir(directory, false); + break; + } + + mkdir(directory.substr(0, current_slash), false); + } + } +} + +/* -------------------------------------------------------------------------- */ +void SFTPTransfer::perform(DataProvider *dataprovider, + const StringVector &target_files, + bool *directSave) + throw (KError) +{ + Debug::debug()->trace("SFTPTransfer::perform(%p, [ \"%s\"%s ])", + dataprovider, target_files.front().c_str(), + target_files.size() > 1 ? ", ..." : ""); + + bool prepared = false; + if (directSave) + *directSave = false; + + RootDirURLVector &urlv = getURLVector(); + const RootDirURL &parser = urlv.front(); + + LIBSSH2_SFTP_HANDLE *handle = NULL; + FilePath file = parser.getPath(); + file.appendPath(getSubDir()).appendPath(target_files.front()); + + Debug::debug()->dbg("Using target file %s.", file.c_str()); + + try { + handle = libssh2_sftp_open(m_sftp, file.c_str(), + LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, 0644); + if (!handle) + throw KSFTPError("Cannot create file " + file + " remotely.", + libssh2_sftp_last_error(m_sftp)); + + dataprovider->prepare(); + prepared = true; + + while (true) { + size_t read_data = dataprovider->getData(m_buffer, BUFSIZ); + + // finished? + if (read_data == 0) + break; + + size_t ret = libssh2_sftp_write(handle, m_buffer, read_data); + if (ret != read_data) + throw KSFTPError("SFTPTransfer::perform: " + "libssh2_sftp_write() failed.", + libssh2_sftp_last_error(m_sftp)); + } + } catch (...) { + if (handle) + libssh2_sftp_close(handle); + close(); + if (prepared) + dataprovider->finish(); + throw; + } + + if (handle) + libssh2_sftp_close(handle); + dataprovider->finish(); +} + + +/* -------------------------------------------------------------------------- */ +void SFTPTransfer::close() + throw () +{ + Debug::debug()->trace("SFTPTransfer::close()"); + + if (m_sshSession) { + libssh2_session_disconnect(m_sshSession, "Normal Shutdown."); + libssh2_session_free(m_sshSession); + m_sshSession = NULL; + } + delete m_socket; + m_socket = NULL; +} + +#endif // HAVE_LIBSSH2 + +//}}} --- /dev/null +++ b/kdumptool/sshtransfer.h @@ -0,0 +1,134 @@ +/* + * (c) 2015, Petr Tesarik <ptesarik@suse.cz>, 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. + */ +#ifndef SSHTRANSFER_H +#define SSHTRANSFER_H + +#include "global.h" +#include "stringutil.h" +#include "fileutil.h" +#include "rootdirurl.h" +#include "process.h" +#include "socket.h" +#include "transfer.h" + +#if HAVE_LIBSSH2 +# include <libssh2.h> +# include <libssh2_sftp.h> +#endif + +//{{{ SSHTransfer -------------------------------------------------------------- + +/** + * Transfers a file to SSH (upload). + */ +class SSHTransfer : public URLTransfer { + + public: + + /** + * Creates a SSHTransfer object. + * + * @exception KError when initialising the underlying library fails + */ + SSHTransfer(const RootDirURLVector &urlv, const std::string &subdir) + throw (KError); + + /** + * Destroys a SSHTransfer object. + */ + ~SSHTransfer() + throw (); + + /** + * Transfers the file. + * + * @see Transfer::perform() + */ + void perform(DataProvider *dataprovider, + const StringVector &target_files, + bool *directSave) + throw (KError); + + private: + char m_buffer[BUFSIZ]; + + StringVector makeArgs(std::string const &remote); +}; + +//}}} +//{{{ SFTPTransfer ------------------------------------------------------------- + +#if HAVE_LIBSSH2 + +/** + * Transfers a file to SFTP (upload). + */ +class SFTPTransfer : public URLTransfer { + + public: + + /** + * Creates a SFTPTransfer object. + * + * @exception KError when initialising the underlying library fails + */ + SFTPTransfer(const RootDirURLVector &urlv, const std::string &subdir) + throw (KError); + + /** + * Destroys a SFTPTransfer object. + */ + ~SFTPTransfer() + throw (); + + /** + * Transfers the file. + * + * @see Transfer::perform() + */ + void perform(DataProvider *dataprovider, + const StringVector &target_files, + bool *directSave) + throw (KError); + + protected: + void close() + throw (); + + void mkdir(const FilePath &dir, bool recursive) + throw (KError); + + bool exists(const std::string &file) + throw (KError); + + private: + LIBSSH2_SESSION *m_sshSession; + LIBSSH2_SFTP *m_sftp; + Socket *m_socket; + char m_buffer[BUFSIZ]; + +}; + +#endif // HAVE_LIBSSH2 + +//}}} + +#endif /* SSHTRANSFER_H */ + +// vim: set sw=4 ts=4 fdm=marker et: :collapseFolds=1: --- a/kdumptool/transfer.cc +++ b/kdumptool/transfer.cc @@ -26,10 +26,6 @@ #include <cstring> #include <curl/curl.h> -#if HAVE_LIBSSH2 -# include <libssh2.h> -# include <libssh2_sftp.h> -#endif #include "dataprovider.h" #include "global.h" @@ -39,9 +35,8 @@ #include "util.h" #include "fileutil.h" #include "stringutil.h" -#include "socket.h" #include "configuration.h" -#include "process.h" +#include "sshtransfer.h" using std::fopen; using std::fread; @@ -479,431 +474,6 @@ void FTPTransfer::open(DataProvider *dat } //}}} -//{{{ SFTPTransfer ------------------------------------------------------------- - -#if HAVE_LIBSSH2 - -/* -------------------------------------------------------------------------- */ -SFTPTransfer::SFTPTransfer(const RootDirURLVector &urlv, - const std::string &subdir) - throw (KError) - : URLTransfer(urlv, subdir), - m_sshSession(NULL), m_sftp(NULL), m_socket(NULL) -{ - if (urlv.size() > 1) - cerr << "WARNING: First dump target used; rest ignored." << endl; - const RootDirURL &parser = urlv.front(); - - Debug::debug()->trace("SFTPTransfer::SFTPTransfer(%s)", - parser.getURL().c_str()); - - m_sshSession = libssh2_session_init(); - if (!m_sshSession) - throw KError("libssh2_session_init() failed."); - - // set blocking - libssh2_session_set_blocking(m_sshSession, 1); - - // get the correct port - int port = parser.getPort(); - if (port <= 0) - port = Socket::DP_SSH; - - // create the socket and connect - m_socket = new Socket(parser.getHostname(), port, Socket::ST_TCP); - int fd = m_socket->connect(); - - // start it up - int ret = libssh2_session_startup(m_sshSession, fd); - if (ret != 0) { - close(); - throw KError("libssh2_session_startup() failed with "+ - Stringutil::number2string(ret) +"."); - } - - // get the hostkey fingerprints - const char *hostsha1 = - libssh2_hostkey_hash(m_sshSession, LIBSSH2_HOSTKEY_HASH_SHA1); - Debug::debug()->info - ("SSH SHA1 fingerprint: %s", - Stringutil::bytes2hexstr(hostsha1, SHA1SUM_LENGTH, true).c_str()); - - const char *hostmd5 = - libssh2_hostkey_hash(m_sshSession, LIBSSH2_HOSTKEY_HASH_MD5); - Debug::debug()->info - ("SSH MD5 fingerprint: %s", - Stringutil::bytes2hexstr(hostmd5, MD5SUM_LENGTH, true).c_str()); - -#if HAVE_LIBSSL - // check the fingerprints if possible - Configuration *config = Configuration::config(); - const string &hostkey = config->KDUMP_HOST_KEY.value(); - - if (!hostkey.empty() && hostkey != "*") { - char expectmd5[MD5SUM_LENGTH]; - char expectsha1[SHA1SUM_LENGTH]; - Stringutil::digest_base64(hostkey.c_str(), hostkey.size(), - expectmd5, expectsha1); - - if (memcmp(hostsha1, expectsha1, SHA1SUM_LENGTH)) - throw KError("Target host key SHA1 fingerprint mismatch!"); - Debug::debug()->info("SHA1 fingerprint matches"); - - if (memcmp(hostmd5, expectmd5, MD5SUM_LENGTH)) - throw KError("Target host key MD5 fingerprint mismatch!"); - Debug::debug()->info("MD5 fingerprint matches"); - } else - cerr << "WARNING: SSH host key accepted without checking!" << endl; -#endif // HAVE_LIBSSL - - // SSH authentication - bool authenticated = false; - - // username and password - string username = parser.getUsername(); - string password = parser.getPassword(); - - // public and private key - string homedir = getenv("HOME"); - FilePath pubkey; - FilePath privkey; - - // DSA - (pubkey = homedir).appendPath(".ssh").appendPath("id_dsa.pub"); - (privkey = homedir).appendPath(".ssh").appendPath("id_dsa"); - if (!authenticated && pubkey.exists() && privkey.exists()) { - Debug::debug()->dbg("Using private key %s and public key %s", - privkey.c_str(), pubkey.c_str()); - - ret = libssh2_userauth_publickey_fromfile(m_sshSession, - username.c_str(), pubkey.c_str(), privkey.c_str(), - password.c_str()); - if (ret == 0) - authenticated = true; - else - Debug::debug()->dbg("id_dsa: " - "libssh2_userauth_publickey_fromfile() failed with "+ - Stringutil::number2string(ret) + "."); - } - - // RSA - (pubkey = homedir).appendPath(".ssh").appendPath("id_rsa.pub"); - (privkey = homedir).appendPath(".ssh").appendPath("id_rsa"); - if (!authenticated && pubkey.exists() && privkey.exists()) { - Debug::debug()->dbg("Using private key %s and public key %s", - privkey.c_str(), pubkey.c_str()); - - ret = libssh2_userauth_publickey_fromfile(m_sshSession, - username.c_str(), pubkey.c_str(), privkey.c_str(), - password.c_str()); - if (ret == 0) - authenticated = true; - else - Debug::debug()->dbg("id_rsa: " - "libssh2_userauth_publickey_fromfile() failed with "+ - Stringutil::number2string(ret) + "."); - } - - // password - if (!authenticated) { - Debug::debug()->dbg("Using password auth"); - - ret = libssh2_userauth_password(m_sshSession, username.c_str(), - password.c_str()); - if (ret == 0) - authenticated = true; - else - Debug::debug()->dbg("libssh2_userauth_password() failed with "+ - Stringutil::number2string(ret) + "."); - } - - if (!authenticated) { - close(); - throw KError("SSH authentication failed."); - } - - // SFTP session - m_sftp = libssh2_sftp_init(m_sshSession); - if (!m_sftp) { - close(); - throw KError("libssh2_sftp_init() failed with "+ - Stringutil::number2string(ret) + "."); - } - - FilePath fp = parser.getPath(); - mkdir(fp.appendPath(subdir), true); -} - -/* -------------------------------------------------------------------------- */ -SFTPTransfer::~SFTPTransfer() - throw () -{ - Debug::debug()->trace("SFTPTransfer::~SFTPTransfer()"); - - close(); -} - -// ----------------------------------------------------------------------------- -bool SFTPTransfer::exists(const string &file) - throw (KError) -{ - Debug::debug()->trace("SFTPTransfer::exists(%s)", file.c_str()); - - LIBSSH2_SFTP_ATTRIBUTES attrs; - int ret = libssh2_sftp_stat(m_sftp, file.c_str(), &attrs); - - if (ret != 0) { - int errorcode = libssh2_sftp_last_error(m_sftp); - if (errorcode == LIBSSH2_FX_NO_SUCH_FILE) - return false; - else - throw KSFTPError("libssh2_sftp_stat on " + file + " failed.", - errorcode); - } - - return true; -} - -// ----------------------------------------------------------------------------- -void SFTPTransfer::mkdir(const FilePath &dir, bool recursive) - throw (KError) -{ - Debug::debug()->trace("SFTPTransfer::mkdir(%s, %d)", - dir.c_str(), int(recursive)); - - if (!recursive) { - if (!exists(dir)) { - int ret = libssh2_sftp_mkdir(m_sftp, dir.c_str(), 0755); - if (ret != 0) - throw KSFTPError("mkdir of " + dir + " failed.", - libssh2_sftp_last_error(m_sftp)); - } - } else { - string directory = dir; - - // remove trailing '/' if there are any - while (directory[directory.size()-1] == '/') - directory = directory.substr(0, directory.size()-1); - - string::size_type current_slash = 0; - - while (true) { - current_slash = directory.find('/', current_slash+1); - if (current_slash == string::npos) { - mkdir(directory, false); - break; - } - - mkdir(directory.substr(0, current_slash), false); - } - } -} - -/* -------------------------------------------------------------------------- */ -void SFTPTransfer::perform(DataProvider *dataprovider, - const StringVector &target_files, - bool *directSave) - throw (KError) -{ - Debug::debug()->trace("SFTPTransfer::perform(%p, [ \"%s\"%s ])", - dataprovider, target_files.front().c_str(), - target_files.size() > 1 ? ", ..." : ""); - - bool prepared = false; - if (directSave) - *directSave = false; - - RootDirURLVector &urlv = getURLVector(); - const RootDirURL &parser = urlv.front(); - - LIBSSH2_SFTP_HANDLE *handle = NULL; - FilePath file = parser.getPath(); - file.appendPath(getSubDir()).appendPath(target_files.front()); - - Debug::debug()->dbg("Using target file %s.", file.c_str()); - - try { - handle = libssh2_sftp_open(m_sftp, file.c_str(), - LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, 0644); - if (!handle) - throw KSFTPError("Cannot create file " + file + " remotely.", - libssh2_sftp_last_error(m_sftp)); - - dataprovider->prepare(); - prepared = true; - - while (true) { - size_t read_data = dataprovider->getData(m_buffer, BUFSIZ); - - // finished? - if (read_data == 0) - break; - - size_t ret = libssh2_sftp_write(handle, m_buffer, read_data); - if (ret != read_data) - throw KSFTPError("SFTPTransfer::perform: " - "libssh2_sftp_write() failed.", - libssh2_sftp_last_error(m_sftp)); - } - } catch (...) { - if (handle) - libssh2_sftp_close(handle); - close(); - if (prepared) - dataprovider->finish(); - throw; - } - - if (handle) - libssh2_sftp_close(handle); - dataprovider->finish(); -} - - -/* -------------------------------------------------------------------------- */ -void SFTPTransfer::close() - throw () -{ - Debug::debug()->trace("SFTPTransfer::close()"); - - if (m_sshSession) { - libssh2_session_disconnect(m_sshSession, "Normal Shutdown."); - libssh2_session_free(m_sshSession); - m_sshSession = NULL; - } - delete m_socket; - m_socket = NULL; -} - -#endif // HAVE_LIBSSH2 - -//}}} -//{{{ SSHTransfer ------------------------------------------------------------- - -/* -------------------------------------------------------------------------- */ -SSHTransfer::SSHTransfer(const RootDirURLVector &urlv, - const std::string &subdir) - throw (KError) - : URLTransfer(urlv, subdir) -{ - if (urlv.size() > 1) - cerr << "WARNING: First dump target used; rest ignored." << endl; - const RootDirURL &target = urlv.front(); - - Debug::debug()->trace("SSHTransfer::SSHTransfer(%s)", - target.getURL().c_str()); - - string remote; - FilePath fp = target.getPath(); - fp.appendPath(getSubDir()); - remote.assign("mkdir -p ").append(fp); - - SubProcess p; - p.spawn("ssh", makeArgs(remote)); - int status = p.wait(); - if (status != 0) - throw KError("SSHTransfer::SSHTransfer: ssh command failed" - " with status " + Stringutil::number2string(status)); -} - -/* -------------------------------------------------------------------------- */ -SSHTransfer::~SSHTransfer() - throw () -{ - Debug::debug()->trace("SSHTransfer::~SSHTransfer()"); -} - -/* -------------------------------------------------------------------------- */ -void SSHTransfer::perform(DataProvider *dataprovider, - const StringVector &target_files, - bool *directSave) - throw (KError) -{ - Debug::debug()->trace("SSHTransfer::perform(%p, [ \"%s\"%s ])", - dataprovider, target_files.front().c_str(), - target_files.size() > 1 ? ", ..." : ""); - - bool prepared = false; - if (directSave) - *directSave = false; - - RootDirURLVector &urlv = getURLVector(); - const RootDirURL &target = urlv.front(); - - FilePath fp = target.getPath(); - fp.appendPath(getSubDir()).appendPath(target_files.front()); - - string remote; - remote.assign("dd of=").append(fp).append("-incomplete"); - remote.append(" && mv ").append(fp).append("-incomplete ").append(fp); - Debug::debug()->dbg("Remote command: %s", remote.c_str()); - - SubProcess p; - p.setPipeDirection(STDIN_FILENO, SubProcess::ParentToChild); - p.spawn("ssh", makeArgs(remote)); - - int fd = p.getPipeFD(STDIN_FILENO); - try { - dataprovider->prepare(); - prepared = true; - - while (true) { - size_t read_data = dataprovider->getData(m_buffer, BUFSIZ); - - // finished? - if (read_data == 0) - break; - - char *p = m_buffer; - while (read_data) { - ssize_t ret = write(fd, p, read_data); - - if (ret < 0) - throw KSystemError("SSHTransfer::perform: write failed", - errno); - read_data -= ret; - p += ret; - } - } - } catch (...) { - close(fd); - if (prepared) - dataprovider->finish(); - throw; - } - close(fd); - - dataprovider->finish(); - int status = p.wait(); - if (status != 0) - throw KError("SSHTransfer::perform: ssh command failed" - " with status " + Stringutil::number2string(status)); -} - -StringVector SSHTransfer::makeArgs(std::string const &remote) -{ - const RootDirURL &target = getURLVector().front(); - StringVector ret; - - ret.push_back("-F"); - ret.push_back("/kdump/.ssh/config"); - - ret.push_back("-l"); - ret.push_back(target.getUsername()); - - int port = target.getPort(); - if (port != -1) { - ret.push_back("-p"); - ret.push_back(Stringutil::number2string(port)); - } - - ret.push_back(target.getHostname()); - ret.push_back(remote); - - return ret; -} - -//}}} //{{{ NFSTransfer -------------------------------------------------------------- // ----------------------------------------------------------------------------- --- a/kdumptool/transfer.h +++ b/kdumptool/transfer.h @@ -23,16 +23,11 @@ #include <cstdarg> #include <curl/curl.h> -#if HAVE_LIBSSH2 -# include <libssh2.h> -# include <libssh2_sftp.h> -#endif #include "global.h" #include "stringutil.h" #include "fileutil.h" #include "rootdirurl.h" -#include "socket.h" class DataProvider; @@ -252,102 +247,6 @@ class FTPTransfer : public URLTransfer { }; //}}} -//{{{ SFTPTransfer ------------------------------------------------------------- - -#if HAVE_LIBSSH2 - -/** - * Transfers a file to SFTP (upload). - */ -class SFTPTransfer : public URLTransfer { - - public: - - /** - * Creates a SFTPTransfer object. - * - * @exception KError when initialising the underlying library fails - */ - SFTPTransfer(const RootDirURLVector &urlv, const std::string &subdir) - throw (KError); - - /** - * Destroys a SFTPTransfer object. - */ - ~SFTPTransfer() - throw (); - - /** - * Transfers the file. - * - * @see Transfer::perform() - */ - void perform(DataProvider *dataprovider, - const StringVector &target_files, - bool *directSave) - throw (KError); - - protected: - void close() - throw (); - - void mkdir(const FilePath &dir, bool recursive) - throw (KError); - - bool exists(const std::string &file) - throw (KError); - - private: - LIBSSH2_SESSION *m_sshSession; - LIBSSH2_SFTP *m_sftp; - Socket *m_socket; - char m_buffer[BUFSIZ]; - -}; - -#endif // HAVE_LIBSSH2 - -//}}} -//{{{ SSHTransfer -------------------------------------------------------------- - -/** - * Transfers a file to SSH (upload). - */ -class SSHTransfer : public URLTransfer { - - public: - - /** - * Creates a SSHTransfer object. - * - * @exception KError when initialising the underlying library fails - */ - SSHTransfer(const RootDirURLVector &urlv, const std::string &subdir) - throw (KError); - - /** - * Destroys a SSHTransfer object. - */ - ~SSHTransfer() - throw (); - - /** - * Transfers the file. - * - * @see Transfer::perform() - */ - void perform(DataProvider *dataprovider, - const StringVector &target_files, - bool *directSave) - throw (KError); - - private: - char m_buffer[BUFSIZ]; - - StringVector makeArgs(std::string const &remote); -}; - -//}}} //{{{ NFSTransfer ------------------------------------------------------------- /**
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor