cmds is a list of commands to call. In my case, I'm tring to call ls | grep c. When I run the program, nothing gets printed. It seems grep is waiting for something?
Note: If I only use ls (via execPipe(cmds,1)), everything works.
What is wrong?
int execPipe(char*** cmds,int len){
int i;
int pipefd[100][2];
for(i = 0; i < len; i++)
pipe(pipefd[i]);
i = 0;
for(i = 0; i < len; i++){
if (fork() == 0){
printf("executing #%d %s\n",i,cmds[i][0]);
//i=0: in=sdtin, out=1
//i=1: in=1,out=3
//i=2: in=3,out=5
//i=len in=len*2-1, out=sdtout
close(pipefd[i][0]);
if(i != 0){
dup2(pipefd[i-1][1],0); //read becomes the write of last one
}
if(i != len-1){
dup2(pipefd[i][1],1); //write becomes pipefd[i][1]
}
execvp(cmds[i][0],cmds[i]);
return EXIT_SUCCESS;
}
close(pipefd[i][0]);
close(pipefd[i][1]);
wait(NULL);
}
return 0;
}
int main(){
char*** cmds = malloc(2*sizeof(char**));
cmds[0] = malloc(2*sizeof(char**));
cmds[0][0] = "ls";
cmds[0][1] = NULL;
cmds[1] = malloc(3*sizeof(char**));
cmds[1][0] = "grep";
cmds[1][1] = "c";
cmds[1][2] = NULL;
execPipe(cmds,2);
return 0;
}
This code works:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static
int execPipe(char ***cmds, int len)
{
int i;
int pids[len];
int pipefd[len][2];
for (i = 0; i < len - 1; i++)
pipe(pipefd[i]);
for (i = 0; i < len; i++)
{
int pid;
if ((pid = fork()) == 0)
{
printf("PID %d: executing #%d %s\n", (int)getpid(), i, cmds[i][0]);
if (i != 0)
{
dup2(pipefd[i - 1][0], 0); // JL: Fix
}
if (i != len - 1)
{
dup2(pipefd[i][1], 1); // write becomes pipefd[i][1]
}
for (int j = 0; j < len - 1; j++) // JL: Fix
{
close(pipefd[j][0]);
close(pipefd[j][1]);
}
execvp(cmds[i][0], cmds[i]);
fprintf(stderr, "Failed to execute command %s\n", cmds[i][0]);
return EXIT_FAILURE;
}
else if (pid < 0)
{
fprintf(stderr, "failed to fork for %s\n", cmds[i][0]);
exit(1);
}
else
pids[i] = pid;
}
for (i = 0; i < len - 1; i++) // JL: Fix
{
close(pipefd[i][0]);
close(pipefd[i][1]);
}
int corpse;
int status;
int kids = len;
while (kids > 0 && (corpse = wait(&status)) > 0)
{
printf("PID %d died with status 0x%.4X\n", corpse, status);
for (i = 0; i < kids; i++)
{
if (pids[i] == corpse)
{
pids[i] = pids[kids-1];
kids--;
break;
}
}
}
return 0;
}
int main(void)
{
char ***cmds = malloc(2 * sizeof(char **));
cmds[0] = malloc(2 * sizeof(char **));
cmds[0][0] = "ls";
cmds[0][1] = NULL;
cmds[1] = malloc(3 * sizeof(char **));
cmds[1][0] = "grep";
cmds[1][1] = "c";
cmds[1][2] = NULL;
execPipe(cmds, 2);
return 0;
}
Comments:
Notice how many close operations there are.
It would be reasonable to factor the close loop into a function that gets called where needed.
You could get away without the first child closing the pipes, but it is silly to break the symmetry.
It is crucial that the parent close the pipes — but only after the pipes are finished with (that is, after all the children are created).
The wait() loop deals with the situation where the parent process had children that it didn't know about that terminate before the children it launches — a rather unusual but far from impossible circumstance. It would be possible simply to wait until all children die, but maybe one of the previously created children isn't going to terminate. The loop waits until all the known children have died and then exits.
A more complex mechanism would only have two pipes open at any one time, even in a 50 process pipeline, rather than opening all 49 pipes at once, but that's a refinement for later.
You should extend this to a 3-process or longer pipeline and check that it works. Possible pipelines include:
who | awk '{print $1}' | sort
who | awk '{print $1}' | sort | uniq -c
who | awk '{print $1}' | sort | uniq -c | sort -n
Beware: the shell removes single quotes.
Related
This is my first question so I apologize if I'm omitting anything important. So I've been working on an assignment that handles piping via forking. My code is pretty messy, littered with printf statements so I see what's going on.
I've looked around online and I think I get the idea of how to handle piping, but the problem I'm having is that my code skips dup2() on any file descriptor except inFD and outFD.
Here's the code for my function. Also, from what I understand, my teacher made a macro called CHK which checks for errors. If there is an error (such as dup2 returning -1), it'll terminate with a print to stderr.
My includes, global variables and myhandler() for signal
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <math.h>
#include <signal.h>
// Function calls
void parse(char *w, char **ptrArray, char *inArray, char *outArray, int *pipeArray);
int flagHandler(char **ptrArray, char *inArray, char *outArray);
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray);
// Global Variables
const int STORAGE = 254;
const int MAXITEM = 100;
int inFD; // file descriptor for <
int outFD; // file descriptor for >
int complete = 0; // for sighandler
int readDes = 0;
int writeDes = 1;
int numPipes = 0;
int status;
int forCounter = 0;
int fildes[4];
int pipeIndex = 0;
// MetaChar flags
int lessthanSign = 0; // < flag
int greaterthanSign = 0; // > flag
int firstChildFlag = 0;
int lastChildFlag = 0;
void myhandler(int signum)
{
complete = 1;
}
My main function
int main()
{
char s[STORAGE]; // array of words
char *newargv[MAXITEM];
char inArray[STORAGE]; // for <
char outArray[STORAGE]; // for >
int firstCheck;
int pidBackground; // holds value from fork(), used for background calls
struct stat st; // for stat(), checks if file exists
// dynamic array based on numPipes
// first child doesn't use this array, as it uses newargv[0] and newargv
// only the middle children and last child use this array, hence 10
int *pipeArray = malloc(10 * sizeof(int));
int numLoops = 0;
int i = 0;
signal(SIGTERM, myhandler);
for(;;)
{
// Reset flags here
lessthanSign = 0;
greaterthanSign = 0;
pipeSign = 0;
firstChildFlag = 0;
lastChildFlag = 0;
pipeIndex = 0;
parse(s, newargv, inArray, outArray, pipeArray);
pipeHandler(newargv, inArray, outArray, pipeArray);
wait(NULL);
fflush(NULL);
} // end for
printf("Entering killpg; numLoops = %d\n", numLoops);
killpg(getpid(), SIGTERM);
printf("p2 terminated.\n");
exit(0);
} // end main
Main calls parse which fills in newargv[]. It also fills in inArray[] and outArray[] with the string immediately after a < and > respectively. When detecting a pipe sign, it puts a null on newargv[], as well as putting a value in pipeArray[] for indexing the executable's name in newargv. I omitted the parse() and flagHandler() calls to keep it minimal.
My parseHandler() function
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray)
{
pid_t firstChild;
pid_t firstChildBackground;
pid_t middleChild;
pid_t lastChild;
pid_t lastChildBackground;
int i = 0; // plain integer for for loops
printf("Initializing pipes\n");
//pipe(fildes);
//pipe(fildes + 2);
for (i = 0; i < (2*numPipes); i+=2)
{
printf("pipe initializing; i is %d\n", i);
if (pipe(fildes + i) < 0)
{
perror("pipe initialization failed");
exit(EXIT_FAILURE);
}
}
fflush(stdout);
if ((firstChild = fork()) < 0)
{
perror("First child's fork failed!");
exit(EXIT_FAILURE);
}
printf("firstChild pid = %d\n", getpid());
if (firstChild == 0)
{
if (firstChildFlag == 1)
{
printf("inFD = open...\n");
inFD = open(inArray, O_RDONLY);
printf("Doing dup2 inFD\n");
if (dup2(inFD, STDIN_FILENO) < 0)
{
perror("First child's < dup2 failed");
exit(EXIT_FAILURE);
}
}
printf("doing dup2 fildes[writeDes]\n");
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("First child's dup2 failed");
exit(EXIT_FAILURE);
}
printf("*****doing dup2 fildes[writeDes] was a success!\n");
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (firstChildFlag == 1)
{
lessthanSign = 0;
firstChildFlag = 0;
if (close(inFD) < 0)
{
perror("close inFD failed");
exit(EXIT_FAILURE);
}
}
writeDes += 2;
printf("About to execvp first child\n");
if (execvp(ptrArray[0], ptrArray) < 0)
{
perror("execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((middleChild = fork() < 0))
{
perror("Middle child's fork failed");
exit(EXIT_FAILURE);
}
printf("middleChild pid = %d\n", getpid());
if (middleChild == 0)
{
if (dup2(fildes[readDes], STDIN_FILENO) < 0)
{
perror("Middle child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("Middle child's dup2 on writing failed");
exit(EXIT_FAILURE);
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
readDes += 2;
writeDes += 2;
if (execvp(ptrArray[pipeArray[0]], ptrArray + pipeArray[0]) < 0)
{
perror("Middle child's execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((lastChild = fork() < 0))
{
perror("Last child's fork failed");
exit(EXIT_FAILURE);
}
printf("lastChild pid = %d\n", getpid());
if (lastChild == 0)
{
if (dup2(fildes[readDes], STDOUT_FILENO) < 0)
{
perror("Last child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (lastChildFlag == 1)
{
outFD = open(outArray, O_CREAT | O_RDWR, 0400 | 0200);
if (dup2(outFD, STDOUT_FILENO) < 0)
{
perror("Last child's > dup2 failed");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (lastChildFlag == 1)
{
greaterthanSign = 0;
lastChildFlag = 0;
if (close(outFD) < 0)
{
perror("close on outFD failed");
exit(EXIT_FAILURE);
}
}
printf("Execvp last child\n");
if (execvp(ptrArray[pipeArray[1]], ptrArray + pipeArray[1]) < 0)
{
perror("Last child's execvp failed");
exit(EXIT_FAILURE);
}
printf("Last child execvp finished\n");
}
}
}
// Only the parent gets here
printf("Only the parent should be here\n");
printf("My pid is %d\n", getpid());
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
for (;;)
{
pid_t pid;
if (pid = wait(NULL) < 0)
{
perror("wait failed");
exit(EXIT_FAILURE);
}
if (pid == lastChild)
{
printf("Parent is waiting for lastChild\n");
break;
}
}
printf("Parent finished waiting. Returning...\n");
return 0;
}
I did pipe(fildes) before any fork, so that all children and a parent have their copy. Therefore, I must close all file descriptors in each child (after dup2 but before execvp) and the parent. The parent will then wait until it gets the pid of lastChild.
With a lot of printf statements, I have found that no child does the dup2() command (except for dup2(inFD...) and dup2(outFD...) when the flags are appropriate). There is also no error printed.
I printed out my (char) newargv[] and my (int) pipeArray[] and they contain the correct values. It seems to be just the dup2 problem, and I have absolutely no idea what's going wrong with it.
I made a simple text file called test2 containing
ls | sort | cat someString
Where someString is just a file with some text. With all the print statements in the pipeHandler() function my output is:
EDIT: I fixed a couple typos I had. I forgot to lace an extra set of parenthesis on 3 ifs, if ((firstChild = fork()0 < 0)
I now have an infinite loop as the parent is waiting for the lastChild's pid. Here's the output:
Initializing pipes
numpipes = 2
pipe initializing; i is 0
pipe initializing; i is 2
firstChild pid = 20521
firstChild pid = 20522
doing dup2 fildes[writeDes]
middleChild pid = 20521
middleChild pid = 20523
lastChild pid = 20521
Only the parent should be here
My pid is 20521
lastChild pid = 20524
<infinite loop>
I'm still clueless though as to what's going on or what's potentially stopping the child.
#MarkPlotnick you're right! It's not that dup2 isn't executing or anything. Because I did dup2(fildes[1], STDOUT_FILENO), all print statements will be piped.
I fixed the typo mentioned as well. I tried my teacher's test file
< input1 cat|>your.outputc tr a-z A-Z | tr \ q
Which should result with a file called your.outputc. It does, and the contents are input1 with the effects of tr. However, I also have the printf statements at the top of this file.
I assumed the dup2 wasn't working because no printf statement followed, unlike it did in dup2(inFD, STDIN_FILENO), but that's probably because it was STDIN.
I'm trying to get a better understanding of pipes and processes. I want to implement multiple chained pipes like cat test.txt | sort | uniq -c. I started my code with the cat test.txt, but it isn't working. It compiles, but when I provide a file name in the command line, for example, ./hwk ./test.txt. Nothing returns. Can someone take a look and give me some hints? I want to use loops because I want to be able to add more pipes. I know there's a lot of issues in my code, so I hope someone can give me some guidance on this topic. Thanks.
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#define SIZE 1024
int main (int argc, char **argv)
{
int num_pipe = 1;
int commands = num_pipe + 1; //number of commands is one more than the number of pipes
int fds[num_pipe * 2];
int status;
pid_t pid;
char *str_ptr;
//Pass Command
char *arrayOfCommands[] = {"cat", NULL};
//Setting up pipes
int i;
for (i = 0; i < num_pipe; i++){
if(pipe(fds + i * 2) == -1) {
perror("Error creating pipes");
exit(1);
}
}
int j = 0;
for (i = 0; i < commands - 1; ++i) {
pid = fork();
if (pid == 0) {
if (i < commands) {
if (dup2(fds[j+1], 1) < 0) {
perror("dup2 error");
exit(EXIT_FAILURE);
}
}
if (j != 0) {
if(dup2(fds[j-2], 0) < 0) {
perror("dup2 error");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < 2*num_pipe; i++) {
close(fds[i]);
}
if (execvp(arrayOfCommands[0], arrayOfCommands) < 0) {
perror("Array error");
exit(EXIT_FAILURE);
}
}
else if (pid < 0){
perror("Error");
exit(EXIT_FAILURE);
}
j += 2;
}
for (i = 0; i < 2 * num_pipe; i++){
close(fds[i]);
}
for (i = 0; i < num_pipe + 1; i++) {
wait(&status);
}
return 0;
}
I called this mainly minor adaptation of your program p3.c, compiling it to produce p3. Since there's only one command (cat) being invoked, I juggled things so that it will work correctly. When run as ./p3 p3.c, it prints out the content of the source code.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
static void err_exit(const char *str);
int main (int argc, char **argv)
{
int num_pipe = 0; // Just cat - no pipes
int commands = num_pipe + 1; // Number of commands is one more than the number of pipes
int fds[num_pipe * 2 + 1]; // Avoid size 0 array
char *arrayOfCommands[3] = { "cat", NULL, NULL};
if (argc != 2)
err_exit("Missing filename argument");
arrayOfCommands[1] = argv[1];
for (int i = 0; i < num_pipe; i++)
{
if (pipe(fds + i * 2) == -1)
err_exit("Error creating pipes");
}
int j = 0;
for (int i = 0; i < commands; ++i)
{
pid_t pid = fork();
if (pid == 0)
{
printf("%d: %s %s\n", (int)getpid(), arrayOfCommands[0], arrayOfCommands[1]);
fflush(stdout);
if (i < commands-1 && dup2(fds[j+1], 1) < 0)
err_exit("dup2 error");
if (j != 0 && dup2(fds[j-2], 0) < 0)
err_exit("dup2 error");
for (i = 0; i < 2*num_pipe; i++)
close(fds[i]);
execvp(arrayOfCommands[0], arrayOfCommands);
err_exit("Array error");
}
else if (pid < 0)
err_exit("Error");
j += 2;
}
for (int i = 0; i < 2 * num_pipe; i++)
close(fds[i]);
for (int i = 0; i < num_pipe + 1; i++)
{
int status;
pid_t pid = wait(&status);
printf("PID %d exited 0x%.4X\n", (int)pid, status);
}
return 0;
}
static void err_exit(const char *str)
{
perror(str);
exit(EXIT_FAILURE);
}
Check that works for you. Then you'll need to work out how you're going to create a second command. Your arrayOfCommands isn't going to help directly. You'll need another array of strings in some shape or form.
An extension to run cat file | rev. The changes are really quite minor. I created a_cat to handle the cat command, a_rev for the rev command, and a_cmds as the array of commands. It was also necessary to fix a loop on i to a loop on k.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
static void err_exit(const char *str);
int main (int argc, char **argv)
{
int num_pipe = 1;
int commands = num_pipe + 1; //number of commands is one more than the number of pipes
int fds[num_pipe * 2 + 1]; // Avoid size 0 array
char *a_cat[3] = { "cat", NULL, NULL};
char *a_rev[2] = { "rev", NULL};
char **a_cmds[] = { a_cat, a_rev };
if (argc != 2)
err_exit("Missing filename argument");
a_cat[1] = argv[1];
for (int i = 0; i < num_pipe; i++)
{
if (pipe(fds + i * 2) == -1)
err_exit("Error creating pipes");
}
int j = 0;
for (int i = 0; i < commands; ++i)
{
pid_t pid = fork();
if (pid == 0)
{
printf("%d: %s\n", (int)getpid(), a_cmds[i][0]);
fflush(stdout);
if (i < commands-1 && dup2(fds[j+1], 1) < 0)
err_exit("dup2 error");
if (j != 0 && dup2(fds[j-2], 0) < 0)
err_exit("dup2 error");
for (int k = 0; k < 2*num_pipe; k++)
close(fds[k]);
execvp(a_cmds[i][0], a_cmds[i]);
err_exit("Array error");
}
else if (pid < 0)
err_exit("Error");
j += 2;
}
for (int i = 0; i < 2 * num_pipe; i++)
close(fds[i]);
for (int i = 0; i < num_pipe + 1; i++)
{
int status;
pid_t pid = wait(&status);
printf("PID %d exited 0x%.4X\n", (int)pid, status);
}
return 0;
}
static void err_exit(const char *str)
{
perror(str);
exit(EXIT_FAILURE);
}
You aren't passing your program's command-line arguments through to the "cat" child process. You initialize arrayOfCommands like so -> char *arrayOfCommands[] = {"cat", NULL}; <- then you pass it as-is to the execvp() function as the second argument.
Okay your first problem is that in the line:
execvp(arrayOfCommands[0], arrayOfCommands);
you are using arrayOfCommands but I am not sure how you're populating arrayOfCommands for the case where the text file is not being displayed. I mean are you setting arrayOfCommands like the following earlier in the code:
char *arrayOfCommands[] = {"cat", "./test.txt", NULL};
If I understand you correctly your program is called hwk and for whatever reason you think ./hwk ./test.txt should be parsed but that means you should be parsing argv.
Okay now that that's out of the way let's look at the bigger problem of how you are setting things up.
So when a shell parses out pipes it does there's quite a bit going on. Consider the following:
foo fooparam1 fooparam2 | bar barparam1 | baz bazparam1 bazparam2
The shell uses recursion to solve the problem:
foo fooparam1 fooparam2 | ( bar barparam1 | baz bazparam1 bazparam2 )
So it would look SOMETHING like:
spawn_sub_pipes(const char *str) {
char *cmd = strtok(str, "|");
char *rest = strtok(NULL, "|");
int fds[2];
pipe(fds[]);
int pid = fork();
if ( pid < 0 ) {
perror("pipe error");
exit(-1);
}
if ( pid ) { /* parent is the writer */
close(fds[0]); /* close reading pipe */
dup2(fds[1], 1); /* we attach stdout to the pipe */
}
if ( pid == 0 ) {
close(fds[1]);
dup2(fds[0], 0); /* attach the pipe to stdin */
if ( rest ) { /* fork next children */
spawn_sub_pipes(rest);
}
execvpe(cmd);
}
}
IMPORTANT NOTE
I have just written the above code out without testing it. Get the idea from it but don't use it verbatim.
I’m attempting to create my own shell I believe i have the forking done correctly but i cannot figure out how to pipe correctly. Any help or tips would be appreciated.
basically my pipes aren’t working and i have spent ages attempting to figure out how to get them to properly transmit the data between the processes.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h" // from Steven's book Advanced programing in the UNIX Enviroment
extern int makeargv(char *, char * , char ***);
int main()
{ char **argp;
int i,j,vpret;
char buf[80];
pid_t pid;
int pnum;
//pipe number
int ploc[16];
//pipe location
//(this has a max of 12 possible pipes)
int targ;
int fdleft[2], fdright[2];
printf(" <(^_^)> \nHello \n I am your console and I am here to help you \n");
printf(" If you dont need me anymore just say \"bye\" ");
fflush(stdout);
write(1,"\n(>^_^)> ",8);
while(strcmp(fgets(buf, 80, stdin), "bye\n")!=0)
{
j=makeargv(buf," \n",&argp); //this breaks the line up and returns the number of commands
pnum = 0;
ploc[0] = 0;
if (j > 16) j = 16;
for (i=0;i<j;i++)
{
if ( strcmp(argp[i], "|") == 0)
{
argp[i]= NULL;
ploc[pnum+1] = (i+1);
pnum++;
}
}
for (i = 0; i < (pnum+1); i++)
{
pipe(fdright);
if (i != 0)
{
dup2(fdright[1], fdleft[0]);
}
pid = fork();
switch (pid)
{
case -1:
err_sys("fork failed");
break;
case 0: // child
if (i != pnum)
{
dup2(fdright[1],1);
}
if ( i != 0);
{
dup2(fdright[0],0);
}
//printf("(^o^) running pipe[%i]\n" , i);
targ =(ploc[i]) ;
execvp(argp[targ],&argp[targ]);
write(1,"(-_-) I'm sorry the exec failed \n",33);
exit(1);
default:
dup2(fdleft[1], fdright[1]);
waitpid(pid,NULL, 0);
close(fdright[0]);
close(fdright[1]);
//waitpid(pid,NULL, 0);
}
}
//waitpid(pid, NULL, 0);
write(1,"\n(>^_^)> ",8);
}
printf(" v(^o^)^ BYE BYE!\n");
}
thanks
Various comments:
while (strcmp(fgets(buf, 80, stdin), "bye\n")!=0)
This crashes if the shell is given EOF instead of bye. Don't combine the two function calls like that. If you want it all in one loop condition, then use:
while (fgets(buf, sizeof(buf), stdin) != 0 && strcmp(buf, "bye\n") != 0)
We'll discuss limits on the length of the command line another time.
Since you've not supplied makeargv() to look at, we have to assume it does its job OK.
Your loop that splits things up into commands and pipes is:
pnum = 0;
ploc[0] = 0;
if (j > 16) j = 16;
for (i = 0; i < j; i++)
{
if (strcmp(argp[i], "|") == 0)
{
argp[i] = NULL;
ploc[pnum+1] = (i+1);
pnum++;
}
}
Let's assume we have a command line input: ls -l | grep lemon. It appears that your makeargv() would return 5 and set argp as follows:
argp[0] = "ls";
argp[1] = "-l";
argp[2] = "|";
argp[3] = "grep";
argp[4] = "lemon";
argp[5] = 0; // Inferred - things will crash sooner or later if wrong
This loop of yours would give you:
ploc[0] = 0;
ploc[1] = 3;
pnum = 1;
Your code has a pair of file descriptors in the fdleft array, but you never initialize the array (call pipe(), for example), even though you use it in calls to dup2().
The main for loop then has to run twice, once for each command. For the general case of three or more commands in a pipeline (who | grep me | sort, for example), your first command (who) needs its standard input untouched, but its standard output going to the pipe that connects who and grep. The 'middle' commands (second to penultimate commands, or grep me in the example) each needs its standard input to come from the previous pipe and needs to create a new pipe for its standard output to go to. The last command (in this example, the third command, sort), needs its standard input to come from the last pipe and its standard output unchanged.
Your code doesn't do that, or get anywhere close.
When you use pipe() and then dup() or dup2() to map any of the descriptors to standard I/O descriptors, you need to close both ends of the pipe. You simply don't have enough close() calls around either.
Your parent process has to launch each of the children in turn, and only waits for them to exit after it has launched them all. There are different ways of organizing the processes. The parent could fork once; the child could be responsible for launching the leading commands in the pipeline, finally executing the last command itself. The parent has just one direct child (the others are grandchildren), so it only has to wait for the one command to finish. The alternative is that the parent knows about each of the processes in the pipeline and it waits for them all to finish.
If your parent processes waits for each command in a pipeline to complete before launching the remainder, you can end up with a form of deadlock. One child writes so much data to its pipe that it is blocked by the kernel until some process reads from the pipe, but the process to read from the pipe is not yet launched and the parent is waiting for the child to exit. You also lose the benefits of multi-processing and concurrency.
In your 'case 0', you have an extraneous semi-colon. My compiler warned me about it. If yours didn't warn you about it, you need to use more compilation warnings or get a better compiler.
case 0: // child
if (i != pnum)
{
dup2(fdright[1], 1);
}
if (i != 0); // Unwanted semi-colon!
{
dup2(fdright[0], 0);
}
There are many questions about pipe lines in mini-shells on SO, including:
SO 13636252
SO 13693446
SO 13905948
SO 14312939
SO 13213864
The answer for 13636252 is most nearly generic. The only snag is it uses char *** which is apt to be confusing, and it is so tightly written it has mutually recursive functions with minimal repetition. OTOH, it works correctly, and your makeargv() function also uses a char *** argument.
Reworked code
Here is your code reworked so that it works. It includes implementations of err_sys() and makeargv(). My makeargv() simply assumes that there will be fewer than 32 words in the command line. It is not, by any stretch of my imagination, a robust command line parser. It does allow you to type ls | wc and gives the correct answer; it also allows who | grep me | sort and gives the correct answer; it also allows ls and gives the correct answer. The spaces around the pipe symbols are crucial, though (in a normal shell, they're optional, so who|grep me|sort should work too, but it won't with this code.
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
extern int makeargv(char *line, char *seps, char ***args);
extern void err_sys(const char *msg);
static void dump_argv(char **argv);
static void dump_fds(void);
int main(void)
{
char buf[80];
printf(" <(^_^)> \nHello \n I am your console and I am here to help you\n");
printf(" If you don't need me anymore just say \"bye\"\n");
fflush(stdout);
dump_fds();
printf("(>^_^)> ");
while (fgets(buf, sizeof(buf), stdin) != 0 && strcmp(buf, "bye\n") != 0)
{
pid_t pid;
char **argp;
int fdleft[2] = { -1, -1 };
int fdright[2] = { -1, -1 };
int pnum = 0;
int ploc[16];
int j = makeargv(buf, " \n", &argp);
ploc[0] = 0;
if (j > 16)
j = 16;
for (int i = 0; i < j; i++)
{
if (strcmp(argp[i], "|") == 0)
{
argp[i] = NULL;
ploc[++pnum] = i+1;
}
}
printf("pnum = %d\n", pnum);
for (int k = 0; k < pnum+1; k++)
printf("ploc[%d] = %d\n", k, ploc[k]);
for (int i = 0; i < pnum+1; i++)
{
if (i != pnum)
{
if (pnum > 0)
{
if (pipe(fdright) != 0)
err_sys("pipe");
//printf("%d: fdright = { %d, %d }\n", i, fdright[0], fdright[1]);
//dump_fds();
}
}
if ((pid = fork()) < 0)
err_sys("fork failed");
else if (pid == 0)
{
/* Child */
int targ;
//dump_fds();
if (i != pnum)
{
dup2(fdright[1], 1);
close(fdright[0]);
close(fdright[1]);
}
if (i != 0)
{
dup2(fdleft[0], 0);
close(fdleft[0]);
close(fdleft[1]);
}
targ = ploc[i];
dump_argv(&argp[targ]);
dump_fds();
execvp(argp[targ], &argp[targ]);
fprintf(stderr, "(-_-) I'm sorry the exec failed\n");
exit(1);
}
if (i != 0)
{
//dump_fds();
//printf("%d: fdleft = { %d, %d }\n", i, fdleft[0], fdleft[1]);
assert(fdleft[0] != -1 && fdleft[1] != -1);
close(fdleft[0]);
close(fdleft[1]);
//dump_fds();
}
printf("PID %d launched\n", pid);
fdleft[0] = fdright[0];
fdleft[1] = fdright[1];
}
//dump_fds();
//printf("%d: fdleft = { %d, %d }\n", -1, fdleft[0], fdleft[1]);
close(fdleft[0]);
close(fdleft[1]);
free(argp);
//dump_fds();
int corpse;
int status;
while ((corpse = waitpid(0, &status, 0)) > 0)
printf(":-( PID %d status 0x%.4X\n", corpse, status);
printf("\n(>^_^)> ");
}
printf(" v(^o^)^ BYE BYE!\n");
}
static void dump_argv(char **argv)
{
int n = 0;
char **args;
args = argv;
while (*args++ != 0)
n++;
fprintf(stderr, "%d: %d args\n", getpid(), n);
args = argv;
while (*args != 0)
fprintf(stderr, "[%s]\n", *args++);
fprintf(stderr, "EOA\n");
}
/* Report on open file descriptors (0..19) in process */
static void dump_fds(void)
{
struct stat b;
char buffer[32];
sprintf(buffer, "%d: ", getpid());
char *str = buffer + strlen(buffer);
for (int i = 0; i < 20; i++)
*str++ = (fstat(i, &b) == 0) ? 'o' : '-';
*str++ = '\n';
*str = '\0';
fputs(buffer, stderr);
}
int makeargv(char *line, char *seps, char ***args)
{
enum { MAX_ARGS = 32 };
char **argv = malloc(32 * sizeof(char *)); // Lazy!
if (argv == 0)
err_sys("out of memory in makeargv()");
int n;
char **argp = argv;
char *str = line;
for (n = 0; n < MAX_ARGS - 1; n++)
{
str += strspn(str, seps);
if (*str == '\0')
break;
*argp++ = str;
int len = strcspn(str, seps);
if (len == 0)
break;
str[len] = '\0';
str += len + 1;
}
*argp = 0;
dump_argv(argv);
*args = argv;
return(n);
}
void err_sys(const char *msg)
{
int errnum = errno;
char *errmsg = strerror(errnum);
fprintf(stderr, "%s (%d: %s)\n", msg, errnum, errmsg);
exit(1);
}
Sample output:
$ ./pipes-15673333
<(^_^)>
Hello
I am your console and I am here to help you
If you don't need me anymore just say "bye"
29191: ooo-----------------
(>^_^)> who | grep jl | sort
29191: 6 args
[who]
[|]
[grep]
[jl]
[|]
[sort]
EOA
pnum = 2
ploc[0] = 0
ploc[1] = 2
ploc[2] = 5
PID 29194 launched
PID 29195 launched
29194: 1 args
[who]
EOA
PID 29196 launched
29194: ooo-----------------
29195: 2 args
[grep]
[jl]
EOA
29195: ooo-----------------
29196: 1 args
[sort]
EOA
29196: ooo-----------------
:-( PID 29194 status 0x0000
jleffler console Mar 27 15:11
jleffler ttys000 Mar 27 16:26
jleffler ttys001 Mar 27 16:26
jleffler ttys002 Mar 27 16:26
jleffler ttys003 Mar 27 16:26
jleffler ttys004 Mar 27 16:26
jleffler ttys005 Mar 27 16:26
:-( PID 29195 status 0x0000
:-( PID 29196 status 0x0000
(>^_^)> ls
29191: 1 args
[ls]
EOA
pnum = 0
ploc[0] = 0
PID 29197 launched
29197: 1 args
[ls]
EOA
29197: ooo-----------------
bash.getopts.update makefile pipeline.c pthread-1.c shuntzeroes.c timezeromoves.c
cmpfltint.c mda.c pipeline.dSYM pthread-2.c so.14304827 uint128.c
const-stuff.c mq-saurabh pipes-13905948.c pthread-3.c so.367309 uname.c
dupdata.sql mqp-saurabh pipes-14312939.c quine.c so.6964747 unwrap.c
fifocircle.c multi-pipe-sort.c pipes-15673333 ranges.sql so.6965001 xxx.sql
idsdb00246324.ec multiopts.sh pipes-15673333.c recv.c so.8854855.sql yyy.sql
incunabulum.c nextpipe.c pipes-15673333.dSYM regress.c strandsort.c
madump.c pipeline powa.c send.c streplace.c
:-( PID 29197 status 0x0000
(>^_^)> ls -C | wc
29191: 4 args
[ls]
[-C]
[|]
[wc]
EOA
pnum = 1
ploc[0] = 0
ploc[1] = 3
PID 29200 launched
PID 29201 launched
29200: 2 args
29201: 1 args
[ls]
[wc]
[-C]
EOA
EOA
29201: ooo-----------------
29200: ooo-----------------
:-( PID 29200 status 0x0000
16 46 581
:-( PID 29201 status 0x0000
(>^_^)> bye
v(^o^)^ BYE BYE!
$
I'm trying to implement multiple pipes in my shell in C. I found a tutorial on this website and the function I made is based on this example. Here's the function
void executePipes(cmdLine* command, char* userInput) {
int numPipes = 2 * countPipes(userInput);
int status;
int i = 0, j = 0;
int pipefds[numPipes];
for(i = 0; i < (numPipes); i += 2)
pipe(pipefds + i);
while(command != NULL) {
if(fork() == 0){
if(j != 0){
dup2(pipefds[j - 2], 0);
}
if(command->next != NULL){
dup2(pipefds[j + 1], 1);
}
for(i = 0; i < (numPipes); i++){
close(pipefds[i]);
}
if( execvp(*command->arguments, command->arguments) < 0 ){
perror(*command->arguments);
exit(EXIT_FAILURE);
}
}
else{
if(command != NULL)
command = command->next;
j += 2;
for(i = 0; i < (numPipes ); i++){
close(pipefds[i]);
}
while(waitpid(0,0,0) < 0);
}
}
}
After executing it and typing a command like for example ls | grep bin, the shell just hangs there and doesn't output any result. I made sure I closed all pipes. But it just hangs there. I thought that it was the waitpid that's was the problem. I removed the waitpid and after executing I get no results. What did I do wrong? Thanks.
Added code:
void runPipedCommands(cmdLine* command, char* userInput) {
int numPipes = countPipes(userInput);
int status;
int i = 0, j = 0;
pid_t pid;
int pipefds[2*numPipes];
for(i = 0; i < 2*(numPipes); i++){
if(pipe(pipefds + i*2) < 0) {
perror("pipe");
exit(EXIT_FAILURE);
}
}
while(command) {
pid = fork();
if(pid == 0) {
//if not first command
if(j != 0){
if(dup2(pipefds[(j-1) * 2], 0) < 0){
perror(" dup2");///j-2 0 j+1 1
exit(EXIT_FAILURE);
//printf("j != 0 dup(pipefd[%d], 0])\n", j-2);
}
//if not last command
if(command->next){
if(dup2(pipefds[j * 2 + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
for(i = 0; i < 2*numPipes; i++){
close(pipefds[i]);
}
if( execvp(*command->arguments, command->arguments) < 0 ){
perror(*command->arguments);
exit(EXIT_FAILURE);
}
} else if(pid < 0){
perror("error");
exit(EXIT_FAILURE);
}
command = command->next;
j++;
}
for(i = 0; i < 2 * numPipes; i++){
close(pipefds[i]);
puts("closed pipe in parent");
}
while(waitpid(0,0,0) <= 0);
}
}
I believe the issue here is that your waiting and closing inside the same loop that's creating children. On the first iteration, the child will exec (which will destroy the child program, overwriting it with your first command) and then the parent closes all of its file descriptors and waits for the child to finish before it iterates on to creating the next child. At that point, since the parent has closed all of its pipes, any further children will have nothing to write to or read from. Since you are not checking for the success of your dup2 calls, this is going un-noticed.
If you want to keep the same loop structure, you'll need to make sure the parent only closes the file descriptors that have already been used, but leaves those that haven't alone. Then, after all children have been created, your parent can wait.
EDIT: I mixed up the parent/child in my answer, but the reasoning still holds: the process that goes on to fork again closes all of its copies of the pipes, so any process after the first fork will not have valid file descriptors to read to/write from.
pseudo code, using an array of pipes created up-front:
/* parent creates all needed pipes at the start */
for( i = 0; i < num-pipes; i++ ){
if( pipe(pipefds + i*2) < 0 ){
perror and exit
}
}
commandc = 0
while( command ){
pid = fork()
if( pid == 0 ){
/* child gets input from the previous command,
if it's not the first command */
if( not first command ){
if( dup2(pipefds[(commandc-1)*2], 0) < ){
perror and exit
}
}
/* child outputs to next command, if it's not
the last command */
if( not last command ){
if( dup2(pipefds[commandc*2+1], 1) < 0 ){
perror and exit
}
}
close all pipe-fds
execvp
perror and exit
} else if( pid < 0 ){
perror and exit
}
cmd = cmd->next
commandc++
}
/* parent closes all of its copies at the end */
for( i = 0; i < 2 * num-pipes; i++ ){
close( pipefds[i] );
}
In this code, the original parent process creates a child for each command and therefore survives the entire ordeal. The children check to see if they should get their input from the previous command and if they should send their output to the next command. Then they close all of their copies of the pipe file descriptors and then exec. The parent doesn't do anything but fork until it's created a child for each command. It then closes all of its copies of the descriptors and can go on to wait.
Creating all of the pipes you need first, and then managing them in the loop, is tricky and requires some array arithmetic. The goal, though, looks like this:
cmd0 cmd1 cmd2 cmd3 cmd4
pipe0 pipe1 pipe2 pipe3
[0,1] [2,3] [4,5] [6,7]
Realizing that, at any given time, you only need two sets of pipes (the pipe to the previous command and the pipe to the next command) will simplify your code and make it a little more robust. Ephemient gives pseudo-code for this here. His code is cleaner, because the parent and child do not have to do unnecessary looping to close un-needed file descriptors and because the parent can easily close its copies of the file descriptors immediately after the fork.
As a side note: you should always check the return values of pipe, dup2, fork, and exec.
EDIT 2: typo in pseudo code. OP: num-pipes would be the number of pipes. E.g., "ls | grep foo | sort -r" would have 2 pipes.
Here's the correct functioning code
void runPipedCommands(cmdLine* command, char* userInput) {
int numPipes = countPipes(userInput);
int status;
int i = 0;
pid_t pid;
int pipefds[2*numPipes];
for(i = 0; i < (numPipes); i++){
if(pipe(pipefds + i*2) < 0) {
perror("couldn't pipe");
exit(EXIT_FAILURE);
}
}
int j = 0;
while(command) {
pid = fork();
if(pid == 0) {
//if not last command
if(command->next){
if(dup2(pipefds[j + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
//if not first command&& j!= 2*numPipes
if(j != 0 ){
if(dup2(pipefds[j-2], 0) < 0){
perror(" dup2");///j-2 0 j+1 1
exit(EXIT_FAILURE);
}
}
for(i = 0; i < 2*numPipes; i++){
close(pipefds[i]);
}
if( execvp(*command->arguments, command->arguments) < 0 ){
perror(*command->arguments);
exit(EXIT_FAILURE);
}
} else if(pid < 0){
perror("error");
exit(EXIT_FAILURE);
}
command = command->next;
j+=2;
}
/**Parent closes the pipes and wait for children*/
for(i = 0; i < 2 * numPipes; i++){
close(pipefds[i]);
}
for(i = 0; i < numPipes + 1; i++)
wait(&status);
}
The (shortened) relevant code is:
if(fork() == 0){
// do child stuff here
....
}
else{
// do parent stuff here
if(command != NULL)
command = command->next;
j += 2;
for(i = 0; i < (numPipes ); i++){
close(pipefds[i]);
}
while(waitpid(0,0,0) < 0);
}
Which means the parent (controlling) process does this:
fork
close all pipes
wait for child process
next loop / child
But it should be something like this:
fork
fork
fork
close all pipes (everything should have been duped now)
wait for childs
You only need two pipes alternating like below:
typedef int io[2];
extern int I; //piped command current index
extern int pipe_count; //count of '|'
#define CURRENT 0
#define PREVIOUS 1
#define READ 0
#define WRITE 1
#define is_last_command (I == pipe_count)
bool connect(io pipes[2])
{
if (pipe_count)
{
if (is_last_command || I != 0)
dup2(pipes[PREVIOUS][READ], STDIN_FILENO);
if (I == 0 || !is_last_command)
dup2(pipes[CURRENT][WRITE], STDOUT_FILENO);
}
return (true);
}
void close_(io pipes[2])
{
if (pipe_count)
{
if (is_last_command || I != 0)
close(pipes[PREVIOUS][READ]);
if (I == 0 || !is_last_command)
close(pipes[CURRENT][WRITE]);
}
}
void alternate(int **pipes)
{
int *pipe_current;
pipe_current = pipes[CURRENT];
pipes[CURRENT] = pipes[PREVIOUS];
pipes[PREVIOUS] = pipe_current;
}
Example usage:
#define ERROR -1
#define CHILD 0
void execute(char **command)
{
static io pipes[2];
if (pipe_count && pipe(pipes[CURRENT]) == ERROR)
exit_error("pipe");
if (fork()==CHILD && connect(pipes))
{
execvp(command[0], command);
_exit(EXIT_FAILURE);
}
while (wait(NULL) >= 0);
close_(pipes);
alternate((int **)pipes);
}
static void run(char ***commands)
{
for (I = 0; commands[I]; I++)
if (*commands[I])
execute(commands[I]);
}
I'll leave a link to a full working code for someone who needs it.
Building upon the idea of using a maximum of two pipes at a given time mentioned by Christopher Neylan, I put together pseudocode for n-pipes. args is an array of character pointers of size 'args_size' which is a global variable.
// MULTIPLE PIPES
// Test case: char *args[] = {"ls", "-l", "|", "head", "|", "tail", "-4",
0};// "|", "grep", "Txt", 0};
enum fileEnd{READ, WRITE};
void multiple pipes( char** args){
pid_t cpid;
// declare pipes
int pipeA[2]
int pipeB[2]
// I have done getNumberofpipes
int numPipes = getNumberOfPipes;
int command_num = numPipes+1;
// holds sub array of args
// which is a statement to execute
// for example: cmd = {"ls", "-l", NULL}
char** cmd
// iterate over args
for(i = 0; i < args_size; i++){
//
// strip subarray from main array
// cmd 1 | cmd 2 | cmd3 => cmd
// cmd = {"ls", "-l", NULL}
//Open/reopen one pipe
//if i is even open pipeB
if(i % 2) pipe(pipeB);
//if i is odd open pipeA
else pipe(pipeA);
switch(cpid = fork(){
case -1: error forking
case 0: // child process
childprocess(i);
default: // parent process
parentprocess(i, cpid);
}
}
}
// parent pipes must be closed in parent
void parentprocess(int i, pid_t cpid){
// if first command
if(i == 0)
close(pipeB[WRITE]);
// if last command close WRITE
else if (i == numPipes){
// if i is even close pipeB[WRITE]
// if i is odd close pipeA[WRITE]
}
// otherwise if in middle close READ and WRITE
// for appropriate pipes
// if i is even
close(pipeA[READ])
close(pipeB[WRITE])
// if i is odd
close(pipeB[READ])
close(pipeA[WRITE])
}
int returnvalue, status;
waitpid(cpid, returnvalue, status);
}
void childprocess(int i){
// if in first command
if(i == 0)
dup2(pipeB[WRITE], STDOUT_FILENO);
//if in last command change stdin for
// the necessary pipe. Don't touch stdout -
// stdout goes to shell
else if( numPipes == i){
// if i is even
dup2(pipeB[READ], STDIN_FILENO)
//if i is odd
dup2(pipeA[READ], STDIN_FILENO);
}
// otherwise, we are in middle command where
// both pipes are used.
else{
// if i is even
dup2(pipeA[READ], STDIN_FILENO)
dupe(pipeB[WRITE], STDOUT_FILENO)
// if i is odd
dup2(pipeB[READ], STDIN_FILENO)
dup2(pipeA[WRITE], STDOUT_FILENO)
}
// execute command for this iteration
// check for errors!!
// The exec() functions only return if an error has occurred. The return value is -1, and errno is set to indicate the error.
if(exec(cmd, cmd) < 0)
printf("Oh dear, something went wrong with read()! %s\n", strerror(errno));
}
}
Basically what you wanna do is a recursive function where the child executes the first command and the parent executes the second one if no other commands are left or calls the function again.
I'm trying to create a simple shell in C for Unix. I've been able to do all the parsing of commands and execution, but I'm having a problem with piping. I think the problem is that I'm not hooking into the correct pipe for the input of the second command.
For example, if I type "ls | wc", it will pause after the "wc" command, which I think is because its waiting for input. I think the problem is when I use dup2(reading[i],0), and its not hooking into the correct pipe.
I know this is a bit of a broad question, but if there are any pointers I could get, I would appreciate it. Here is the code that creates new processes and tries to pipe them.
int fileds[2];
int reading[num_cmds];
int writing[num_cmds];
int p;
for(p=0; p < num_cmds; p++)
{
reading[p] = -1;
writing[p] = -1;
}
int j;
for(j=0; j < num_cmds-1; j++) //Create pipes for commands
{
int fileds[2];
pipe(fileds);
reading[j+1] = fileds[0];
writing[j] = fileds[1];
}
int i = 0;
for(i = 0; i < num_cmds;i++)
{
cmd_args = parse_cmd(cmds[i],output_file,input_file,&run_bg); //Get command and args
pid_t childpid;
int status;
childpid=fork();
if (childpid >= 0)
{
if (childpid == 0)
{
if(writing[i] != -1)
{
dup2(writing[i],1);
close(writing[i]);
}
if(reading[i] != -1)
{
dup2(reading[i],0);
close(reading[i]);
}
int h;
for(h = 0; h < num_cmds; h++)
{
close(writing[h]);
close(reading[h]);
}
if(execvp(cmd_args[0],cmd_args) == -1)
{
perror("Problem with command");
exit(0);
}
}
else
{
wait(&status);
int m;
for(m = 0; m < num_cmds; m++)
{
if( writing[m] != -1) close(writing[m]);
if( reading[m] != -1) close(reading[m]);
}
}
}
else
{
perror("fork");
continue;
}
input_file[0] = 0;
output_file[0] = 0;
run_bg = 0;
}
}
UPDATE: I was able to figure it out, thanks to Richard. It was a combination of closing the file descriptors in the wrong order and not closing some at all. Here's the working code.
int fileds[2];
int reading[num_cmds];
int writing[num_cmds];
int p;
for(p=0; p < num_cmds; p++)
{
reading[p] = -1;
writing[p] = -1;
}
int j;
for(j=0; j < num_cmds-1; j++)
{
int fileds[2];
pipe(fileds);
reading[j+1] = fileds[0];
writing[j] = fileds[1];
}
int i = 0;
for(i = 0; i < num_cmds;i++)
{
cmd_args = parse_cmd(cmds[i],output_file,input_file,&run_bg);
pid_t childpid;
int status;
childpid=fork();
if (childpid >= 0)
{
if (childpid == 0)
{
if(writing[i] != -1)
{
close(1);
dup2(writing[i],1);
}
if(reading[i] != -1)
{
close(0);
dup2(reading[i],0);
}
if(execvp(cmd_args[0],cmd_args) == -1)
{
perror("Problem with command");
exit(0);
}
}
else
{
wait(&status);
close(writing[i]);
if(i > 0)
{
close(reading[i]);
}
}
}
else
{
perror("fork");
}
input_file[0] = 0;
output_file[0] = 0;
run_bg = 0;
}
I think your problem may be that you wait for each process inside the loop and then close all the file descriptors. This makes the file descriptors invalid for the next call to dup2() and results in stdin for the next process staying unchanged.
Just a guess, I haven't run the code.
When I type "ls | wc" wc does as expected and prints the number of words output by the ls command. Remember that when you are piping commands using "|" you don't need to create pipes in your application. The first command needs to output to stdout and the second command needs to read that output from standard in.