Home > Software design >  Can't quit a fork() when using pipe()
Can't quit a fork() when using pipe()

Time:05-05

I am recreating a complete shell. For that I must simulate "|". To do this, I have to use the dup2(), fork() and pipe() functions.

The code I've had the most success with is this:

int exec_pipe(global *glob, char *commande)
{
    int pipefd[2];
    char **pipe_commandes = my_split(commande, '|');
    char **left = my_str_to_word_array(pipe_commandes[0]);
    char **right = my_str_to_word_array(pipe_commandes[1]);
    int pid = 0;
    int status;


    pipe(pipefd);
    pid = fork();
    if (pid == 0) {
        close(pipefd[1]);
        dup2(pipefd[0], 0);
        close(pipefd[0]);
        glob->commande = right;
        distribe_commande(glob);
        glob->commande = NULL;
    } else {
        close(pipefd[0]);
        dup2(pipefd[1], 1);
        close(pipefd[1]);
        glob->commande = left;
        distribe_commande(glob);
        glob->commande = NULL;
    }
}

The function distribe_commande() leads to a formatting of the command so that it is executed with execve() in this function:

void exec_path_commande(char *path, global *glob)
{
    int pid;
    int status;

    pid = fork();
    if (pid == 0) {
        dup2(glob->fd, glob->origine);
        if (execve(path, glob->commande, glob->env) == -1)
            exit(0);
    } else
        while (waitpid(pid, &status, 0) != -1 && !WIFEXITED(status))
            error_execve(status);

}

Where char *path is the correct formated command.

My probleme is that when I send the commande ls | cat -e the command work :

$~> ls | cat -e
^[[0$
42sh$
build$
CMakeLists.txt$
hello$
include$
Jenkinsfile$
lib$
main.c$
Makefile$
src$

But if I send another command to the programme the | cat -e effect remain even on the prompt and I don't understand why:

$~> ls | cat -e
^[[0$
42sh$
build$
CMakeLists.txt$
hello$
include$
Jenkinsfile$
lib$
main.c$
Makefile$
src$
^[[0;31m^[[1m$^[[0;36m^[[1m~^[[0;32m^[[1m> ^[[0;37m^[[0mls
^[[0$
42sh$
build$
CMakeLists.txt$
hello$
include$
Jenkinsfile$
lib$
main.c$
Makefile$
src$
^[[0;31m^[[1m$^[[0;36m^[[1m~^[[0;32m^[[1m> ^[[0;37m^[[0m

Thanks in advance for your answers.

CodePudding user response:

You are doing dup2 in a wrong place. You also have one fork too many.

A redirect should look like this (outline/pseudocode, not real C code):

fd = open(...)
pid = fork()
if (pid == 0)
   dup2(fd, 1) // redirect the output, just an example
   close(fd)
   exec(...)
wait(...)

Note, dup2 and close are after the fork and before the exec.

A pipeline is two (or more) redirects coordinated via a pipe, so:

pipe(fds)
pid1 = fork()
if (pid1 == 0)
   dup2(fds[0], 0)
   close(fds[0])
   close(fds[1])
   exec(...)

pid2 = fork()
if (pid2 == 0)
   dup2(fds[1], 1)
   close(fds[0])
   close(fds[1])
   exec(...)

wait(...)
wait(...)

Note also both waits are after both execs. If you do it the other way (exec-wait-exec-wait), commands like yes | head will not work.

So you need to refactor exec_path_commande quite a bit.

  • Related