Warning, file /plasma/drkonqi/src/main.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /***************************************************************** 0002 * drkonqi - The KDE Crash Handler 0003 * 0004 * SPDX-FileCopyrightText: 2000-2003 Hans Petter Bieker <bieker@kde.org> 0005 * SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org> 0006 * 0007 * SPDX-License-Identifier: BSD-2-Clause 0008 *****************************************************************/ 0009 0010 #include <cstdlib> 0011 #include <unistd.h> 0012 0013 #include <QIcon> 0014 0015 #include <KAboutData> 0016 #include <KConfigGroup> 0017 #include <KLocalizedString> 0018 #include <KSharedConfig> 0019 #include <QCommandLineParser> 0020 #include <QDebug> 0021 #include <QFile> 0022 #include <QTemporaryFile> 0023 0024 #include <QDBusConnection> 0025 #include <QDBusInterface> 0026 #include <QDBusReply> 0027 0028 #include <config-drkonqi.h> 0029 0030 #ifdef Q_OS_MACOS 0031 #include <KWindowSystem> 0032 #endif 0033 0034 #include "backtracegenerator.h" 0035 #include "config-drkonqi.h" 0036 #include "debuggermanager.h" 0037 #include "drkonqi.h" 0038 #include "drkonqidialog.h" 0039 #include "statusnotifier.h" 0040 0041 static const char version[] = PROJECT_VERSION; 0042 0043 namespace 0044 { 0045 // Clean on-disk data before quitting. This ought to only happen if we are 0046 // certain that the user doesn't want the crash to appear again. 0047 void cleanupAfterUserQuit() 0048 { 0049 DrKonqi::cleanupBeforeQuit(); 0050 qApp->quit(); 0051 } 0052 0053 void openDrKonqiDialog() 0054 { 0055 auto *w = new DrKonqiDialog(); 0056 QObject::connect(qApp, &QCoreApplication::aboutToQuit, w, &QObject::deleteLater); 0057 QObject::connect(w, &DrKonqiDialog::rejected, qApp, &cleanupAfterUserQuit); 0058 w->show(); 0059 #ifdef Q_OS_MACOS 0060 KWindowSystem::forceActiveWindow(w->winId()); 0061 #endif 0062 } 0063 0064 void requestDrKonqiDialog(bool restarted, bool interactionAllowed) 0065 { 0066 auto *statusNotifier = new StatusNotifier(); 0067 statusNotifier->setActivationAllowed(interactionAllowed); 0068 if (interactionAllowed) { 0069 statusNotifier->show(); 0070 } 0071 if (!restarted) { 0072 statusNotifier->notify(); 0073 } 0074 QObject::connect(statusNotifier, &StatusNotifier::expired, qApp, &cleanupAfterUserQuit); 0075 QObject::connect(statusNotifier, &StatusNotifier::activated, &openDrKonqiDialog); 0076 } 0077 0078 bool isShuttingDown() 0079 { 0080 if (QDBusConnection::sessionBus().isConnected()) { 0081 QDBusInterface remoteApp(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QStringLiteral("org.kde.KSMServerInterface")); 0082 0083 QDBusReply<bool> reply = remoteApp.call(QStringLiteral("isShuttingDown")); 0084 return reply.isValid() ? reply.value() : false; 0085 } 0086 return false; 0087 } 0088 } 0089 0090 int main(int argc, char *argv[]) 0091 { 0092 #ifndef Q_OS_WIN // krazy:exclude=cpp 0093 // Drop privs. 0094 setgid(getgid()); 0095 if (setuid(getuid()) < 0 && geteuid() != getuid()) { 0096 exit(255); 0097 } 0098 #endif 0099 0100 QApplication app(argc, argv); 0101 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0102 app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); 0103 #endif 0104 KLocalizedString::setApplicationDomain("drkonqi5"); 0105 0106 // Prevent KApplication from setting the crash handler. We will set it later... 0107 setenv("KDE_DEBUG", "true", 1); 0108 // Session management is not needed, do not even connect in order to survive longer than ksmserver. 0109 unsetenv("SESSION_MANAGER"); 0110 0111 KAboutData aboutData(QStringLiteral("drkonqi"), 0112 i18n("The KDE Crash Handler"), 0113 QString::fromLatin1(version), 0114 i18n("The KDE Crash Handler gives the user feedback " 0115 "if a program has crashed."), 0116 KAboutLicense::GPL, 0117 i18n("(C) 2000-2018, The DrKonqi Authors")); 0118 aboutData.addAuthor(i18nc("@info:credit", "Hans Petter Bieker"), QString(), QStringLiteral("bieker@kde.org")); 0119 aboutData.addAuthor(i18nc("@info:credit", "Dario Andres Rodriguez"), QString(), QStringLiteral("andresbajotierra@gmail.com")); 0120 aboutData.addAuthor(i18nc("@info:credit", "George Kiagiadakis"), QString(), QStringLiteral("gkiagia@users.sourceforge.net")); 0121 aboutData.addAuthor(i18nc("@info:credit", "A. L. Spehr"), QString(), QStringLiteral("spehr@kde.org")); 0122 KAboutData::setApplicationData(aboutData); 0123 app.setWindowIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug"), app.windowIcon())); 0124 0125 QCommandLineParser parser; 0126 aboutData.setupCommandLine(&parser); 0127 0128 const QCommandLineOption signalOption(QStringLiteral("signal"), i18nc("@info:shell", "The signal <number> that was caught"), QStringLiteral("number")); 0129 const QCommandLineOption appNameOption(QStringLiteral("appname"), i18nc("@info:shell", "<Name> of the program"), QStringLiteral("name")); 0130 const QCommandLineOption appPathOption(QStringLiteral("apppath"), i18nc("@info:shell", "<Path> to the executable"), QStringLiteral("path")); 0131 const QCommandLineOption appVersionOption(QStringLiteral("appversion"), i18nc("@info:shell", "The <version> of the program"), QStringLiteral("version")); 0132 const QCommandLineOption bugAddressOption(QStringLiteral("bugaddress"), i18nc("@info:shell", "The bug <address> to use"), QStringLiteral("address")); 0133 const QCommandLineOption programNameOption(QStringLiteral("programname"), i18nc("@info:shell", "Translated <name> of the program"), QStringLiteral("name")); 0134 const QCommandLineOption productNameOption(QStringLiteral("productname"), i18nc("@info:shell", "Bugzilla product name"), QStringLiteral("name")); 0135 const QCommandLineOption pidOption(QStringLiteral("pid"), i18nc("@info:shell", "The <PID> of the program"), QStringLiteral("pid")); 0136 const QCommandLineOption startupIdOption(QStringLiteral("startupid"), i18nc("@info:shell", "Startup <ID> of the program"), QStringLiteral("id")); 0137 const QCommandLineOption kdeinitOption(QStringLiteral("kdeinit"), i18nc("@info:shell", "The program was started by kdeinit")); 0138 const QCommandLineOption saferOption(QStringLiteral("safer"), i18nc("@info:shell", "Disable arbitrary disk access")); 0139 const QCommandLineOption restartedOption(QStringLiteral("restarted"), i18nc("@info:shell", "The program has already been restarted")); 0140 const QCommandLineOption keepRunningOption(QStringLiteral("keeprunning"), 0141 i18nc("@info:shell", 0142 "Keep the program running and generate " 0143 "the backtrace at startup")); 0144 const QCommandLineOption threadOption(QStringLiteral("thread"), i18nc("@info:shell", "The <thread id> of the failing thread"), QStringLiteral("threadid")); 0145 const QCommandLineOption dialogOption(QStringLiteral("dialog"), i18nc("@info:shell", "Do not show a notification but launch the debug dialog directly")); 0146 0147 parser.addOptions({signalOption, 0148 appNameOption, 0149 appPathOption, 0150 appVersionOption, 0151 bugAddressOption, 0152 programNameOption, 0153 productNameOption, 0154 pidOption, 0155 startupIdOption, 0156 kdeinitOption, 0157 saferOption, 0158 restartedOption, 0159 keepRunningOption, 0160 threadOption, 0161 dialogOption}); 0162 0163 // Add all unknown options but make sure to print a warning. 0164 // This enables older DrKonqi's to run by newer KCrash instances with 0165 // possibly different/new options. 0166 // KCrash can always send all options it knows to send and be sure that 0167 // DrKonqi will not explode on them. If an option is not known here it's 0168 // either too old or too new. 0169 // 0170 // To implement this smartly we'll ::parse all arguments, and then ::process 0171 // them again once we have injected no-op options for all unknown ones. 0172 // This allows ::process to still do common argument handling for --version 0173 // as well as standard error handling. 0174 if (!parser.parse(app.arguments())) { 0175 const QStringList unknownOptionNames = parser.unknownOptionNames(); 0176 for (const QString &option : unknownOptionNames) { 0177 qWarning() << "Unknown option" << option << " - ignoring it."; 0178 parser.addOption(QCommandLineOption(option)); 0179 } 0180 } 0181 0182 parser.process(app); 0183 aboutData.processCommandLine(&parser); 0184 0185 DrKonqi::setSignal(parser.value(signalOption).toInt()); 0186 DrKonqi::setAppName(parser.value(appNameOption)); 0187 DrKonqi::setAppPath(parser.value(appPathOption)); 0188 DrKonqi::setAppVersion(parser.value(appVersionOption)); 0189 DrKonqi::setBugAddress(parser.value(bugAddressOption)); 0190 DrKonqi::setProgramName(parser.value(programNameOption)); 0191 DrKonqi::setProductName(parser.value(productNameOption)); 0192 DrKonqi::setPid(parser.value(pidOption).toInt()); 0193 DrKonqi::setKdeinit(parser.isSet(kdeinitOption)); 0194 DrKonqi::setSafer(parser.isSet(saferOption)); 0195 DrKonqi::setRestarted(parser.isSet(restartedOption)); 0196 DrKonqi::setKeepRunning(parser.isSet(keepRunningOption)); 0197 DrKonqi::setThread(parser.value(threadOption).toInt()); 0198 DrKonqi::setStartupId(parser.value(startupIdOption)); 0199 auto forceDialog = parser.isSet(dialogOption); 0200 0201 if (!DrKonqi::init()) { 0202 return 1; 0203 } 0204 0205 app.setQuitOnLastWindowClosed(false); 0206 0207 const bool restarted = parser.isSet(restartedOption); 0208 0209 // Whether the user should be encouraged to file a bug report 0210 const bool interactionAllowed = KConfigGroup(KSharedConfig::openConfig(), "General").readEntry("InteractionAllowed", true); 0211 const bool shuttingDown = isShuttingDown(); 0212 0213 // For automatically restarted services or during shutdown, do nothing in case no interaction is allowed 0214 if (!forceDialog && !interactionAllowed && (restarted || shuttingDown)) { 0215 return 0; 0216 } 0217 0218 // if no notification service is running (eg. shell crashed, or other desktop environment) 0219 // and we didn't auto-restart the app, open DrKonqi dialog instead of showing an SNI 0220 // and emitting a desktop notification. 0221 if (shuttingDown) { 0222 DrKonqi::shutdownSaveReport(); 0223 } else if (forceDialog || (!restarted && !StatusNotifier::notificationServiceRegistered())) { 0224 openDrKonqiDialog(); 0225 } else { 0226 requestDrKonqiDialog(restarted, interactionAllowed); 0227 } 0228 0229 return app.exec(); 0230 }