Having trouble with fork(), pipe(), dup2() and exec() (pipes exercise)

This is a discussion on Having trouble with fork(), pipe(), dup2() and exec() (pipes exercise) within the C Programming forums, part of the General Programming Boards category; Here's my code: Code: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <wait.h> #include <readline/readline.h> int main(int argc, char *argv[]) { ...

  1. #1
    Registered User
    Join Date
    Mar 2006
    Posts
    158

    Having trouble with fork(), pipe(), dup2() and exec() (pipes exercise)

    Here's my code:

    Code:
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <wait.h>
        #include <readline/readline.h>
        
        int main(int argc, char *argv[]) {
        	char *bBuffer, *sPtr, *aPtr = NULL, *pipeComms[2], *cmdArgs[10];
            int fdPipe[2], pCount, aCount, i, status;
            pid_t pid;
        	
            pipe(fdPipe);
        	
        	while(1) {
        		bBuffer = readline("Shell> ");
        		
        		if(!strcasecmp(bBuffer, "exit")) {
        			return 0;
        		}
        		
        		sPtr = bBuffer;
        		pCount = -1;
        		
        		do {
        			aPtr = strsep(&sPtr, "|");
        			pipeComms[++pCount] = aPtr;
        		} while(aPtr);
        		
        		for(i = 0; i < pCount; i++) {
        			aCount = -1;
        			
        			do {
        				aPtr = strsep(&pipeComms[i], " ");
        				cmdArgs[++aCount] = aPtr;
        			} while(aPtr);
        			
        			if(strlen(cmdArgs[0]) > 0) {
        				pid = fork();
        				
        				if(pid == 0) {
        					if(i == 0) {
        						close(fdPipe[0]);
        						
        						dup2(fdPipe[1], STDOUT_FILENO);
        						
        						close(fdPipe[1]);
        					} else if(i == 1) {
        						close(fdPipe[1]);
        						
        						dup2(fdPipe[0], STDIN_FILENO);
        						
        						close(fdPipe[0]);
        					}
        					
        					execvp(cmdArgs[0], cmdArgs);
        				} else {
        					waitpid(pid, &status, 0);
        					
        					if(WIFEXITED(status)) {
        						printf("[%d] TERMINATED (Status: %d)\n",
        							pid, WEXITSTATUS(status));
        					}
        				}
        			}
        		}
        	}
        	
        	return 0;
        }
    Here's the test case where this fails:

    Code:
        nazgulled ~/Projects/SO/G08 $ ls -l
        total 8
        -rwxr-xr-x 1 nazgulled nazgulled  7181 2009-05-27 17:44 a.out
        -rwxr-xr-x 1 nazgulled nazgulled   754 2009-05-27 01:42 data.h
        -rwxr-xr-x 1 nazgulled nazgulled  1305 2009-05-27 17:50 main.c
        -rwxr-xr-x 1 nazgulled nazgulled   320 2009-05-27 01:42 makefile
        -rwxr-xr-x 1 nazgulled nazgulled 14408 2009-05-27 17:21 prog
        -rwxr-xr-x 1 nazgulled nazgulled  9276 2009-05-27 17:21 prog.c
        -rwxr-xr-x 1 nazgulled nazgulled 10496 2009-05-27 17:21 prog.o
        -rwxr-xr-x 1 nazgulled nazgulled    16 2009-05-27 17:19 test
        nazgulled ~/Projects/SO/G08 $ ./a.out 
        Shell> ls -l|grep prog
        [4804] TERMINATED (Status: 0)
        -rwxr-xr-x 1 nazgulled nazgulled 14408 2009-05-27 17:21 prog
        -rwxr-xr-x 1 nazgulled nazgulled  9276 2009-05-27 17:21 prog.c
        -rwxr-xr-x 1 nazgulled nazgulled 10496 2009-05-27 17:21 prog.o
    The problem is that I should return to my shell after that, I should see "Shell> " waiting for more input. You can also notice that you don't see a message similar to "[4804] TERMINATED (Status: 0)" (but with a different pid), which means the second process didn't terminate.

    I think it has something to do with grep, because this works:

    Code:
        nazgulled ~/Projects/SO/G08 $ ./a.out 
        Shell> echo q|sudo fdisk /dev/sda
        [4838] TERMINATED (Status: 0)
        
        The number of cylinders for this disk is set to 1305.
        There is nothing wrong with that, but this is larger than 1024,
        and could in certain setups cause problems with:
        1) software that runs at boot time (e.g., old versions of LILO)
        2) booting and partitioning software from other OSs
           (e.g., DOS FDISK, OS/2 FDISK)
        
        Command (m for help): 
        [4839] TERMINATED (Status: 0)
    You can easily see two "terminate" messages...

    So, what's wrong with my code?

    P.S: There's no error handling on purpose, this code is just like a proof of concept to show off my problem...

  2. #2
    Registered User
    Join Date
    Mar 2006
    Posts
    158
    Anyone please?

  3. #3
    Registered User
    Join Date
    Mar 2006
    Posts
    158
    I've realized the problem was the fact that I wasn't closing the pipes on the parent and grep was still waiting for and EOF to finish.

    Now I'm having a more important issue.

    As you can see, the code will only work for 2 piped commands, now I need to make it work for N commands. But I have no clue how to do such thing...

    Any help is appreciated.

  4. #4
    Registered User Homer_Simpson's Avatar
    Join Date
    May 2009
    Posts
    22
    Quote Originally Posted by Nazgulled View Post
    I've realized the problem was the fact that I wasn't closing the pipes on the parent and grep was still waiting for and EOF to finish.
    Now I'm having a more important issue.
    I hope you mean it this time, "one named" Nazgulled.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. "ls | sort" with pipes and forks?
    By alwut in forum C Programming
    Replies: 3
    Last Post: 01-09-2008, 12:59 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21