2

I am trying to learn Unix C and doing some exercises for practice. I am currently working on writing my own shell that works similar to the linux bash shell.

The code I have below provides for a fairly basic shell. It now provides I/O redirection. I am trying to add support for piping. Initially, I just want to add support for a single pipe.

I have tried to go through some tutorials online but can't quite figure out where to start.

Currently, the shell below can handle commands commands such as the following. ls > abc, cat< file1 > file2, etc.

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

#define TRUE 1

int main(void)
{
   char *arg_list[10];

   int status;

   int counter = 0;

   int counter2 = 0;

   pid_t pid;
   char buf[100];

   char inFile[10];
   char outFile[10];

   int fdIn, fdOut;
   while(TRUE)
   {
      printf("> ");
      if (!fgets(buf, 100, stdin))
      return 0;

      pid = fork();
      switch(pid)
      {
      case -1:
      return 1;

      case 0:
      {
      arg_list[counter] = strtok(buf, " \n");

      counter = 0;

      while(arg_list[counter] != NULL)
      {
       counter++;
       arg_list[counter] = strtok(NULL, " \n");
      }

      counter2 = 0;

      while(arg_list[counter2] != NULL)
     {
       if(!strcmp(arg_list[counter2], "<"))
       {
         if(arg_list[counter2+1] != NULL)
         {
           fdIn = open(arg_list[counter2+1], O_RDONLY);
           dup2(fdIn, STDIN_FILENO);
         }
         else
         {
           printf("No input file specified");
         }
         arg_list[counter2] = 0;
       }
       else if(!strcmp(arg_list[counter2], ">"))
       {
         if(arg_list[counter2+1] != NULL)
         {
         fdOut = open(arg_list[counter2+1], O_CREAT | O_WRONLY | O_TRUNC, 0666);
           dup2(fdOut, STDOUT_FILENO);
         }
         else
         {
           printf("No output file specified");
         }
         arg_list[counter2] = 0;
       }
       counter2++;
     }

    execvp(arg_list[0], arg_list);
    break;
  }

  default:
  waitpid(-1, &status, 0);
  break;
  }
}

  return 0;
}

If somebody can point me in the right direction, that would be appreciated.

user695752
  • 319
  • 7
  • 18
  • 7
    It would seem that your ambitions currently exceed your abilities. I would focus on getting a handle on parsing before trying to write a full-blown shell. – Ignacio Vazquez-Abrams Jul 08 '11 at 19:52
  • 3
    i dont agree - for a C learner this isnt bad code (we have all see MUCH worse in SO). Setting your sights high is a good thing; building up to it step by step is good too. Yes I know Bad Things will happen when he has too many arguments. But I bet he knows that too, or will find out soon – pm100 Jul 08 '11 at 20:33
  • 1
    The quality of the code is not the issue here. The problem is that a more complex parser is required, but it doesn't seem as though the asker knows (how?) to implement one. – Ignacio Vazquez-Abrams Jul 08 '11 at 20:53
  • I have just edited my code. It now supports I/O redirection and now I need some help with supporting a pipe. – user695752 Jul 15 '11 at 20:10
  • Something I'm wondering though, why are you writing this without lex/flex and yacc/bison? If you want to learn c, do an exercise geared towards teaching you c, instead of something that will bump you into all the little sharp corners of c string manipulation. – Spencer Rathbun Jul 15 '11 at 20:45

2 Answers2

3

After you use dup2() (successfully), you have two file descriptors open for the one file. You need to close the original file descriptor; the executed process should not have the extra file descriptors open.

You are also going to need to open the files in the appropriate way before using dup2(). Amongst other things, that means strtok() is not a good choice because it blats out the delimiter but you need to know which file to open for reading and which for writing).

You are also going to need to fettle the argument list; it should contain just the command name and a null pointer, not the two file names.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

Why do you need to check the type of command? Unix shells don't treat any commands specially; all redirections, including pipes, are handled the same way. One thing to watch out for is that redirections can happen anywhere in a command, so you should parse them out first; try

>foo ls <bar -la

in a shell sometime. (Pipes are an obvious exception to this, since they also delimit commands; syntactically | is the same as ;, although semantically there is redirection involved in addition.)

geekosaur
  • 59,309
  • 11
  • 123
  • 114