File indexing completed on 2024-05-05 17:39:48

0001 /*
0002     KSysGuard, the KDE System Guard
0003 
0004     SPDX-FileCopyrightText: 1999-2001 Chris Schlaeger <cs@kde.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 
0008 */
0009 
0010 #include <QDebug>
0011 #include <klocalizedstring.h>
0012 #include <kprocess.h>
0013 #include <kshell.h>
0014 
0015 #include "SensorManager.h"
0016 #include "ksgrd_debug.h"
0017 
0018 #include "SensorShellAgent.h"
0019 
0020 using namespace KSGRD;
0021 
0022 SensorShellAgent::SensorShellAgent(SensorManager *sm)
0023     : SensorAgent(sm)
0024     , mDaemon(nullptr)
0025 {
0026 }
0027 
0028 SensorShellAgent::~SensorShellAgent()
0029 {
0030     if (mDaemon) {
0031         mDaemon->write("quit\n", sizeof("quit\n") - 1);
0032         mDaemon->disconnect();
0033         mDaemon->waitForFinished();
0034         delete mDaemon;
0035         mDaemon = nullptr;
0036     }
0037 }
0038 
0039 bool SensorShellAgent::start(const QString &host, const QString &shell, const QString &command, int)
0040 {
0041     mDaemon = new KProcess();
0042     mDaemon->setOutputChannelMode(KProcess::SeparateChannels);
0043     mRetryCount = 3;
0044     setHostName(host);
0045     mShell = shell;
0046     mCommand = command;
0047 
0048     connect(mDaemon, SIGNAL(error(QProcess::ProcessError)), SLOT(daemonError(QProcess::ProcessError)));
0049     connect(mDaemon, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(daemonExited(int, QProcess::ExitStatus)));
0050     connect(mDaemon.data(), &QProcess::readyReadStandardOutput, this, &SensorShellAgent::msgRcvd);
0051     connect(mDaemon.data(), &QProcess::readyReadStandardError, this, &SensorShellAgent::errMsgRcvd);
0052 
0053     if (!command.isEmpty()) {
0054         *mDaemon << KShell::splitArgs(command);
0055     } else
0056         *mDaemon << mShell << hostName() << QStringLiteral("ksysguardd");
0057     mDaemon->start();
0058 
0059     return true;
0060 }
0061 
0062 void SensorShellAgent::hostInfo(QString &shell, QString &command, int &port) const
0063 {
0064     shell = mShell;
0065     command = mCommand;
0066     port = -1;
0067 }
0068 
0069 void SensorShellAgent::msgRcvd()
0070 {
0071     QByteArray buffer = mDaemon->readAllStandardOutput();
0072     mRetryCount = 3; // we received an answer, so reset our retry count back to 3
0073     processAnswer(buffer.constData(), buffer.size());
0074 }
0075 
0076 void SensorShellAgent::errMsgRcvd()
0077 {
0078     const QByteArray buffer = mDaemon->readAllStandardOutput();
0079 
0080     // Because we read the error buffer in chunks, we may not have a proper utf8 string.
0081     // We should never get input over stderr anyway, so no need to worry too much about it.
0082     // But if this is extended, we will need to handle this better
0083     const QString buf = QString::fromUtf8(buffer);
0084 
0085     qCDebug(LIBKSYSGUARD_KSGRD) << "SensorShellAgent: Warning, received text over stderr!"
0086                                 << "\n"
0087                                 << buf;
0088 }
0089 
0090 void SensorShellAgent::daemonExited(int exitCode, QProcess::ExitStatus exitStatus)
0091 {
0092     Q_UNUSED(exitCode);
0093     qCDebug(LIBKSYSGUARD_KSGRD) << "daemon exited, exit status " << exitStatus;
0094     if (mRetryCount-- <= 0 || (mDaemon->start(), !mDaemon->waitForStarted())) {
0095         setDaemonOnLine(false);
0096         if (sensorManager()) {
0097             sensorManager()->disengage(this); // delete ourselves
0098         }
0099     }
0100 }
0101 
0102 void SensorShellAgent::daemonError(QProcess::ProcessError errorStatus)
0103 {
0104     QString error;
0105     switch (errorStatus) {
0106     case QProcess::FailedToStart:
0107         qCDebug(LIBKSYSGUARD_KSGRD) << "failed to run" << mDaemon->program().join(QLatin1Char(' '));
0108         error = i18n("Could not run daemon program '%1'.", mDaemon->program().join(" "));
0109         break;
0110     case QProcess::Crashed:
0111     case QProcess::Timedout:
0112     case QProcess::WriteError:
0113     case QProcess::ReadError:
0114     default:
0115         error = i18n("The daemon program '%1' failed.", mDaemon->program().join(" "));
0116     }
0117     setReasonForOffline(error);
0118     qCDebug(LIBKSYSGUARD_KSGRD) << "Error received " << error << "(" << errorStatus << ")";
0119     setDaemonOnLine(false);
0120     if (sensorManager())
0121         sensorManager()->disengage(this); // delete ourselves
0122 }
0123 bool SensorShellAgent::writeMsg(const char *msg, int len)
0124 {
0125     // write returns -1 on error, in which case we should return false.  true otherwise.
0126     return mDaemon->write(msg, len) != -1;
0127 }