1/*
2 Copyright (C) 2009 George Kiagiadakis <gkiagia@users.sourceforge.net>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <config-drkonqi.h>
19
20#include "crashedapplication.h"
21
22#if defined(HAVE_STRSIGNAL) && defined(Q_OS_UNIX)
23# include <clocale>
24# include <cstring>
25# include <cstdlib>
26#else
27# if defined(Q_OS_UNIX)
28# include <signal.h>
29# else
30# include <windows.h>
31# endif
32#endif
33
34#include <KToolInvocation>
35
36CrashedApplication::CrashedApplication(QObject *parent)
37 : QObject(parent), m_restarted(false)
38{
39}
40
41CrashedApplication::~CrashedApplication()
42{
43}
44
45QString CrashedApplication::name() const
46{
47 return m_name;
48}
49
50QFileInfo CrashedApplication::executable() const
51{
52 return m_executable;
53}
54
55QString CrashedApplication::fakeExecutableBaseName() const
56{
57 if (!m_fakeBaseName.isEmpty()) {
58 return m_fakeBaseName;
59 } else {
60 return m_executable.baseName();
61 }
62}
63
64QString CrashedApplication::version() const
65{
66 return m_version;
67}
68
69BugReportAddress CrashedApplication::bugReportAddress() const
70{
71 return m_reportAddress;
72}
73
74int CrashedApplication::pid() const
75{
76 return m_pid;
77}
78
79int CrashedApplication::signalNumber() const
80{
81 return m_signalNumber;
82}
83
84QString CrashedApplication::signalName() const
85{
86#if defined(HAVE_STRSIGNAL) && defined(Q_OS_UNIX)
87 const char * oldLocale = std::setlocale(LC_MESSAGES, NULL);
88 char * savedLocale;
89 if (oldLocale) {
90 savedLocale = strdup(oldLocale);
91 } else {
92 savedLocale = NULL;
93 }
94 std::setlocale(LC_MESSAGES, "C");
95 const char *name = strsignal(m_signalNumber);
96 std::setlocale(LC_MESSAGES, savedLocale);
97 std::free(savedLocale);
98 return QString::fromLocal8Bit(name != NULL ? name : "Unknown");
99#else
100 switch (m_signalNumber) {
101# if defined(Q_OS_UNIX)
102 case SIGILL: return QLatin1String("SIGILL");
103 case SIGABRT: return QLatin1String("SIGABRT");
104 case SIGFPE: return QLatin1String("SIGFPE");
105 case SIGSEGV: return QLatin1String("SIGSEGV");
106 case SIGBUS: return QLatin1String("SIGBUS");
107# else
108 case EXCEPTION_ACCESS_VIOLATION: return QLatin1String("EXCEPTION_ACCESS_VIOLATION");
109 case EXCEPTION_DATATYPE_MISALIGNMENT: return QLatin1String("EXCEPTION_DATATYPE_MISALIGNMENT");
110 case EXCEPTION_BREAKPOINT: return QLatin1String("EXCEPTION_BREAKPOINT");
111 case EXCEPTION_SINGLE_STEP: return QLatin1String("EXCEPTION_SINGLE_STEP");
112 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return QLatin1String("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
113 case EXCEPTION_FLT_DENORMAL_OPERAND: return QLatin1String("EXCEPTION_FLT_DENORMAL_OPERAND");
114 case EXCEPTION_FLT_DIVIDE_BY_ZERO: return QLatin1String("EXCEPTION_FLT_DIVIDE_BY_ZERO");
115 case EXCEPTION_FLT_INEXACT_RESULT: return QLatin1String("EXCEPTION_FLT_INEXACT_RESULT");
116 case EXCEPTION_FLT_INVALID_OPERATION: return QLatin1String("EXCEPTION_FLT_INVALID_OPERATION");
117 case EXCEPTION_FLT_OVERFLOW: return QLatin1String("EXCEPTION_FLT_OVERFLOW");
118 case EXCEPTION_FLT_STACK_CHECK: return QLatin1String("EXCEPTION_FLT_STACK_CHECK");
119 case EXCEPTION_FLT_UNDERFLOW: return QLatin1String("EXCEPTION_FLT_UNDERFLOW");
120 case EXCEPTION_INT_DIVIDE_BY_ZERO: return QLatin1String("EXCEPTION_INT_DIVIDE_BY_ZERO");
121 case EXCEPTION_INT_OVERFLOW: return QLatin1String("EXCEPTION_INT_OVERFLOW");
122 case EXCEPTION_PRIV_INSTRUCTION: return QLatin1String("EXCEPTION_PRIV_INSTRUCTION");
123 case EXCEPTION_IN_PAGE_ERROR: return QLatin1String("EXCEPTION_IN_PAGE_ERROR");
124 case EXCEPTION_ILLEGAL_INSTRUCTION: return QLatin1String("EXCEPTION_ILLEGAL_INSTRUCTION");
125 case EXCEPTION_NONCONTINUABLE_EXCEPTION: return QLatin1String("EXCEPTION_NONCONTINUABLE_EXCEPTION");
126 case EXCEPTION_STACK_OVERFLOW: return QLatin1String("EXCEPTION_STACK_OVERFLOW");
127 case EXCEPTION_INVALID_DISPOSITION: return QLatin1String("EXCEPTION_INVALID_DISPOSITION");
128# endif
129 default: return QLatin1String("Unknown");
130 }
131#endif
132}
133
134bool CrashedApplication::hasBeenRestarted() const
135{
136 return m_restarted;
137}
138
139int CrashedApplication::thread() const
140{
141 return m_thread;
142}
143
144const QDateTime& CrashedApplication::datetime() const
145{
146 return m_datetime;
147}
148
149void CrashedApplication::restart()
150{
151 if (m_restarted) {
152 return;
153 }
154
155 int ret = -1;
156
157 //start the application via kdeinit, as it needs to have a pristine environment and
158 //KProcess::startDetached() can't start a new process with custom environment variables.
159 if (!m_fakeBaseName.isEmpty()) {
160 // if m_fakeBaseName is set, this means m_executable is the path to kdeinit4
161 // so we need to use the fakeBaseName to restart the app
162 ret = KToolInvocation::kdeinitExec(m_fakeBaseName);
163 } else {
164 ret = KToolInvocation::kdeinitExec(m_executable.absoluteFilePath());
165 }
166
167 const bool success = (ret == 0);
168
169 m_restarted = success;
170 emit restarted(success);
171}
172
173QString getSuggestedKCrashFilename(const CrashedApplication* app)
174{
175 QString filename = app->fakeExecutableBaseName() + '-' +
176 app->datetime().toString("yyyyMMdd-hhmmss") +
177 ".kcrash.txt";
178
179 if (filename.contains('/')) {
180 filename = filename.mid(filename.lastIndexOf('/') + 1);
181 }
182
183 return filename;
184}
185
186#include "crashedapplication.moc"
187