Снова рекурсивный конвейер в Unix. Часть 2 - PullRequest
0 голосов
/ 04 декабря 2018

Я знаю, что эта тема была опубликована довольно часто, но я хочу взять ее в другом направлении.Я хотел бы написать программу, которая имеет функциональность конвейерной оболочки, например, cmd1 |cmd2 |cmd3 трубопроводов и перенаправлений.Я прочитал страницы типа , , , и , для справки.И эти решения прекрасно работают для «горизонтальной конвейеризации», но я бы хотел реализовать ее «вертикально».Для того, чтобы моя оболочка была вертикальной, каждый процесс 'команда' должен иметь своего родителя (предыдущая команда).Таким образом, каждая команда, которая должна быть выполнена, порождается из предыдущей.Проблема, с которой я столкнулся, заключается в том, что когда я выполняю рекурсию в потомке (а не в родителе, как в примерах), программа выполняется нормально, но затем зависает, и я должен нажать Enter, чтобы перекомпоновать мою оболочку.Мне любопытно, почему это не так и как это исправить.

static void exec_pipeline(size_t pos, int in_fd) {
    // Invalid Pipe has issues
    if (newargv[pipe_commands[pos+1]] == NULL)
        report_error_and_exit("Invalid pipe");
/* last command, pipe_command conatins indices of commands to execute */
    if (pipe_commands[pos + 1] == 0) { 
        redirect(in_fd, STDIN_FILENO); /* read from in_fd, write to STDOUT */
        execvp(newargv[pipe_commands[pos]], newargv + pipe_commands[pos]);
        report_error_and_exit("execvp last command");
    }
    else { /* $ <in_fd cmds[pos] >fd[1] | <fd[0] cmds[pos+1] ... */
        int fd[2]; /* output pipe */
        if (pipe(fd) == -1)
            report_error_and_exit("pipe");
        switch(fork()) {
            case -1:
                report_error_and_exit("fork");
            case 0: /* parent: execute the rest of the commands */
                CHK(close(fd[1])); /* unused */
                CHK(close(in_fd)); /* unused */
                exec_pipeline(pos + 1, fd[0]); /* execute the rest */
            default: /* child: execute current command `cmds[pos]` */
                child = 1;
                CHK(close(fd[0])); /* unused */
                redirect(in_fd, STDIN_FILENO);  /* read from in_fd */
                redirect(fd[1], STDOUT_FILENO); /* write to fd[1] */
                execvp(newargv[pipe_commands[pos]], newargv + pipe_commands[pos]);
                report_error_and_exit("execvp");

        }
    }
}
void report_error_and_exit(const char *msg) {
    perror(msg);
    (child ? _exit : exit)(EXIT_FAILURE);
}

/* move oldfd to newfd */
void redirect(int oldfd, int newfd) {
    if (oldfd != newfd) {
        if (dup2(oldfd, newfd) != -1)
            CHK(close(oldfd));
        else
            report_error_and_exit("dup2");
    }
}

CHK очень похож на assert, определен в файле с именем CHK.h и выглядит так, если вам интересно:

  do {if((x) == -1)\
   {fprintf(stderr,"In file %s, on line %d:\n",__FILE__,__LINE__);\
    fprintf(stderr,"errno = %d\n",errno);\
    perror("Exiting because");\
    exit(1);\
   }\
 } while(0)

1 Ответ

0 голосов
/ 09 декабря 2018

Разобрался!Таким образом, проблема заключалась в том, что при вертикальной реализации последней выполняемой командой была команда «cmd3», которой должна была быть команда «cmd1».Не идеальное решение, но работает.В основном просто перевернул направление строительства трубы.Это решение все еще имеет некоторые проблемы с файловыми дескрипторами, передаваемыми при вводе.

static void exec_pipe(size_t pos, int in_fd) {
    // Invalid Pipe has issues
    if (newargv[pipe_commands[pos+1]] == NULL) {
        report_error_and_exit("Invalid pipe");
    }
    if (pipe_commands[pos + 1] == 0) { /* last command */
        redirect(in_fd, STDOUT_FILENO); /* read from in_fd, write to STDOUT */
        execvp(newargv[pipe_commands[PIPE_FLAG-pos]], newargv + pipe_commands[PIPE_FLAG-pos]);
        report_error_and_exit("execvp last command");
    } else { /* $ <in_fd cmds[pos] >fd[1] | <fd[0] cmds[pos+1] ... */
        int fd[2]; /* output pipe */
        if (pipe(fd) == -1)
            report_error_and_exit("pipe");
        switch(fork()) {
            case -1:
                report_error_and_exit("fork");
            case 0: /* child: execute the rest of the commands */
                CHK(close(fd[0])); /* unused */
                CHK(close(in_fd)); /* unused */
                exec_pipe(pos + 1, fd[1]); /* execute the rest */
            default: /* parent: execute current command `cmds[pos]` */
                child = 1;
                CHK(close(fd[1])); /* unused */
                redirect(in_fd, STDOUT_FILENO);  /* read from in_fd */
                redirect(fd[0], STDIN_FILENO); /* write to fd[0] */
                execvp(newargv[pipe_commands[PIPE_FLAG-pos]], newargv + pipe_commands[PIPE_FLAG-pos]);
                report_error_and_exit("execvp");
        }
    }
}

void pipeHelper() {
    pid_t dad;
    (void) fflush(stdin);
    (void) fflush(stdout);

    // Check for successful fork
    if ((dad = fork()) < 0)
        report_error_and_exit("fork");
    else if (dad == 0) {
        // Catch input redirect
        // Copy input file description to standard in descriptor then close
        if (IN_FLAG == 1)
            redirect(input_file_description, STDIN_FILENO);
        // Catch output redirect
        // Copy output file description to standard out descriptor then close
        if (OUT_FLAG == 1)
            redirect(output_file_description, STDOUT_FILENO);
        // Catch input redirect
        if (HEREIS_FLAG > 0 && BAIL_FLAG == 0)
            redirect(hereis_file_description, STDIN_FILENO);
        // Redirect to /dev/null
        if (AMP_FLAG != 0 && IN_FLAG == 0)
            redirect(devnull_file_description, STDIN_FILENO);
        exec_pipe(0, STDIN_FILENO);
        //exec_pipeline(0, STDIN_FILENO);
    } else {
        if (AMP_FLAG != 0) {
            (void) printf("%s [%d]\n", newargv[0], dad);
            AMP_FLAG = 0;
        } else {
            for (;;) {
                pid_t pid;
                pid = wait(NULL);
                if (pid == dad)
                    break;
            }
        }
    }
}
...