Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7458943
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 29, 20262026-05-29T13:50:17+00:00 2026-05-29T13:50:17+00:00

The short program below is intended to iterate over argv passed from the command

  • 0

The short program below is intended to iterate over argv passed from the command line and exec each argument. This is not my homework, but rather it is something I am doing in preparation for doing my homework.

The first argument gets input from STDIN and STDOUT, and writes to a pipe. At the end of each iteration (except the last), the file descriptors are swapped, so that the pipe written to by the last exec will be read from by the next. In this way I intend, for example, for

./a.out /bin/pwd /usr/bin/wc 

to print out only the length of the working directory. Code follows

#include <stdio.h>                                                              
#include <unistd.h>                                                             
#include <sys/types.h>                                                          
#include <stdlib.h>                                                             
#include <string.h>                                                             

main(int argc, char * argv[]) {                                                 

  int i;
  int left[2], right[2], nbytes; /* arrays for file descriptors */

  /* pointers for swapping */
  int (* temp);
  int (* leftPipe) = left;                 
  int (* rightPipe) = right;

  pid_t childpid;                                                               
  char readbuffer[80];                                                          

  /* for the first iteration, leftPipe is STDIN */
  leftPipe[0] = STDIN_FILENO;
  leftPipe[1] = STDOUT_FILENO;

  for (i = 1; i < argc; i++) {                                                  

    /* reopen the right pipe (is this necessary?) */
    pipe(rightPipe);                                                            
    fprintf(stderr, "%d: %s\n", i, argv[i]);
    fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);                                                                                    
    if ((childpid = fork()) == -1) {                                            
      perror("fork");                                                           
      exit(1);                                                                  
    }                                                                           

    if (childpid == 0) {                                                        

      /* read input from the left */                                            
      close(leftPipe[1]); /* close output */                                    
      dup2(leftPipe[0], STDIN_FILENO);                                          
      close(leftPipe[0]); /* is this necessary? A tutorial seemed to be doing this */ 

      /* write output to the right */                                           
      close(rightPipe[0]); /* close input */                                    
      dup2(rightPipe[1], STDOUT_FILENO);                                        
      close(rightPipe[1]);                                                      

      execl(argv[i], argv[i], NULL);                                            
      exit(0);                                                                  
    }                                                                           

    wait();                                                                     

    /* on all but the last iteration, swap the pipes */
    if (i + 1 < argc) {              

      /* swap the pipes */                                                      
      fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
      temp = leftPipe;                                                          
      leftPipe = rightPipe;                                                     
      rightPipe = temp;                                                         
      fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
    }                                                                           
  }                                                                             

    /* read what was last written to the right pipe */                          
    close(rightPipe[1]); /* the receiving process closes 1 */                  

    nbytes = read(rightPipe[0], readbuffer, sizeof(readbuffer));       
    readbuffer[nbytes] = 0;
    fprintf(stderr, "Received string: %s\n", readbuffer);                                

  return 0;                                                                     
}

UPDATE: in all of the below test cases I had originally used /bin/wc but which wc reveiled that the water closet is not at all where I thought. I am in the process of amending the results.

The output in a trivial case (./a.out /bin/pwd) is as expected:

1: /bin/pwd
Received string: /home/zeigfreid/Works/programmatical/Langara/spring_2012/OS/labs/lab02/play

The output from running this program with the first example (./a.out /bin/pwd /usr/bin/wc):

1: /bin/pwd
0 1 3 4
3 4 0 1
2: /bin/wc

At which point, the terminal hangs (maybe waiting on input).

As you can see, the string is not being received. What I imagine is that I have done something wrong above, either when swapping pointers, or that I don’t understand unix file descriptors. My assignment, in the end, will be to interpret arbitrarily long pipes, and this is one of the ideas I had for solving the problem. I’m having trouble judging whether I am on the right track of barking up a tree. Do I understand unix file descriptors?

UPDATE:

Running it with /bin/ls as the second argument, I got the following result (the numbers are the file descriptors at various points):

1: /bin/pwd
0 1 3 4
0 1 3 4
3 4 0 1
2: /bin/ls
3 4 5 6
Received string: a.out
log
pipe2.c
play.c
@

There is still some garbage at the end there, but I am now more concerned that I do not understand pointers! These two commands are independent from each other though, they don’t really make use of the pipe.

