В настоящее время я пытаюсь создать пользовательскую оболочку для класса. Я могу выполнять команды, выпущенные из этой оболочки, без проблем, но если я подключу свою команду в свою оболочку, я получаю бесконечный цикл. Я не понимаю, почему это может произойти. Пример ниже приведет к бесконечному циклу.C Инфинитный цикл в оболочке после команд конвейера в нем
echo "ls" | ./myshell
Конечно, мне нужно перенаправить выходные данные программ, если произойдет труба внутри команды, например. ls | grep test
. В моей оболочке это работает безупречно. Я использую fork()
, execv()
и, конечно, pipe
+ dup
для перенаправления потоков между дочерними процессами.
Кажется, как будто fgets()
не очистит STDIN_FILENO
от последней выданной команды.
Для команды echo "ls" | ./myshell
моя программа будет сделать следующее: (минимальный рабочий пример)
EDIT: Минимальный рабочий пример
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int running = 1;
int exit_code = 0;
char cwd[256];
char command[256];
char args[10][256];
char buffer[256] __attribute__((aligned(4096)));
void handle_command(char* buffer, int buffer_size)
{
int c = 0;
int argsCount = -1;
int lastIndex = 0;
for (c = 0; c < buffer_size && buffer[c]; c++)
{
if (argsCount > 10)
{
argsCount = 10;
printf("Argument Count is limited to 10 (no dynamic memory allocation) all other arguments will be ignored\n");
break;
}
if (buffer[c] == '\r' || buffer[c] == '\n' || buffer[c] == ' ')
{
if (argsCount == -1)
{
memcpy(command, buffer + lastIndex, c - lastIndex);
command[c - lastIndex] = 0;
}
else
{
memcpy(args[argsCount], buffer + lastIndex, c - lastIndex);
args[argsCount][c - lastIndex] = 0;
}
argsCount++;
lastIndex = c + 1;
}
}
if (strcmp(command, "exit") == 0)
{
c = 4;
while (buffer[c] == ' ')
c++;
exit_code = atoi(&buffer[c]);
printf("Exiting Shell with exit_code %d\n", exit_code);
running = 0;
}
else if (strcmp(command, "") != 0)
{
// -------------- Add structure to commands --------------------------------
struct command_struct{
char *options[10];
} sub_commands[1];
// Simplified code, there would be a dynamic amount of sub_commands
// and further logic to handle pipes and < > >>
// initialize first command, would work dynamically
sub_commands[0].options[0] = command;
sub_commands[0].options[1] = NULL;
int status;
int pid = fork();
if (pid == 0) {
execvp(sub_commands[0].options[0], sub_commands[0].options);
perror("Error: Reached code after execvp\n");
} else if (pid < 0) {
perror("Cannot fork!\n");
}
wait(&status);
}
}
int main(int argc, char *argv[])
{
cwd[0] = '/';
do
{
printf("\n%s %s%s", "SHELL:", cwd, "> ");
fgets(buffer, 255, stdin);
buffer[255] = 0;
handle_command(buffer, 256);
for (size_t a = 0; a < 256; a++)
buffer[a] = 0;
} while (running);
return exit_code;
}
EDIT Я должен отметить, что части этот код был указан в этом классе.
Любая помощь была бы весьма признательна!
Вы дали нам несколько кусочков, но ничего подобного не достаточно, чтобы уверенно ответить на вопрос. Предоставьте нам MCVE для изучения. –
Я могу заметить, однако, что у вас есть проблема с отсутствием ошибок. Например, если 'fgets()' не может прочитать строку (возможно, потому что конец 'stdin' был достигнут), тогда это будет указывать так, возвращая' NULL', но вы не смотрите на этот случай. Аналогично, если ваш 'execvp()' терпит неудачу, то дочерний процесс выпадет из блока 'if', который вы представили, и продолжайте работать как копия родительской оболочки. –
@JohnBollinger благодарит вас за ваше замечание, я думал, что зачистка его до минимального минимума увеличит вероятность ответа - я отправлю MCVE как можно скорее. – Pethor