соединение нескольких процессов с каналами, как в оболочке "prog1 | prog2 | prog3" - PullRequest
0 голосов
/ 26 мая 2019

Я пытаюсь написать простую оболочку (просто пытаюсь понять, как работают оболочки).Первая часть (анализ аргументов командной строки) работает нормально, но я не могу заставить работать вторую часть (выполнение команды).

Я пытаюсь создать пару каналов для каждых двух последовательныхпрограммы.Текущая команда записывает в pdes [0], а следующая читает из pdes [1];Поскольку я создаю несколько процессов в цикле, переменная с именем prev_out используется для запоминания конца чтения предыдущей команды в списке.Первая команда в списке читает свой ввод из стандартного ввода, а не из канала.Аналогично, последняя программа также записывает свои выходные данные в стандартный вывод, а не в канал.

         pipe1      pipe2
          *  *      *  *
         *    *    *    *
 --> CMD1      CMD2      CMD3 --> stdout

Что-то похожее на приведенную выше схему.Каждая команда записывает в pdes [0] и читает соответствующие pdes [1].

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <assert.h>

#include <unistd.h>
#include <sys/wait.h>

#define MAXLINE     255
#define MAXARG      32
#define MAXNCMD     16

    extern char   **environ;

    int
    main(int argc, char *argv[])
    {
        char           *cmds[MAXNCMD][MAXARG];
        char        line     [MAXLINE + 1];
        pid_t       childs  [MAXNCMD];
        char           *cmdcur, *argcur;
        char           *linecp;
        int         c        , st;
        int         i        , j, k;
        int         prev_in  , prev_out;

        for (;;) {
            printf("%% ");

            i = 0;

            while ('\n' != (c = getc(stdin)) && i < MAXLINE) {
                if (c == EOF)
                    exit(EXIT_SUCCESS);
                /* NOTREACHED */
                line[i++] = c;
            }
            line[i] = 0;    /* null-terminate */

            if (0 == strncmp(line, "exit", 4)) {
                exit(EXIT_SUCCESS);
                /* NOTREACHED */
            }
            if (0 == strncmp(line, "cd ", 3)) {
                if (-1 == chdir(line + 3)) {
                    perror("chdir()");
                }
                continue;
            }
            linecp = line;
            j = 0;
            k = 0;

            while (NULL != (cmdcur = strsep(&linecp, "|"))) {

                while (*cmdcur == ' ')
                    cmdcur++;

                k = 0;
                while (NULL != (argcur = strsep(&cmdcur, " "))) {

                    while (*argcur == ' ')
                        argcur++;

                    if (NULL == (cmds[j][k] = malloc(strlen(argcur) + 1))) {
                        perror("malloc()");
                        exit(EXIT_FAILURE);
                    }
                    strncpy(cmds[j][k], argcur, strlen(argcur));
                    k++;

                    if (k == MAXARG) {
                        fprintf(stderr, "%s: Too many args\n", argv[0]);
                        exit(EXIT_FAILURE);
                    }   /* NOTREACHED */
                }
                cmds[j][k] = NULL;
                j++;

                if (j == MAXNCMD) {
                    fprintf(stderr, "%s: Too many args\n", argv[0]);
                    exit(EXIT_FAILURE);
                    /* NOTREACHED */
                }
            }

            *cmds[j] = NULL;

            int         nc = j;

            for (int m = 0; m < nc; m++) {

                int         pdes      [2];
                if (-1 == pipe(pdes)) {
                    perror("pipe()");
                    exit(EXIT_FAILURE);
                }
                if (-1 == (childs[m] = fork())) {
                    perror("fork()");
                    exit(EXIT_FAILURE);
                }
                prev_out = pdes[1];
                if (0 == childs[m]) {
                    /* child */
                    if (0 == m) {
                        close(STDOUT_FILENO); /* the first process in the pipe group needs
                        dup(pdes[0]);          * only to set its stdout, the next process
                        prev_out = pdes[1];    * will use the other end */
                    } else if (m == (nc - 1)) {
                        close(STDIN_FILENO);  /* the last process only needs to set its stdin
                        dup(prev_out);         * it will use termical as stdout by default */
                    } else {
                        close(STDIN_FILENO);  /* inner processes should set both stdin and stdout */
                        dup(prev_out);
                        close(STDOUT_FILENO);
                        dup(pdes[0]);
                        prev_out = pdes[1];
                    }

                    if (-1 == execvp(cmds[i][0], cmds[i])) {
                        perror("execvp()");
                        exit(EXIT_FAILURE);
                    }
                } else if (childs[m] > 0) {
                    if (childs[m] != wait(NULL)) {
                        perror("wait()");
                        exit(EXIT_FAILURE);
                    }
                }
            }
        }

        return 0;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...