Пример C Unix Pipes - PullRequest
       15

Пример C Unix Pipes

4 голосов
/ 30 января 2011

Попытка реализовать оболочку, в основном, трубопроводную.Я написал этот тестовый пример, который я ожидаю просто передать ls в wc ... он определенно не работает так, как ожидалось.Он печатает ls на терминал, а затем печатает исчерпанную память.Я очень потерян в том, как это исправить и заставить его работать.find_path работает во всех моих тестах.

Edit - я должен использовать execv для проекта, это классная вещь, но я попробовал его с execvp на всякий случай, и он делает точно то же самое.Также это всего лишь пример, тест, чтобы понять, почему он не работает, я вызываю fork дважды для обеих команд и waitpid, потому что мне больше нечего делать.

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
int find_path(char* execname, char** dst)
{        
        char *path = getenv("PATH");
        path = strdup(path);
        char *pos;
        path = strtok_r(path, ":", &pos);
        char *originalpath  = path;
        do
        {
                char* test = (char*)calloc(strlen(path) + strlen(execname) + 2, sizeof(char));
                test = strcpy(test, path);
                int testlen = strlen(test);
                (*(test+testlen)) = '/';
                strcpy(test + testlen + 1,execname);
                struct stat buf;
                int result = stat(test, &buf);
                if (result == 0)
                {
                        *dst = test;
                        free (originalpath);
                        return 1;
                }
                else
                {
                        free(test);
                }

        } while ((path = strtok_r(NULL, ":", &pos)) != NULL);
        free(originalpath);
        return 0;
}

int main()
{
    char *cmd1 = "ls";
    char *cmd2 = "wc";
    int filedes[2];
    pipe(filedes);
    char** argv = (char**)calloc(1, sizeof(char*)); 
    argv[0] = (char*)malloc(sizeof(char*));
    argv[0] = NULL;

    pid_t pid = fork();
    if (pid == 0)
    {
        char *path;
                find_path(cmd1, &path);
        dup2(filedes[1],stdout);

        execv(path,argv); 
    }
    pid = fork();
    if (pid == 0)
    {
        dup2(filedes[0], stdin);
        char *path;
        find_path(cmd2, &path);
        execv(path, argv);

    }
    else
        waitpid(pid);

}

Ответы [ 2 ]

8 голосов
/ 30 января 2011

Часто, когда сложно отладить программу, лучше всего немного ее упростить, чтобы устранить источники ошибок.Вот ваша программа, упрощенная для удаления find_path в качестве источника ошибок:

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

int main(void)
{
    int filedes[2];
    pipe(filedes);

    /* Run LS. */
    pid_t pid = fork();
    if (pid == 0) {
        /* Set stdout to the input side of the pipe, and run 'ls'. */
        dup2(filedes[1], 1);
        char *argv[] = {"ls", NULL};
        execv("/bin/ls", argv);
    } else {
        /* Close the input side of the pipe, to prevent it staying open. */
        close(filedes[1]);
    }

    /* Run WC. */
    pid = fork();
    if (pid == 0) {
        dup2(filedes[0], 0);
        char *argv[] = {"wc", NULL};
        execv("/usr/bin/wc", argv);
    }

    /* Wait for WC to finish. */
    waitpid(pid);
}

Это должно вести себя так, как вы ожидаете.

Во время упрощения появилось несколько ошибок:

  • argv[] не был настроен правильно, в частности, argv [0] был установлен в NULL;
  • Программа не закрывала входную сторону канала, который былдано ls.Когда ls закончился, канал не был закрыт (потому что процесс wc все еще имел его открытым), не давая возможности wc когда-либо завершиться.
  • Программа путала значения stdout иstdin (типа FILE*) с номерами файловых дескрипторов 0 и 1 (используется dup, pipe и т. Д.)
1 голос
/ 30 января 2011

Вы можете многое сделать для улучшения этого кода (например, если разбить его на более мелкие функции, это будет началом), но я подозреваю, что проблема с нехваткой памяти связана с кодом в find_path (), которого вы могли бы полностью избежать,используя execvp , который найдет исполняемый файл, используя для вас стандартный механизм PATH.Вероятно, было бы неплохо установить обработчик сигнала с помощью sigaction для обработки SIGCHLD и вызвать waitpid из обработчика сигнала вместо простого вызова ad-hoc waitpid (), как вы делаете,Вы, кажется, разветвляетесь больше, чем хотите, и вы не проверяете ошибки.Надеюсь, что эти предложения помогут.

...