Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

THIS IS IN C PROGRAMMING LANGUAGE. PLEASE POST ONLY MAIN IN CODE 1 FOR THE ANSWER. THANK YOU! Objectives: Build your own shell. A Simple

THIS IS IN C PROGRAMMING LANGUAGE. PLEASE POST ONLY "MAIN" IN CODE 1 FOR THE ANSWER. THANK YOU!

Objectives: Build your own shell. 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 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #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

switch (inputBuffer[i]){

case ' ':

case '\t' : /* argument separators */

if(start != -1){

args[ct] = &inputBuffer[start]; /* set up pointer */

ct++;

}

inputBuffer[i] = '\0'; /* add a null char; make a C string */

start = -1;

break;

case ' ': /* should be the final char examined */

if (start != -1){

args[ct] = &inputBuffer[start];

ct++;

}

inputBuffer[i] = '\0';

args[ct] = NULL; /* no more arguments to this command */

break;

default : /* some other character */

if (start == -1)

start = i;

if (inputBuffer[i] == '&'){

*background = 1;

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 command entered */ int background; /* equals 1 if a command is followed by & */ char *args [MAX_LINE/2 + 1]; /* command line arguments */ while (1) { background = 0 ; printf ( COMMAND ->) ; setup (inputBuffer, args, &background) ; /** the steps are: (0) If command is built-in, print command results to terminal. If command is exit, print statistics and exit() (1) fork a child process using fork( ) (2) the child process will invoke execvp( ) (3) if background == 1, the parent will wait, otherwise it will invoke the setup ( ) function again. */ } } -=-=-=-=-=-=-=-=-=-=-=-=-=-= END OF CODE 1 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- In Code II we show a C program that uses the function handle_SIGINT( ) for handling the SIGINT signal. This function prints out the message Caught Control-c and then invokes the exit ( ) function to terminate the program. (We must use the write( ) function for performing output rather than the more common printf ( ) as the former is known as being signal-safe, indicating it can be called from inside a signal-handling function; Such guarantees cannot be made of printf ( ) . ) This program will run in the while (1) loop until the user enters the sequence . When this occurs, the signal-handling function handle_SIGINT( ) is invoked.

-=-=-=-=-=-=-=-=-=-=-=-=-=-= CODE 2 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #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; } -=-=-=-=-=-=-=-=-=-=-=-=-=-= END OF CODE 2 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- The signal-handling function should be declared above main() and, because control can be transferred to this function at any point, no parameters may be passed to this function. Therefore, any data that it must access in your program must be declared globally, i.e. at the top of the source file before your function declarations. Before returning from the signal-handling function, it should reissue the command prompt. Details for our class: A shell is a command line interpreter which often has some functionality built in, and spawns off processes to handle other functions. You will be writing a simple shell which spawns off processes to handle most commands. Your shell will also provide some job control functions via built-in functionality that you write. Your shell must: 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:

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

Recommended Textbook for

How To Make A Database In Historical Studies

Authors: Tiago Luis Gil

1st Edition

3030782409, 978-3030782405

More Books

Students also viewed these Databases questions