File indexing completed on 2024-04-21 08:47:48

0001 /*  This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2000 Alexander Neundorf <neundorf@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 #include "kshellcmdexecutor.h"
0007 
0008 #include <sys/time.h>
0009 #include <sys/types.h>
0010 #include <unistd.h>
0011 #include <signal.h>
0012 #include <stdlib.h>
0013 
0014 #include <QSocketNotifier>
0015 #include <QInputDialog>
0016 #include <QFontDatabase>
0017 
0018 #include <KDESu/PtyProcess>
0019 #include <KLocalizedString>
0020 
0021 
0022 KShellCommandExecutor::KShellCommandExecutor(const QString &command, QWidget *parent)
0023     : QTextEdit(parent)
0024     , m_shellProcess(nullptr)
0025     , m_command(command)
0026     , m_readNotifier(nullptr)
0027     , m_writeNotifier(nullptr)
0028 {
0029     setAcceptRichText(false);
0030     setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
0031     setReadOnly(true);
0032 }
0033 
0034 KShellCommandExecutor::~KShellCommandExecutor()
0035 {
0036     if (m_shellProcess != nullptr) {
0037         ::kill(m_shellProcess->pid() + 1, SIGTERM);
0038         delete m_shellProcess;
0039     };
0040 }
0041 
0042 int KShellCommandExecutor::exec()
0043 {
0044     //qCDebug(KONQUEROR_LOG)<<"---------- KShellCommandExecutor::exec()";
0045     setText(QLatin1String(""));
0046     if (m_shellProcess != nullptr) {
0047         ::kill(m_shellProcess->pid(), SIGTERM);
0048         delete m_shellProcess;
0049     };
0050     delete m_readNotifier;
0051     delete m_writeNotifier;
0052 
0053     m_shellProcess = new KDESu::PtyProcess();
0054     m_shellProcess->setTerminal(true);
0055 
0056     QList<QByteArray> args;
0057     args += "-c";
0058     args += m_command.toLocal8Bit();
0059     //qCDebug(KONQUEROR_LOG)<<"------- executing: "<<m_command.toLocal8Bit();
0060 
0061     QByteArray shell(getenv("SHELL"));
0062     if (shell.isEmpty()) {
0063         shell = "sh";
0064     }
0065 
0066     int ret = m_shellProcess->exec(shell, args);
0067     if (ret < 0) {
0068         //qCDebug(KONQUEROR_LOG)<<"could not execute";
0069         delete m_shellProcess;
0070         m_shellProcess = nullptr;
0071         return 0;
0072     }
0073 
0074     m_readNotifier = new QSocketNotifier(m_shellProcess->fd(), QSocketNotifier::Read, this);
0075     m_writeNotifier = new QSocketNotifier(m_shellProcess->fd(), QSocketNotifier::Write, this);
0076     m_writeNotifier->setEnabled(false);
0077     connect(m_readNotifier, &QSocketNotifier::activated, this, &KShellCommandExecutor::readDataFromShell);
0078     connect(m_writeNotifier, &QSocketNotifier::activated, this, &KShellCommandExecutor::writeDataToShell);
0079 
0080     return 1;
0081 }
0082 
0083 void KShellCommandExecutor::readDataFromShell()
0084 {
0085     //qCDebug(KONQUEROR_LOG)<<"--------- reading ------------";
0086     char buffer[16 * 1024];
0087     int bytesRead =::read(m_shellProcess->fd(), buffer, 16 * 1024 - 1);
0088     //0-terminate the buffer
0089     //process exited
0090     if (bytesRead <= 0) {
0091         slotFinished();
0092     } else if (bytesRead > 0) {
0093         //qCDebug(KONQUEROR_LOG)<<"***********************\n"<<buffer<<"###################\n";
0094         buffer[bytesRead] = '\0';
0095         this->append(QString::fromLocal8Bit(buffer));
0096         setAcceptRichText(false);
0097     };
0098 }
0099 
0100 void KShellCommandExecutor::writeDataToShell()
0101 {
0102     //qCDebug(KONQUEROR_LOG)<<"--------- writing ------------";
0103     bool ok;
0104     QString str = QInputDialog::getText(this,
0105                                         QString(),
0106                                         i18n("Input Required:"),
0107                                         QLineEdit::Normal,
0108                                         QString(),
0109                                         &ok);
0110     if (ok) {
0111         QByteArray input = str.toLocal8Bit();
0112         ::write(m_shellProcess->fd(), input.constData(), input.length());
0113         ::write(m_shellProcess->fd(), "\n", 1);
0114     } else {
0115         slotFinished();
0116     }
0117 
0118     if (m_writeNotifier) {
0119         m_writeNotifier->setEnabled(false);
0120     }
0121 }
0122 
0123 void KShellCommandExecutor::slotFinished()
0124 {
0125     setAcceptRichText(false);
0126     if (m_shellProcess != nullptr) {
0127         delete m_readNotifier;
0128         m_readNotifier = nullptr;
0129         delete m_writeNotifier;
0130         m_writeNotifier = nullptr;
0131 
0132         //qCDebug(KONQUEROR_LOG)<<"slotFinished: pid: "<<m_shellProcess->pid();
0133         ::kill(m_shellProcess->pid() + 1, SIGTERM);
0134         ::kill(m_shellProcess->pid(), SIGTERM);
0135     };
0136     delete m_shellProcess;
0137     m_shellProcess = nullptr;
0138     emit finished();
0139 }
0140