ich versuche gerade meiner KI das benutzen der Shell bei zu bringen. Dazu muss es aber erst mal eine möglichkeit geben das ein C++ Programm so tun kann als sei es ein normaler Benutzer. Daher die Idee Befehle über eine Umleitung von stdout, stderr und stdin zu steuern.
Leider war mein Versuch nur Teilweise erfolgreich. Solange die Befehle nur an stdout oder stderr ausgeben funktioniert das einwandfrei. Sobald ich aber Befehle wie fdisk benutze blockiert das ganze. Man sieht dann das der Prozess läuft aber die ausgaben lassen sich nicht mehr über die Umgeleitete Pipe lesen.
Hier mal der Konstruktor der die wichtigste arbeit macht. Der übersichtlichkeit halber habe ich die meisten Methoden weg gelassen weil die mit dem Problem nichts zu tun haben.
Code: Alles auswählen
runCommand (std::string strCommand)
{
const int iRead = 0;
const int iWrite = 1;
int pStdout[2];
int pStderr[2];
int pStdin[2];
pid_t pid;
if (pipe(pStdout) != 0 ||
pipe(pStderr) != 0 ||
pipe(pStdin) != 0)
std::cout << "Fehler beim anlegen der pipes" << std::endl;
pid = fork();
if (pid < 0)
pid = pid;
else
if (pid == 0)
{
close (pStdout[iRead]);
close (pStderr[iRead]);
close (pStdin[iWrite]);
dup2(pStdout[iWrite], STDOUT_FILENO);
dup2(pStderr[iWrite], STDERR_FILENO);
dup2(pStdin[iRead], STDIN_FILENO);
close(pStdout[iWrite]);
close(pStderr[iWrite]);
close(pStdin[iRead]);
if (execl("/bin/bash", "bash", "-c", strCommand.c_str (), NULL) == 0)
{
std::cout << "Fehler beim starten des externen Prozesses: " << strerror (errno) << std::endl;
exit (0);
}
std::cout << "In der C++-Klasse runCommand geschehen merkwürdige Dinge ..." << std::endl;
exit(1);
}
close(pStdout[iWrite]);
close(pStderr[iWrite]);
close(pStdin[iRead]);
pIntStreamOut = fdopen(pStdout[0], "r");
if (pIntStreamOut == 0)
{
std::cout << "Fehler beim öffnen von stdout: " << strerror (errno) << std::endl;
exit (0);
}
pIntStreamIn = fdopen(pStdin[1], "w");
if (pIntStreamIn == 0)
{
std::cout << "Fehler beim öffnen von stdin: " << strerror (errno) << std::endl;
exit (0);
}
readStdout ();
}
void sendBefehl (std::string strBefehl)
{
std::cout << "runCommand::sendBefehl: start" << std::endl;
int iCount;
int iRc = fwrite (strBefehl.c_str (), strBefehl.size (), iCount, pIntStreamIn);
if (iRc == 0)
std::cout << "Es wurden keine Daten geschrieben." << std::endl;
}
void readStdout (void)
{
std::cout << "runCommand::readStdout: start" << std::endl;
char* pRc;
for (;;)
{
std::unique_ptr<char> szZeile (new char[1000]);
pRc = fgets (szZeile.get (), 1000, pIntStreamOut);
if (pRc == nullptr)
break;
vecIntStdout.push_back (std::move (szZeile));
}
}
Code: Alles auswählen
// Beispiel wie ich getestet habe.
//runCommand run ("find");
//runCommand run ("fdisk /dev/sda");
//run.sendBefehl ("q\n");
for (auto&& out: *(run.getStdout ()))
{
std::cout << out.get ();
}
Grüße
Alexander