Оболочка Unix, реализующая Cat in C - проблема с файловым дескриптором - PullRequest
0 голосов
/ 25 февраля 2011

Я почти закончил практическую реализацию оболочки Unix, за исключением того, что у меня возникла проблема с реализацией cat, когда ее вывод в файл;IE: cat foo.txt > bar.txt - вывод содержимого foo в bar.

Давайте начнем с основной функции , а затем я определю подметоды:

int main(int argc, char **argv)
{           
    printf("[MYSHELL] $ ");

    while (TRUE) {
        user_input = getchar();
        switch (user_input) {

            case EOF:
                exit(-1);

            case '\n':
                printf("[MYSHELL] $ ");
                break;

            default:
                // parse input into cmd_argv - store # commands in cmd_argc
                handle_user_input();

                //determine input and execute foreground/background process
                execute_command();
        }
        background = 0;
    }
    printf("\n[MYSHELL] $ ");
    return 0;    
}

handle_user_input просто заполняет массив cmd_argv для выполнения user_input, удаляет > и устанавливает флаг output, если пользователь желает вывести нафайл.Это основа этого метода:

while (buffer_pointer != NULL) { 
        cmd_argv[cmd_argc] = buffer_pointer;
        buffer_pointer = strtok(NULL, " ");

        if(strcmp(cmd_argv[cmd_argc], ">") == 0){
            printf("\nThere was a '>' in %s @ index: %d for buffer_pointer: %s \n", *cmd_argv,cmd_argc,buffer_pointer);
            cmd_argv[cmd_argc] = strtok(NULL, " ");
            output = 1;
        }

        cmd_argc++;

        if(output){
            filename = buffer_pointer;
            printf("The return of handling input for filename %s =  %s + %s \n", buffer_pointer, cmd_argv[0], cmd_argv[1]); 
            return;
        }        
}

execute_command затем вызывается, интерпретируя теперь заполненный cmd_argv.Просто чтобы дать вам представление о большой картине.Очевидно, что ни один из этих случаев не совпадает, и метод create_process вызывается:

int execute_command()
{
    if (strcmp("pwd", cmd_argv[0]) == 0){
        printf("%s\n",getenv("PATH"));  
        return 1;
    }
    else if(strcmp("cd", cmd_argv[0]) == 0){
        change_directory();
        return 1;        
    }
    else if (strcmp("jobs", cmd_argv[0]) == 0){
        display_job_list();
        return 1;   
    }
    else if (strcmp("kill", cmd_argv[0]) == 0){
        kill_job();
    }
    else if (strcmp("EOT", cmd_argv[0]) == 0){
        exit(1);
    }
    else if (strcmp("exit", cmd_argv[0]) == 0){
        exit(-1);
    }
    else{
        create_process();
        return;
    }
}

Довольно прямо, верно?


create_process - вот где у меня возникают проблемы.

void create_process()
{
    status = 0;
    int pid = fork();
    background = 0;

    if (pid == 0) {
        // child process
        if(output){
            printf("Output set in create process to %d\n",output);
            output = 0;
            int output_fd = open(filename, O_RDONLY);
            printf("Output desc = %d\n",output_fd);
            if (output_fd > -1) {
                dup2(output_fd, STDOUT_FILENO);
                close(output_fd);
            } else {
                perror("open");
            }
        }
        printf("Executing command, but STDOUT writing to COMMAND PROMPT instead of FILE - as I get the 'open' error above \n");
        execvp(*cmd_argv,cmd_argv);
        // If an error occurs, print error and exit
        fprintf (stderr, "unknown command: %s\n", cmd_argv[0]);
        exit(0);
    } else {
        // parent process, waiting on child process
            waitpid(pid, &status, 0);
        if (status != 0)
            fprintf  (stderr, "error: %s exited with status code %d\n", cmd_argv[0], status);
    }
    return;
}

Мой напечатанный output_fd = -1, и мне удается получить perror("open") внутри остального, заявив: open: No such file or directory.Затем он печатает, что это "writing to COMMAND PROMPT instead of FILE", как я отображаю на консоли.Затем выполняет execvp, который обрабатывает cat foo.txt, но выводит его на консоль вместо файла.

Я понимаю, что это не должно быть в данный момент, так как наличие output_fd = -1 нежелательно и должно возвращать другое значение;но я не могу понять, как правильно использовать файловые дескрипторы, чтобы открыть новый / существующий файл с cat foo.txt > bar.txt и записать в него, как WELL AS GET BACK на стандартный ввод командной строки.

Мне удалось вывести в файл, но потом я потерял вернувшийся правильный stdin.Может ли кто-нибудь, пожалуйста, направить меня сюда?Я чувствую, что иду по кругу из-за чего-то глупого, я делаю что-то не так или оглядываюсь.

Любая помощь очень ценится.

Ответы [ 2 ]

2 голосов
/ 25 февраля 2011

Почему вы используете O_RDONLY, если хотите записать в файл? Я думаю, что вы должны использовать что-то вроде:

int output_fd = open(filename, O_WRONLY|O_CREAT, 0666);

(0666 - для установки прав доступа при создании).

И, очевидно, если вы не можете открыть перенаправленный файл, вы не должны запускать команду.

1 голос
/ 25 февраля 2011

Во-первых, я заметил, что вы открыли файл O_RDONLY.Не будет работать так хорошо для вывода!

Во-вторых, основной процесс перенаправления вывода:

  • открытый файл для записи
  • dup stdout, так что вы можете сохранитькопия при необходимости.то же самое с stderr при перенаправлении.
  • fcntl ваш дубликат на CLOEXEC (альтернативно, используйте dup3)
  • файл dup2 на stdout
  • выполните команду

и наконец, вы действительно передаете имена команд как глобальные переменные?Я думаю, что это снова будет преследовать вас, когда вы попытаетесь реализовать cat foo | ( cat bar; echo hi; cat ) > baz или что-то подобное.

...