File indexing completed on 2024-05-05 05:34:26

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     }
0058     mDaemon->start();
0059 
0060     return true;
0061 }
0062 
0063 void SensorShellAgent::hostInfo(QString &shell, QString &command, int &port) const
0064 {
0065     shell = mShell;
0066     command = mCommand;
0067     port = -1;
0068 }
0069 
0070 void SensorShellAgent::msgRcvd()
0071 {
0072     QByteArray buffer = mDaemon->readAllStandardOutput();
0073     mRetryCount = 3; // we received an answer, so reset our retry count back to 3
0074     processAnswer(buffer.constData(), buffer.size());
0075 }
0076 
0077 void SensorShellAgent::errMsgRcvd()
0078 {
0079     const QByteArray buffer = mDaemon->readAllStandardOutput();
0080 
0081     // Because we read the error buffer in chunks, we may not have a proper utf8 string.
0082     // We should never get input over stderr anyway, so no need to worry too much about it.
0083     // But if this is extended, we will need to handle this better
0084     const QString buf = QString::fromUtf8(buffer);
0085 
0086     qCDebug(LIBKSYSGUARD_KSGRD) << "SensorShellAgent: Warning, received text over stderr!"
0087                                 << "\n"
0088                                 << buf;
0089 }
0090 
0091 void SensorShellAgent::daemonExited(int exitCode, QProcess::ExitStatus exitStatus)
0092 {
0093     Q_UNUSED(exitCode);
0094     qCDebug(LIBKSYSGUARD_KSGRD) << "daemon exited, exit status " << exitStatus;
0095     if (mRetryCount-- <= 0 || (mDaemon->start(), !mDaemon->waitForStarted())) {
0096         setDaemonOnLine(false);
0097         if (sensorManager()) {
0098             sensorManager()->disengage(this); // delete ourselves
0099         }
0100     }
0101 }
0102 
0103 void SensorShellAgent::daemonError(QProcess::ProcessError errorStatus)
0104 {
0105     QString error;
0106     switch (errorStatus) {
0107     case QProcess::FailedToStart:
0108         qCDebug(LIBKSYSGUARD_KSGRD) << "failed to run" << mDaemon->program().join(QLatin1Char(' '));
0109         error = i18n("Could not run daemon program '%1'.", mDaemon->program().join(" "));
0110         break;
0111     case QProcess::Crashed:
0112     case QProcess::Timedout:
0113     case QProcess::WriteError:
0114     case QProcess::ReadError:
0115     default:
0116         error = i18n("The daemon program '%1' failed.", mDaemon->program().join(" "));
0117     }
0118     setReasonForOffline(error);
0119     qCDebug(LIBKSYSGUARD_KSGRD) << "Error received " << error << "(" << errorStatus << ")";
0120     setDaemonOnLine(false);
0121     if (sensorManager()) {
0122         sensorManager()->disengage(this); // delete ourselves
0123     }
0124 }
0125 
0126 bool SensorShellAgent::writeMsg(const char *msg, int len)
0127 {
0128     // write returns -1 on error, in which case we should return false.  true otherwise.
0129     return mDaemon->write(msg, len) != -1;
0130 }