File indexing completed on 2024-06-02 05:34:48
0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0002 0003 #include "automaticcoredumpexcavator.h" 0004 0005 #include <fcntl.h> 0006 #include <unistd.h> 0007 0008 #include <chrono> 0009 #include <filesystem> 0010 0011 #include <QDBusConnection> 0012 #include <QDBusConnectionInterface> 0013 #include <QDBusMessage> 0014 #include <QDBusPendingCallWatcher> 0015 #include <QDBusUnixFileDescriptor> 0016 #include <QDebug> 0017 0018 #include "coredumpexcavator.h" 0019 0020 using namespace Qt::StringLiterals; 0021 using namespace std::chrono_literals; 0022 0023 void AutomaticCoredumpExcavator::excavateFrom(const QString &coredumpFilename) 0024 { 0025 if (!m_coreDir) { 0026 m_coreDir = std::make_unique<QTemporaryDir>(QDir::tempPath() + u"/drkonqi-core"_s); 0027 Q_ASSERT(m_coreDir->isValid()); 0028 if (!m_coreDir->isValid()) { 0029 Q_EMIT failed(); 0030 return; 0031 } 0032 // Keep the core to ourself. 0033 std::filesystem::permissions(m_coreDir->path().toStdString(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace); 0034 } 0035 0036 const auto coreFileTarget = m_coreDir->filePath(u"core"_s); 0037 const auto coredumpFileInfo = QFileInfo(coredumpFilename); 0038 0039 if (coredumpFileInfo.isReadable()) { 0040 auto excavator = new CoredumpExcavator(this); 0041 connect(excavator, &CoredumpExcavator::excavated, this, [this, coreFileTarget](int exitCode) { 0042 if (exitCode != 0) { 0043 qWarning() << "Failed to excavate core from file:" << exitCode; 0044 Q_EMIT failed(); 0045 return; 0046 } 0047 Q_EMIT excavated(coreFileTarget); 0048 }); 0049 excavator->excavateFromTo(coredumpFilename, coreFileTarget); 0050 } else { 0051 if (QFile::exists(coreFileTarget)) { 0052 qDebug() << "Core already exists, returning early"; 0053 Q_EMIT excavated(coreFileTarget); 0054 return; 0055 } 0056 0057 auto msg = QDBusMessage::createMethodCall("org.kde.drkonqi"_L1, "/"_L1, "org.kde.drkonqi"_L1, "excavateFromToDirFd"_L1); 0058 0059 int fd = open(qUtf8Printable(m_coreDir->path()), O_RDONLY | O_CLOEXEC | O_DIRECTORY); 0060 if (fd < 0) { 0061 int err = errno; 0062 qWarning() << "Failed to open m_coreDir" << m_coreDir->path() << strerror(err); 0063 Q_EMIT failed(); 0064 return; 0065 } 0066 auto closeFd = qScopeGuard([fd] { 0067 close(fd); 0068 }); 0069 0070 msg << coredumpFileInfo.fileName() << QVariant::fromValue(QDBusUnixFileDescriptor(fd)); 0071 static const auto connection = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "drkonqi-polkit-system-connection"_L1); 0072 connection.interface()->setTimeout(std::chrono::milliseconds(5min).count()); 0073 auto watcher = new QDBusPendingCallWatcher(connection.asyncCall(msg)); 0074 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher, coreFileTarget] { 0075 watcher->deleteLater(); 0076 QDBusReply<QString> reply = *watcher; 0077 qWarning() << reply.isValid() << reply.error() << reply.value(); 0078 if (!reply.isValid() || reply.value().isEmpty()) { 0079 qWarning() << "Failed to excavate core as admin:" << reply.error(); 0080 Q_EMIT failed(); 0081 return; 0082 } 0083 Q_EMIT excavated(coreFileTarget); 0084 }); 0085 } 0086 }