Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Write a program that mimics the shell by printing a SHELL> prompt, repeatedly, t

ID: 3820774 • Letter: W

Question

Write a program that mimics the shell by printing a SHELL> prompt, repeatedly, to allow the user to enter UNIX commands. (The commands you enter should not use wildcards or other metacharacters). The entered command line should be executed with an appropriate exec call. Your program should terminate when the user types in exit. Also try running your solution with some of the shell's internal commands like umask and observe the behavior. Useful Tips: use built in C string operations to get tokens (words) out of a string buffer and perform string comparisons strtok, strcmp fork child to run the exec command, check the child's status on return use WEXITSTATUS to get exit status of a child process

Explanation / Answer

Input

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


void execute(char **, int, char **);
void handle_signal(int);
int parse(char *, char **, char **, int *);
void chop(char *);

#define INPUT_STRING_SIZE 80

#define NORMAL                00
#define OUTPUT_REDIRECTION    11
#define INPUT_REDIRECTION    22
#define PIPELINE            33
#define BACKGROUND           44
#define OUTPUT_APP   55


typedef void (*sighandler_t)(int);

int main(int argc, char *argv[])
{
   int i, mode = NORMAL, cmdArgc;
   size_t len = INPUT_STRING_SIZE;
   char *cpt, *inputString, *cmdArgv[INPUT_STRING_SIZE], *supplement = NULL;
   inputString = (char*)malloc(sizeof(char)*INPUT_STRING_SIZE);
  
   char curDir[100];
  
   while(1)
   {
       mode = NORMAL;
       getcwd(curDir, 100);
       printf("%s@%s->", getlogin(),curDir);
       getline( &inputString, &len, stdin);
       if(strcmp(inputString, "exit ") == 0)
           exit(0);
       cmdArgc = parse(inputString, cmdArgv, &supplement, &mode);
       if(strcmp(*cmdArgv, "cd") == 0)
       {
           chdir(cmdArgv[1]);
       }
       else
           execute(cmdArgv, mode, &supplement);
   }
   return 0;
}

int parse(char *inputString, char *cmdArgv[], char **supplementPtr, int *modePtr)
{
   int cmdArgc = 0, terminate = 0;
   char *srcPtr = inputString;
   //printf("parse fun%sends", inputString);
   while(*srcPtr != '' && terminate == 0)
   {
       *cmdArgv = srcPtr;
       cmdArgc++;
       //printf("parse fun2%sends", *cmdArgv);
       while(*srcPtr != ' ' && *srcPtr != ' ' && *srcPtr != '' && *srcPtr != ' ' && terminate == 0)
       {
           switch(*srcPtr)
           {
               case '&':
                   *modePtr = BACKGROUND;
                   break;
               case '>':
                   *modePtr = OUTPUT_REDIRECTION;
                   *cmdArgv = '';
                   srcPtr++;
                   if(*srcPtr == '>')
                   {
                       *modePtr = OUTPUT_APP;
                       srcPtr++;
                   }
                   while(*srcPtr == ' ' || *srcPtr == ' ')
                       srcPtr++;
                   *supplementPtr = srcPtr;
                   chop(*supplementPtr);
                   terminate = 1;
                   break;
               case '<':
                   *modePtr = INPUT_REDIRECTION;
                   *cmdArgv = '';
                   srcPtr++;
                   while(*srcPtr == ' ' || *srcPtr == ' ')
                       srcPtr++;
                   *supplementPtr = srcPtr;
                   chop(*supplementPtr);
                   terminate = 1;
                   break;
               case '|':
                   *modePtr = PIPELINE;
                   *cmdArgv = '';
                   srcPtr++;
                   while(*srcPtr == ' ' || *srcPtr == ' ')
                       srcPtr++;
                   *supplementPtr = srcPtr;
                   //chop(*supplementPtr);
                   terminate = 1;
                   break;
           }
           srcPtr++;
       }
       while((*srcPtr == ' ' || *srcPtr == ' ' || *srcPtr == ' ') && terminate == 0)
       {
           *srcPtr = '';
           srcPtr++;
       }
       cmdArgv++;
   }
   /*srcPtr++;
   *srcPtr = '';
   destPtr--;*/
   *cmdArgv = '';
   return cmdArgc;
}

void chop(char *srcPtr)
{
   while(*srcPtr != ' ' && *srcPtr != ' ' && *srcPtr != ' ')
   {
       srcPtr++;
   }
   *srcPtr = '';
}

void execute(char **cmdArgv, int mode, char **supplementPtr)
{
   pid_t pid, pid2;
   FILE *fp;
   int mode2 = NORMAL, cmdArgc, status1, status2;
   char *cmdArgv2[INPUT_STRING_SIZE], *supplement2 = NULL;
   int myPipe[2];
   if(mode == PIPELINE)
   {
       if(pipe(myPipe))                   //create pipe
       {
           fprintf(stderr, "Pipe failed!");
           exit(-1);
       }
       parse(*supplementPtr, cmdArgv2, &supplement2, &mode2);
   }
   pid = fork();
   if( pid < 0)
   {
       printf("Error occured");
       exit(-1);
   }
   else if(pid == 0)
   {
       switch(mode)
       {
           case OUTPUT_REDIRECTION:
               fp = fopen(*supplementPtr, "w+");
               dup2(fileno(fp), 1);
               break;
           case OUTPUT_APP:
               fp = fopen(*supplementPtr, "a");
               dup2(fileno(fp), 1);
               break;
           case INPUT_REDIRECTION:
               fp = fopen(*supplementPtr, "r");
               dup2(fileno(fp), 0);
               break;
           case PIPELINE:
               close(myPipe[0]);       //close input of pipe
               dup2(myPipe[1], fileno(stdout));
               close(myPipe[1]);
               break;
       }
       execvp(*cmdArgv, cmdArgv);
   }
   else
   {
       if(mode == BACKGROUND)
           ;
       else if(mode == PIPELINE)
       {
           waitpid(pid, &status1, 0);       //wait for process 1 to finish
           pid2 = fork();
           if(pid2 < 0)
           {
               printf("error in forking");
               exit(-1);
           }
           else if(pid2 == 0)
           {
               close(myPipe[1]);       //close output to pipe
               dup2(myPipe[0], fileno(stdin));
               close(myPipe[0]);
               execvp(*cmdArgv2, cmdArgv2);
           }
           else
           {
               ;//wait(NULL);
               //waitpid(pid, &status1, 0);
               //waitpid(pid2, &status2, 0);
               close(myPipe[0]);
               close(myPipe[1]);
           }
       }
       else
           waitpid(pid, &status1, 0);
           //wait(NULL);
   }
}

===========================================================================

Output:

akshay@akshay-Inspiron-3537:~/Chegg$ gcc shell.c
akshay@akshay-Inspiron-3537:~/Chegg$ ./a.out
akshay@/home/akshay/Chegg->cat input.txt
hello
akshay@/home/akshay/Chegg->exit

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote