Starting from:
$35

$29

Assignment 3 Microshell Simulation Solution

In this assignment, you will implement a microshell in C/C++.




You will need to use several system calls under Linux including

fork(), pipe() and dup(). This assignment's logic is more complex

than in the previous assignments. Please allocate sufficient time for this assignment (suggestion: multiple days).




The name of the executable file should be "Assign3".




Your shell does the following:




--- Print a prompt "480shell" and wait for input.




--- Read the input typed after the prompt.




--- Execute the command typed in after the prompt and print a new

prompt.




--- The shell understands the commands "quit" and "q" as the special

commands to exit.




--- The shell understands a special symbol "||", by which you can

pipe the output of one command to next command. To simplify,

this assignment only requires one pipe between two commands, such

as in:




cat ourfile || sort




Please note that the standard Unix/Linux pipe is "|", which is

different from what our microshell would understand.




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




Input File




A text file is needed to produce the sample output. The file name is

"ourfile". Create a file containing 4 lines:




NIU

Illinois

USA

DeKalb




Sample Output




turing%480sh

480shellcat ourfile ||sort

DeKalb

Illinois

NIU

USA

480shellquit

turing%mysh

480shellmore ourfile || grep DeKalb

DeKalb

480shellls

ourfile 480sh

480shellq

turing%




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




Background Knowledge




1. The assignment will need several system calls for process

management and IPC such as fork(), exec(), pipe(), dup(). You

need to read the Linux manual page to understand their usage. You

will use fork() to create two child processes and use pipe() with

the help of dup()/dup2() to set up the communication between the

child processes. The system call dup() is used to duplicate the

file descriptors so that you can replace the standard input or

output of a process by the file descriptors of a pipe.




2. You need to close all the unneeded file descriptors of the pipes.

You need to close the two pipe file descriptors in the parent

process, the read end of the pipe for the first child process,

and the write end of the pipe for the second child process. After

the dup() is called in each child process, you can close the

write end for the first process and the read end for the second

process since they are no longer needed.




3. You may need strtok() to parse the command line for you. Read the

manual page to understand this function. You can use other ways

to parse the line too.




4. When you use execv() or execvp(), you need to build an array of

pointers to the arguments. The last element of the array should

be (char *) NULL.




5. The parent process needs to call waitpid() to wait for the

completion of the commands.




Tackle the problem step by step:




--- Make sure that your shell is taking inputs correctly.




--- Next test the execution of commands without any pipe involved.




--- Now you can go ahead and solve the pipe problem.




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




Programming Hints




How do I find the library for a system call?




Check the manual page. For example: Do "man strtok". In the

synopsis, you will see:




#include <strings.h




If you are interested in the exact contents of the header file, you

can go to /usr/include and do "more strings.h".




How do I structure the program?




You can start with the following example and add logic to handle pipe(), etc. And of course, you will need to define several functions due to the not-so-trivial logic.




#include <sys/types.h

#include <sys/wait.h

#include <stdio.h

int main(void)

{

char buf[1024];

pid_t pid;

int status;

printf("%% ");

while (fgets(buf,1024,stdin) != NULL)

{

buf[strlen(buf) -1] = 0; //remove the last character. Important!

if ((pid = fork()) <0)

printf("fork error");

else if (pid == 0)

{ /* child */

execlp(buf, buf, (char *) 0);

printf("couldn't execute: %s", buf);

exit(127);

}

/* parent */

if ( (pid = waitpid(pid, &status, 0)) < 0)

printf("waitpid error");

printf("%% ");

}

exit(0);

}




How do I parse the commands?




One approach is to use strtok() which can help you parse the

commands you get from input. There are other ways such as using

c++ string functions. If you choose to use strtok(), the syntax is

like:




char *strtok(char *s1, const char *s2);




The following is extracted from the Unix manual page. See the manual for the full description:




It can be used to break the string pointed to by s1 into a sequence of tokens, each of which is delimited by one or more characters from the string pointed to by s2.




The first call (with pointer s1 specified) returns a pointer to the first character of the first token, subsequent calls (which must be made with the first argument being a null pointer) will work through the string s1 immediately following that token. In this way subsequent calls will work through the string s1 until no tokens remain. When no token remains in s1, a null pointer is returned.




Example:

Suppose string is "abcd efgh || ijk lmn"




number =0;

command[0] = strtok(string,"||");

while((ptr = strtok(NULL, "||")) != NULL)

{

number++;

command[number] = ptr;

}

 

Then command[0] will contain "abcd efgh" and command[1] will contain "ijk lmn"




How do I do error handling?




You need to check the return value of a system call. For example, if the return value of -1 indicates an error, you should have a block that handles it. The simplest way to handle is to print out some error page and then exit the program.




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




Requirements




The program should:




--- work according to the specifications




--- be comprehensible and well documented




--- check the return value of the system calls and have proper error

handling




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




Submission




Submission requirement is the same as in the 1st assignment. Note that the directory must be called: "z1234567_project3_dir", all in

lowercase. Important steps are repeated below:




You will submit a compressed file through Blackboard under

"Assignments" as usual.




The compressed file contains your source code and a Makefile. It

should be named as "your-zid_A3.tar" and must be created

following the procedure described below:




1. Put all your source code files (NO OBJECT or EXECUTABLE FILES) and your Makefile in a directory called "your-zid_A3_dir".

Example: z1234567_A3_dir. Note: 'z' must be in lower case.




In your Makefile, you need to make sure your compilation produces

the executable file called "your-zid_A3". For a student with

z1234567 as her zid, the executable would be z1234567_A3.




2. In the parent directory of your-zid_A3_dir, compress this

whole subdirectory by the following command:




tar -cvvf your-zid_A3.tar your-zid_A3_dir




Example:




tar -cvvf z1234567_A3.tar z1234567_A3_dir




"your-zid_A3.tar" is now the compressed file containing the

whole subdirectory of your files. You can then transfer (e.g. using a

secure ftp client) the tar file from turing to a computer on which you can open a web browser for your final submission to the

Blackboard system.




 









More products