Multi-line implementation using fork () system call execvp () wait () pipe () - this just doesn't work

I need to implement my shell, which processes several command commands. For example, I need to be able to handle this: ls | grep -i cs340 | sort | uniq | cut -c 5 ls | grep -i cs340 | sort | uniq | cut -c 5 ls | grep -i cs340 | sort | uniq | cut -c 5 . I assume the problem is that I am not passing the output of the previous command to the input of the next command. When I execute my code, it gives no result. I am using this pseudo code:

 for cmd in cmds if there is a next cmd pipe(new_fds) fork if child if there is a previous cmd dup2(old_fds[0], 0) close(old_fds[0]) close(old_fds[1]) if there is a next cmd close(new_fds[0]) dup2(new_fds[1], 1) close(new_fds[1]) exec cmd || die else if there is a previous cmd close(old_fds[0]) close(old_fds[1]) if there is a next cmd old_fds = new_fds if there are multiple cmds close(old_fds[0]) close(old_fds[1]) 

Here is the source code for a function that processes multiple channels.

 void execute_multiple_commands(struct command ** commands_to_exec, int num_commands_p) { pid_t status; int i, err; int new_fd[2], old_fd[2]; pid_t pid, cpid; // creating child process if ( (cpid = fork()) == -1) { fprintf(stderr, "Could not create child process, exiting..."); exit(1); } if (cpid == 0) // in the child process we run multiple pipe handling { for (i = 0; i < num_commands_p; i++) // for each cmd in cmds { if (i+1 < num_commands_p) // if there is next cmd pipe(new_fd); if ( (pid = fork()) == -1) { fprintf(stderr, "Could not create child process, exiting..."); exit(1); } if (pid == 0) // if child { if (i != 0) // if there is a previous command { dup2(old_fd[0], 0); // setting up old_pipe to input into the child close(old_fd[0]); close(old_fd[1]); } if (i+1 < num_commands_p) // if there is a next cmd { close(new_fd[0]); // setting up new_pipe to get output from child dup2(new_fd[1], 1); close(new_fd[1]); err = execvp(commands_to_exec[i]->args[0], commands_to_exec[i]->args); status = err; exit(err); } } else { waitpid(pid, &status, 0); if (status == -1) exit(1); if (i != 0) // if there a previous command { close(old_fd[0]); close(old_fd[1]); } if (i+1 < num_commands_p) // if there a next cmd { old_fd[0] = new_fd[0]; old_fd[1] = new_fd[1]; } exit(0); } // end if } // end for if (i) // if there a multiple commands { close(old_fd[0]); close(old_fd[1]); } } else // in the parent process we are waiting for child to handle multiple pipes waitpid(cpid, &status, 0); } 

The execvp() function takes an array of structures. Ive checked all my parsing part and it works great. This is the execute_multiple_commands() function that I'm having problems with.

Here is the code for the struct:

 // name: command // desc: holds one command (meaning that it can be // more than one token in that command) // "ls -la" will be an example of one command // holds num of tokens in command array struct command { char ** args; int num_args; }; 
+4
source share
1 answer

I propose a new strategy, R2:

 function do(commands) if commands is of size 1 exec commands[0] || die split commands into c1 (first command) c2 (the rest of them) open if fork close input end of pipe dup output of pipe to stdin do (c2) || die close output end of pipe dup input of pipe to stdout exec c1 || die 

Using a recursive function, especially if you maintain a list, will help you simplify your logic. You do not need to worry about the depth of the stack here, as all of your address space will be rewritten anyway.

In other news from the man page :

After successfully returning from one of these system calls, the old and new file descriptors can be used interchangeably. They refer to the same description of an open file (see open (2)) and thus separate the file offset and file status flags; for example, if the file offset using lseek (2) on one of the descriptors, the offset also changes for the other.

What does it mean when you say you close both ends of the pipe? You really close it - this is AND the standard input / output that your program intends to use.

-> MUTCH LATER EDIT <-

As Jonathan Leffler noted, the above information is correct. I confirmed this with the following program:

 #include <unistd.h> int main(){ dup2(0, 7); write(7, "Hey, 1\n", 7); close(0); write(7, "Hey, 2\n", 7); close(7); write(7, "Hey, 3\n", 7); } 

The result is the following:

 $ gcc dup2Test.c && ./a.out Hey, 1 Hey, 2 

Thanks Jonathan!

+2
source

Source: https://habr.com/ru/post/1440866/


All Articles