UPDATE: the garbage character was from not closing the string. Now I close it, and no garbage.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-29T13:50:19+00:00Added an answer on May 29, 2026 at 1:50 pm

    The hanging is caused by the fact that the writing end of the “right” pipe isn’t properly closed in the main process after forking. Because of this, wc will never stop reading (after all, the main process could still write stuff to the pipe!). It only stops reading after all copies of the file descriptor of the writing end have been closed.

    Here is a fixed version:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(int argc, char * argv[])
    {
      int i;
      int left[2], right[2], nbytes; /* arrays for file descriptors */
    
      /* pointers for swapping */
      int (* temp);
      int (* leftPipe) = left;
      int (* rightPipe) = right;
    
      pid_t childpid;
      char readbuffer[80];
    
      leftPipe[0] = STDIN_FILENO;
      // no need to assign leftPipe[1] here, it will not be used
    
      for (i = 1; i < argc; i++) {
        pipe(rightPipe); // create new pipe
    
        fprintf(stderr, "%d: %s\n", i, argv[i]);
        fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
        if ((childpid = fork()) == -1) {
          perror("fork");
          exit(1);
        }
    
        if (childpid == 0) {
          // use the reading end of the left pipe as STDIN
          dup2(leftPipe[0], STDIN_FILENO);
          // use the writing end of the right pipe as STDOUT
          dup2(rightPipe[1], STDOUT_FILENO);
          // close reading end of the right pipe
          close(rightPipe[0]);
          execl(argv[i], argv[i], NULL);
          exit(0);
        }
        // IMPORTANT!! close writing end of the right pipe, otherwise
        // the program will hang (this is the main bug in your original
        // implementation)
        close(rightPipe[1]);
    
        // wait properly!
        waitpid(childpid, NULL, 0);
    
        /* on all but the last iteration, swap */
        if (i + 1 < argc) {
          fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
          temp = leftPipe;
          leftPipe = rightPipe;
          rightPipe = temp;
          fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
        }
      }
    
      nbytes = read(rightPipe[0], readbuffer, sizeof(readbuffer));
      readbuffer[nbytes] = 0;
      fprintf(stderr, "Received string: %s\n", readbuffer);
    
      return 0;
    }
    

    Output:

     >> ./a.out /bin/ls /bin/cat /usr/bin/wc
    1: /bin/ls
    0 32767 3 4
    0 32767 3 4
    3 4 0 32767
    2: /bin/cat
    3 4 4 5
    3 4 4 5
    4 5 3 4
    3: /usr/bin/wc
    4 5 5 6
    Received string:     266     294    4280
    

    If you got specific questions about this solution, please let me know 🙂 There also some other minor problems with your original code:

    • using pointers is unnecessary, we can just copy around the pipes (performance surely will not be a problem 😉
    • int is used instead of size_t
    • you didn’t fix all the warning that would be presented to you when compiling with the -Wall flag

    If you’re interested, this is how I would have written it:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(int argc, char **argv) {
      size_t i, nbytes;
      int left[2], right[2], tmp[2];
      pid_t childpid;
      char readbuffer[80];
    
      left[0] = STDIN_FILENO;
    
      for (i = 1; i < argc; ++i) {
        pipe(right);
    
        switch ((childpid = fork())) {
          case -1:
            perror("fork");
            exit(1);
          case 0:
            dup2(left[0], STDIN_FILENO);
            dup2(right[1], STDOUT_FILENO);
            close(right[0]);
            execl(argv[i], argv[i], NULL);
          default:
            close(right[1]);
            waitpid(childpid, NULL, 0);
        }
    
        if (i == argc - 1) break;
        memcpy(tmp,   left,  sizeof tmp);
        memcpy(left,  right, sizeof left);
        memcpy(right, tmp,   sizeof right);
      }
    
      nbytes = read(right[0], readbuffer, sizeof readbuffer);
      readbuffer[nbytes] = 0;
      fprintf(stderr, "Received string: %s\n", readbuffer);
    
      return 0;
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm using boost::program_options to read the users' input from the command line argument. It
(In short: main()'s WaitForSingleObject hangs in the program below). I'm trying to write a
I am using the program below to sort and eventually print out email messages.
I have a short program that is used exclusively with a remote desktop connection
Here's a short test program: sub foo($;@) { my $sql = shift; my @params
I'm programming a short Paint program like and I'm trying to make an MDI
Short version: Is it easy/feasible/possible to program modal window in Flash (AS3)? Is there
I have a web based program which chooses some records from a database using
I am getting a weird exception when I exit the program. This has started
I have written a short String reverse program in C++. I decided to write

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.