Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

A Simple Shell A C program that provides the basic operation of a command line shell is supplied in Code I. This program is composed

A Simple Shell A C program that provides the basic operation of a command line shell is supplied in Code I. This program is composed of two functions: main( ) and setup( ). The setup( ) function reads in the users next command (which can be up to 80 characters), and then parses it into separate tokens that are used to fill the argument vector for the command to be executed. (If the command is to be run in the background, it will end with & , and setup( ) will update the parameter background so the main( ) function can act accordingly. This program is terminated when the user enters exit. The main( ) function presents the prompt COMMAND-> and then invokes setup( ) , which waits for the users to enter a command. The contents of the command entered by the user are loaded into the args array. For example, if the user enters ls l at the COMMAND-> prompt, args[0] becomes equal to the string ls and args[1] is set to the string to -l. (By string, we mean a null-terminated, C-style string variable.)

Code 1: Shell

#include #include #include #include #define MAX_LINE 80 /* 80 chars per line, per command, should be enough. */ /** * setup() reads in the next command line, separating it into distinct tokens * using whitespace as delimiters. setup() sets the args parameter as a * null-terminated string. */ void setup(char inputBuffer[], char *args[],int *background) { int length, /* # of characters in the command line */ i, /* loop index for accessing inputBuffer array */ start, /* index where beginning of next command parameter is */ ct; /* index of where to place the next parameter into args[] */ ct = 0; /* read what the user enters on the command line */ length = read(STDIN_FILENO, inputBuffer, MAX_LINE); start = -1; if (length == 0) exit(0); /* ^d was entered, end of user command stream */ if (length < 0){ perror("error reading the command"); exit(-1); /* terminate with error code of -1 */ } /* examine every character in the inputBuffer */ for (i=0;i

start = -1; inputBuffer[i] = '\0'; } } } args[ct] = NULL; /* just in case the input line was > 80 */ } int main(void) { char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */ int background; /* equals 1 if a command is followed by '&' */ char *args[(MAX_LINE/2)+1]; /* command line (of 80) has max of 40 arguments */ while (1){ /* Program terminates normally inside setup */ background = 0; printf(" COMMAND-> "); setup(inputBuffer,args,&background); /* get next command */ /* the steps are: (0) if built-in command, handle internally (1) if not, fork a child process using fork() (2) the child process will invoke execvp() (3) if background == 0, the parent will wait, otherwise returns to the setup() function. */ } }

----------------------------------------------------------------------------------------------------------------------

Code 2: Signal handeling

#include #include #include #define BUFFER_SIZE 50 char buffer[BUFFER_SIZE] ; /*the signal handling function */ void handle_SIGQUIT( ) { write (STDOUT_FILENO, buffer,strlen (buffer) ) ; exit (0) ; } int main (int argc, char *argv[ ] ) { /* set up the signal handler */ struct sigaction handler ; handler. sa_handler = handle_SIGQUIT ; sigaction (SIGQUIT, &handler , NULL); /*Generate the output message */ strcpy(buffer, Caught Control-backslash ) ; /*loop until we receive <\> */ while (1) ; return 0; }

----------------------------------------------------------------------------------------------------------------------

1. When your shell starts up, it must print a greeting and its pid. You can use getpid() to get the pid. Example: "Welcome to kbshell. My pid is 26357." 2. The shell prompt must be "xxshell[n]:", where xx are your initials, and n is the number of prompts shown so far (starting at 1 and increasing). Example: kbshell[1]: 3. The shell must support the following built-in commands: stop - which stops a running background task by sending it the SIGSTOP signal. bg - which instructs a stopped process to resume running in the background by sending it the SIGCONT signal. fg - which instructs a stopped process to resume running in the foreground by sending it the SIGCONT signal and waiting for it to complete. waitpid() is the right function to use here. Print a message Child process complete when it completes. kill - which kills a stopped or background process by sending it the SIGKILL signal. exit - which prints a message xxshell exiting and exits. Ctrl-\ Ctrl-\ would normally terminate a program to which it is sent. So, if you typed control-\ while running your shell, it would receive the signal and terminate. Instead, we would like our shell to catch the signal and pass it on to the foreground process (if it exists). So, the shell would continue executing but the child would terminate. This is what bash does for the foreground child. The shell should print Caught Ctrl-\ when it catches the signal. 4. For any other command, the shell should fork() a new process and execvp() the command. You are given quite a bit of code including the setup() function which tokenizes the user input and places the arguments into a vector (perfect for execvp). The code for setup() and a skeleton of main() is given in shell.c. Your shell must provide background and foreground options controlled by a "&" sign. If a user command ends with an "&", it should be run in the background. This means that the parent does not wait for the command to complete before issuing a new prompt. If there is no "&", then the parent does wait for the child to complete. In either case, immediately after forking, the parent should print a message indicating the pid of the child and whether the child is running in the background or not (ex. [Child pid = xxxx, background = TRUE]). If the command statement ends with an "&", the shell must run the command in the background. In this case, the shell should immediately offer a new prompt after launching the previous command. If background operation is not indicated, the shell should waitpid() for the child to complete before printing "Child process complete" and offering a new prompt. (Note: you need to use waitpid() rather than wait() because wait() will return if any child is done not just the one you want to wait for.)

Example output

kbshell[1]: time sleep 8 & [Child pid = 26358, background = TRUE] kbshell[2]: date

[Child pid = 26359, background = FALSE] /* Note that the order of the next couple statements depends on the scheduler */ Wed Feb 11 22:48:42 PDT 2021 Child process complete kbshell[3]: real 0m8.018s /* Note this is the child output which is printed after the parent has completed another command */ user 0m0.001s sys 0m0.001s kbshell[4]: time sleep 8 [Child pid = 26360, background = FALSE] real 0m8.018s /* This is the child output before the parent prints another prompt. */ user 0m0.001s sys 0m0.001s Child process complete kbshell[5]: Note that, in the foreground case, since we don't know whether the child or parent will execute first after the fork, the pid message may come before or after child's output.

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Students also viewed these Databases questions