You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
329 lines
8.5 KiB
329 lines
8.5 KiB
/* |
|
Copyright (C) 2009 George Kiagiadakis <gkiagia@users.sourceforge.net> |
|
|
|
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, see <http://www.gnu.org/licenses/>. |
|
|
|
Parts of this code were originally under the following license: |
|
|
|
* Copyright (C) 2000-2003 Hans Petter Bieker <bieker@kde.org> |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
#include "drkonqi.h" |
|
|
|
#include <QtCore/QPointer> |
|
#include <QtCore/QTextStream> |
|
#include <QtCore/QTimerEvent> |
|
#include <QtCore/QTemporaryFile> |
|
#include <QtCore/QDebug> |
|
#include <QtWidgets/QFileDialog> |
|
|
|
#include <KMessageBox> |
|
#include <KCrash> |
|
#include <KLocalizedString> |
|
#include <KJobWidgets> |
|
#include <kio/filecopyjob.h> |
|
|
|
#include "systeminformation.h" |
|
#include "crashedapplication.h" |
|
#include "drkonqibackends.h" |
|
|
|
DrKonqi::DrKonqi() |
|
: m_signal(0) |
|
, m_pid(0) |
|
, m_kdeinit(false) |
|
, m_safer(false) |
|
, m_restarted(false) |
|
, m_keepRunning(false) |
|
, m_thread(0) |
|
{ |
|
m_backend = new KCrashBackend(); |
|
m_systemInformation = new SystemInformation(); |
|
} |
|
|
|
DrKonqi::~DrKonqi() |
|
{ |
|
delete m_systemInformation; |
|
delete m_backend; |
|
} |
|
|
|
//static |
|
DrKonqi *DrKonqi::instance() |
|
{ |
|
static DrKonqi *drKonqiInstance = NULL; |
|
if (!drKonqiInstance) { |
|
drKonqiInstance = new DrKonqi(); |
|
} |
|
return drKonqiInstance; |
|
} |
|
|
|
//based on KCrashDelaySetHandler from kdeui/util/kcrash.cpp |
|
class EnableCrashCatchingDelayed : public QObject |
|
{ |
|
public: |
|
EnableCrashCatchingDelayed() { |
|
startTimer(10000); // 10 s |
|
} |
|
protected: |
|
void timerEvent(QTimerEvent *event) override { |
|
qDebug() << "Enabling drkonqi crash catching"; |
|
KCrash::setDrKonqiEnabled(true); |
|
killTimer(event->timerId()); |
|
this->deleteLater(); |
|
} |
|
}; |
|
|
|
bool DrKonqi::init() |
|
{ |
|
if (!instance()->m_backend->init()) { |
|
cleanup(); |
|
return false; |
|
} else { //all ok, continue initialization |
|
// Set drkonqi to handle its own crashes, but only if the crashed app |
|
// is not drkonqi already. If it is drkonqi, delay enabling crash catching |
|
// to prevent recursive crashes (in case it crashes at startup) |
|
if (crashedApplication()->fakeExecutableBaseName() != QLatin1String("drkonqi")) { |
|
qDebug() << "Enabling drkonqi crash catching"; |
|
KCrash::setDrKonqiEnabled(true); |
|
} else { |
|
new EnableCrashCatchingDelayed; |
|
} |
|
return true; |
|
} |
|
} |
|
|
|
void DrKonqi::cleanup() |
|
{ |
|
delete instance(); |
|
} |
|
|
|
//static |
|
SystemInformation *DrKonqi::systemInformation() |
|
{ |
|
return instance()->m_systemInformation; |
|
} |
|
|
|
//static |
|
DebuggerManager* DrKonqi::debuggerManager() |
|
{ |
|
return instance()->m_backend->debuggerManager(); |
|
} |
|
|
|
//static |
|
CrashedApplication *DrKonqi::crashedApplication() |
|
{ |
|
return instance()->m_backend->crashedApplication(); |
|
} |
|
|
|
//static |
|
void DrKonqi::saveReport(const QString & reportText, QWidget *parent) |
|
{ |
|
if (isSafer()) { |
|
QTemporaryFile tf; |
|
tf.setFileTemplate(QStringLiteral("XXXXXX.kcrash.txt")); |
|
tf.setAutoRemove(false); |
|
|
|
if (tf.open()) { |
|
QTextStream textStream(&tf); |
|
textStream << reportText; |
|
textStream.flush(); |
|
KMessageBox::information(parent, xi18nc("@info", |
|
"Report saved to <filename>%1</filename>.", |
|
tf.fileName())); |
|
} else { |
|
KMessageBox::sorry(parent, i18nc("@info","Could not create a file in which to save the report.")); |
|
} |
|
} else { |
|
QString defname = getSuggestedKCrashFilename(crashedApplication()); |
|
|
|
QPointer<QFileDialog> dlg(new QFileDialog(parent, defname)); |
|
dlg->selectFile(defname); |
|
dlg->setWindowTitle(i18nc("@title:window","Select Filename")); |
|
dlg->setAcceptMode(QFileDialog::AcceptSave); |
|
dlg->setFileMode(QFileDialog::AnyFile); |
|
dlg->setConfirmOverwrite(true); |
|
if (dlg->exec() != QDialog::Accepted) { |
|
return; |
|
} |
|
|
|
if (!dlg) { |
|
//Dialog is invalid, it was probably deleted (ex. via DBus call) |
|
//return and do not crash |
|
return; |
|
} |
|
|
|
QUrl fileUrl; |
|
if(!dlg->selectedUrls().isEmpty()) |
|
fileUrl = dlg->selectedUrls().first(); |
|
delete dlg; |
|
|
|
if (fileUrl.isValid()) { |
|
QTemporaryFile tf; |
|
if (tf.open()) { |
|
QTextStream ts(&tf); |
|
ts << reportText; |
|
ts.flush(); |
|
} else { |
|
KMessageBox::sorry(parent, xi18nc("@info","Cannot open file <filename>%1</filename> " |
|
"for writing.", tf.fileName())); |
|
return; |
|
} |
|
|
|
KIO::FileCopyJob* job = KIO::file_copy(QUrl::fromLocalFile(tf.fileName()), fileUrl); |
|
KJobWidgets::setWindow(job, parent); |
|
if (!job->exec()) { |
|
KMessageBox::sorry(parent, job->errorText()); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void DrKonqi::setSignal(int signal) |
|
{ |
|
instance()->m_signal = signal; |
|
} |
|
|
|
void DrKonqi::setAppName(const QString &appName) |
|
{ |
|
instance()->m_appName = appName; |
|
} |
|
|
|
void DrKonqi::setAppPath(const QString &appPath) |
|
{ |
|
instance()->m_appPath = appPath; |
|
} |
|
|
|
void DrKonqi::setAppVersion(const QString &appVersion) |
|
{ |
|
instance()->m_appVersion = appVersion; |
|
} |
|
|
|
void DrKonqi::setBugAddress(const QString &bugAddress) |
|
{ |
|
instance()->m_bugAddress = bugAddress; |
|
} |
|
|
|
void DrKonqi::setProgramName(const QString &programName) |
|
{ |
|
instance()->m_programName = programName; |
|
} |
|
|
|
void DrKonqi::setPid(int pid) |
|
{ |
|
instance()->m_pid = pid; |
|
} |
|
|
|
void DrKonqi::setKdeinit(bool kdeinit) |
|
{ |
|
instance()->m_kdeinit = kdeinit; |
|
} |
|
|
|
void DrKonqi::setSafer(bool safer) |
|
{ |
|
instance()->m_safer = safer; |
|
} |
|
|
|
void DrKonqi::setRestarted(bool restarted) |
|
{ |
|
instance()->m_restarted = restarted; |
|
} |
|
|
|
void DrKonqi::setKeepRunning(bool keepRunning) |
|
{ |
|
instance()->m_keepRunning = keepRunning; |
|
} |
|
|
|
void DrKonqi::setThread(int thread) |
|
{ |
|
instance()->m_thread = thread; |
|
} |
|
|
|
int DrKonqi::signal() |
|
{ |
|
return instance()->m_signal; |
|
} |
|
|
|
const QString &DrKonqi::appName() |
|
{ |
|
return instance()->m_appName; |
|
} |
|
|
|
const QString &DrKonqi::appPath() |
|
{ |
|
return instance()->m_appPath; |
|
} |
|
|
|
const QString &DrKonqi::appVersion() |
|
{ |
|
return instance()->m_appVersion; |
|
} |
|
|
|
const QString &DrKonqi::bugAddress() |
|
{ |
|
return instance()->m_bugAddress; |
|
} |
|
|
|
const QString &DrKonqi::programName() |
|
{ |
|
return instance()->m_programName; |
|
} |
|
|
|
int DrKonqi::pid() |
|
{ |
|
return instance()->m_pid; |
|
} |
|
|
|
bool DrKonqi::isKdeinit() |
|
{ |
|
return instance()->m_kdeinit; |
|
} |
|
|
|
bool DrKonqi::isSafer() |
|
{ |
|
return instance()->m_safer; |
|
} |
|
|
|
bool DrKonqi::isRestarted() |
|
{ |
|
return instance()->m_restarted; |
|
} |
|
|
|
bool DrKonqi::isKeepRunning() |
|
{ |
|
return instance()->m_keepRunning; |
|
} |
|
|
|
int DrKonqi::thread() |
|
{ |
|
return instance()->m_thread; |
|
}
|
|
|