0

I'm trying to implement a C shell that allows for unlimited unidirectional pipes using the character '>'

So it can handle ls -A > tail > grep '.zip'

I understand that pipes are supposed to talk between processes, but I thought I came up with an idea that could use one pipe and multiple children.

This is what I have so far

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

char *args[1000][1000];//array of arguments

int args_count = 0;//count of the arguments in the array

int runCommand(char **arguments, int *fd, int pipeHasSomeData, int baseCase) {

  pid_t pid;

  int x = 0;

  int status;

  pid = fork();

  if(pid != 0) {

      waitpid(pid, &status, 0);

      if(baseCase) {

          if(WIFEXITED(status))
            {

                if(WEXITSTATUS(status) == 0)
                {
                    /*it worked*/

                } else if(WEXITSTATUS(status) == 255) {

                    printf("The program %s does not exist \n", arguments[0]);

                } else {

                    printf("ERROR: Error code: %d", WEXITSTATUS(status));

                }
            }
            else
            {
                printf("There was a problem that is not normal");
            }

          printf("\n \n");

      }

      return 1;

    } else {

      if(pipeHasSomeData == 1) {//  read from the pipe

          dup2(fd[0], 0);//read from pipe

      }

      if(baseCase == 0) {// not the base case

          dup2(fd[1], 1);//write to pipe

      } else {

          close(fd[1]);//close write

      }

          exit(execvp(arguments[0], arguments));

        return 0;

    }

}

int execute_commands(char *arguments[1000][1000], int pd[2] = NULL) {

    int current_count = args_count;

    int iterator = 0;

    int fd[2];

    int useAPipeInCommand = 0;

    pipe(fd);

while(iterator <= args_count) {//go through and execute all the commands

        if(current_count == 0) {//base case

            return runCommand(arguments[iterator], fd, useAPipeInCommand, 1);

        } else {

            runCommand(arguments[iterator], fd, useAPipeInCommand, 0);

            useAPipeInCommand = 1;

        }

    iterator++;

    current_count--;

    }//end while

    return 1;

}

int main () {

    int i = 0;

    char  text[1024];             /* the input line                 */
    char *tok2;

     while (1) {                   /* repeat until done ....         */

      fflush(stdin);
      fflush(stdout);

      printf("Shell -> ");     /*   display a prompt             */

         *text = 0;

          fgets(text, sizeof text, stdin);             /*   read in the command line     */
          fflush(stdout);
          printf("\n");

          char * tok = strtok(text, " \n\t");

          if (strcmp(tok, "exit") == 0) {  /* is it an "exit"?     */
               return 0;         /*   exit if it is                */

          }

         if (strcmp(tok, " ") == 0) {  /* is it an "exit"?     */
               continue;         /*   exit if it is                */

          }

         tok2 = tok;

      memset(args, 0, sizeof(args[0][0]) * 1000 * 1000);//clear the arguments array

      args_count = 0;

          int count = 0;

          while(tok2 != NULL) {

             if(strcmp(tok2, ">") != 0) {

                 args[args_count][count] = tok2;

                 count++;

                 tok2 = strtok(NULL, " \n\t");

             } else {//pipe was found, up the argument counter and set count to 0

         args[args_count][count] = NULL;

         args_count++;

                 count = 0;

                 tok2 = strtok(NULL, " \n\t");

             }

         }

         args[args_count][count] = NULL;

     execute_commands(args);

    }//end while

    return 0;

}

It is running the single base case no problem but the shell freezes when I do a pipe. Any ideas on the issue?

Dfranc3373
  • 2,048
  • 4
  • 30
  • 44
  • 1
    check out another implementation of multiple pipes in C. http://stackoverflow.com/questions/17630247/coding-multiple-pipe-in-c – Beau Bouchard Apr 28 '15 at 21:54
  • 1
    pipes have a (small) finite buffer; you cannot write more than a little bit to the pipe without blocking unless the other end of the pipe is being read. I didn't read all your code, so I'm just guessing that that is what you're doing. – rici Apr 29 '15 at 00:17

1 Answers1

0

Correct answer from Comments by @beau-bouchard and @rici:

Pipes have a (small) finite buffer; you cannot write more than a little bit to the pipe without blocking unless the other end of the pipe is being read.

For a correct implementation, check out "multiple pipes in C" Coding multiple pipe in C

--UPDATE:

Here is my final working code for anyone that is having a similar issue:

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

int READ = 0;

int WRITE = 1;

char *args[1000][1000];//array of arguments

int args_count = 0;//count of the arguments in the array

int execute_commands(char *arguments[1000][1000]) {

    int pd[2];

    int iterator = 0;

    int fd[2];

    int f_in = 0;

while(iterator <= args_count) {//go through and execute all the commands

      pid_t pid;

      int status;

      pipe(fd);

      pid = fork();

      if(pid != 0) {

          waitpid(pid, &status, 0);//wait for child to exit
          close(fd[WRITE]);//close the writing end

              if(WIFEXITED(status))
                {

                    if(WEXITSTATUS(status) == 0)
                    {
                        /*it worked*/

                    } else if(WEXITSTATUS(status) == 255) {

                        printf("The program %s does not exist \n", arguments[iterator][0]);

                    } else {

                        printf("ERROR: Error code: %d", WEXITSTATUS(status));

                    }
                }
                else
                {
                    printf("There was a problem that is not normal %d", status);
                }

                f_in = fd[READ];//set the pipe to the in

          if(iterator == args_count) {

              printf("\n \n");

          }

          //return 1;

        } else {

          dup2(f_in, 0);

          if(iterator != args_count) {//its not the main value

              dup2(fd[WRITE], 1);//write to pipe

          }

          close(fd[READ]);

              exit(execvp(arguments[iterator][0], arguments[iterator]));

            return 0;

        }

    iterator++;

    }//end while

    return 1;

}

int main () {

    int i = 0;

    char  text[1024];             /* the input line                 */
    char *tok2;

     while (1) {                   /* repeat until done ....         */

      fflush(stdin);
      fflush(stdout);

      printf("Shell -> ");     /*   display a prompt             */

         *text = 0;

          fgets(text, sizeof text, stdin);             /*   read in the command line     */
          fflush(stdout);
          printf("\n");

          char * tok = strtok(text, " \n\t");

          if (strcmp(tok, "exit") == 0) {  /* is it an "exit"?     */
               return 0;         /*   exit if it is                */

          }

         if (strcmp(tok, " ") == 0) {  /* is it an "exit"?     */
               continue;         /*   exit if it is                */

          }

         tok2 = tok;

      memset(args, 0, sizeof(args[0][0]) * 1000 * 1000);//clear the arguments array

      args_count = 0;

          int count = 0;

          while(tok2 != NULL) {

             if(strcmp(tok2, ">") != 0) {

                 args[args_count][count] = tok2;

                 count++;

                 tok2 = strtok(NULL, " \n\t");

             } else {//pipe was found, up the argument counter and set count to 0

         args[args_count][count] = NULL;

         args_count++;

                 count = 0;

                 tok2 = strtok(NULL, " \n\t");

             }

         }

         args[args_count][count] = NULL;

     execute_commands(args);

    }//end while

    return 0;

}
Community
  • 1
  • 1
Dfranc3373
  • 2,048
  • 4
  • 30
  • 44