2015-11-13 2 views
1

В настоящее время я пытаюсь создать пользовательскую оболочку для класса. Я могу выполнять команды, выпущенные из этой оболочки, без проблем, но если я подключу свою команду в свою оболочку, я получаю бесконечный цикл. Я не понимаю, почему это может произойти. Пример ниже приведет к бесконечному циклу.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 Я должен отметить, что части этот код был указан в этом классе.

Любая помощь была бы весьма признательна!

+0

Вы дали нам несколько кусочков, но ничего подобного не достаточно, чтобы уверенно ответить на вопрос. Предоставьте нам MCVE для изучения. –

+3

Я могу заметить, однако, что у вас есть проблема с отсутствием ошибок. Например, если 'fgets()' не может прочитать строку (возможно, потому что конец 'stdin' был достигнут), тогда это будет указывать так, возвращая' NULL', но вы не смотрите на этот случай. Аналогично, если ваш 'execvp()' терпит неудачу, то дочерний процесс выпадет из блока 'if', который вы представили, и продолжайте работать как копия родительской оболочки. –

+0

@JohnBollinger благодарит вас за ваше замечание, я думал, что зачистка его до минимального минимума увеличит вероятность ответа - я отправлю MCVE как можно скорее. – Pethor

ответ

3

Код OP только завершает цикл main()do, когда running == 0.

running = 0; происходит только тогда, когда strcmp(command, "exit") == 0 и не ясно, что со строкой разбора, что просто"exit" когда-либо загружены в command. Примечание: command не является чисто инициализированным за каждый вызов handle_command(), а command не обязательно должен быть глобальной переменной.

Настроить код для выхода, когда fgets() возвращает NULL и обрабатывает обработку обзора. Предложить:

do { 
    printf("\n%s %s%s", "SHELL:", cwd, "> "); 
    if (fgets(buffer, sizeof buffer, stdin) == NULL) { 
    break; 
    } 
    // lop off potential end-of-line character(s) 
    buffer[strcspn(buffer,"\r\n")] = '\0'; 
    handle_command(buffer, sizeof buffer); 
} while (running); 
+0

Спасибо, это сделал трюк! Но я думаю, что 'buffer [strcspn (buffer," \ r \ n ")] = '\ 0';' работает не так, как ожидалось, но я нашел свой собственный путь. Большое спасибо за ваши усилия! – Pethor

+1

@Pethor Alternate: http://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input/27729970#27729970 – chux

Смежные вопросы