A Shell or Command Language Interpreter (CLI) is a piece of software that provides a simple, but powerful, textual interface for users to an operating system. In this Case Study you will investigate the operation of and implement a simple CLI.
A CLI accepts textual input from the user, and executes the commands issued. The main logic of the CLI is given below:
main:
loop
get input line
if end of input exit
break line into words
found := false
if command is builtin
then
do_builtin(line)
found:=true
else
found:=find_and_execute(line)
end if
if not found report error
end loop
Your first task will be to write a program that repeatedly reads a line of input from the user, the fgets() function (see Sect. 5 for usage information of all system provided functions) will help you here. Your program should end when either end of the input file is encountered, or the exact word exit appears in the input as the only word on a line. Traditionally both the File System and Command Language are case sensitive, you should also implement this.
Your next task will be to break the line up into words, which are separated by one or more spaces. The provided function tokenize() does this, and it uses strtok() internally. You may use this function if you wish, in which case you should provide documentation on its operation, or you may write your own parser.
You should next implement the find_and_execute() section of the logic above, by creating a new process using fork() , and then use one of the exec() family of func- tions to run the program requested by the user in the text provided. If the requested program cannot be run then an appropriate error message should be displayed, perror() will help with this (as there are many reasons why this may fail), and the child process terminated.
The CLI process must pause until the created process is concluded, wait() will need to be used here. Once the new process has finished you must decode and print out the exit status of that process.
Once this works you should add a builtin function cd to change the working directory of the CLI. This builtin should always use the next word supplied as the directory to change to, failure to supply a destination should be treated as an error. The chdir() function will be vital here.
Note Thislogichasaninfiniteloopinit. Theappropriateplacetodeterminewhentoexitisin the middle of the loop. When testing the sample code (if used) you should use the Ctrl + C key combination to break out of the program. Do not use Ctrl + Z , it does something completely different.
#include< stdlib.h>
#include< stdio.h>
#include< string.h>
#include< sys/types.h>
#include< sys/wait.h>
#include< unistd.h>
#include< errno.h>
#define MAX_LINE 4096
#define MAX_WORDS MAX_LINE/2
/* a line can have at most MAX_LINE/2 words, why? */
void tokenize(char *line, char **words, int *nwords);
/* break line into words separated by whitespace, placing them in the
array words, and setting the count to nwords */
int main()
{
char line[MAX_LINE], *words[MAX_WORDS], message[MAX_LINE];
int stop=0,nwords=0;
while(1)
{
printf("OSP CLI $ ");
/* read a line of text here */
tokenize(line,words,&nwords);
/* More to do here */
}
return 0;
}
/* this function works, it is up to you to work out why! */
void tokenize(char *line, char **words, int *nwords)
{
*nwords=1;
for(words[0]=strtok(line," tn");
(*nwords< MAX_WORDS)&&(words[*nwords]=strtok(NULL, " tn"));
*nwords=*nwords+1
); /* empty body */
return;
}