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 processExplanation / 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
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.