Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Lab 1: Mini-Shell Introduction This assignment will require you to write your ow

ID: 3748493 • Letter: L

Question

Lab 1: Mini-Shell

Introduction

This assignment will require you to write your own mini-shell. Of course, your shell will not be as feature rich as ksh, bash, or csh, but your shell will have functionality to run both built commands as well as other executables, manage child/parent relationship, and run in a separate Linux namespace.

       

To write your own shell, you will need to start with a C program that will prompt the user for input and accept in a number of arguments from a command line. There is a requirement to use Linux as the Linux namespace functionality only exists in Linux.

The commands entered will be accepted into your shell and then processed to understand if it is a built in command or something that needs to be executed via fork/exec (NOTE: No use of system() function). The interaction with your shell should be just like the standard shells. What I mean by this is to have a good usage statement returned if the arguments passed to the shell are not correct, and when there is an error you should send back a useful error, and not exit the shell, just continue.

Major components required in your shell

Prompt / collect from a command line process. Evaluate whether the command is: Executable program on disk Built in command

Neither - display “command not found” and/or any other errors

Process execution - utilizing fork/exec to create a new process and successfully spawn a child process and execute another program as that process

Manage child/parent processes (don’t create a <defunct> process)

Use the proper exec() function to start new processes

Spawn new namespace using clone() - Namespace (clone function) is an element to Linux and allows a version of virtualization without the need for a hypervisor - functions in the namespace are defined below

Code & functionality - properly written code inclusive of a good main() function, usage statements, ability to send in different commands (strings) that are parsed properly, code does not crash, etc.

Process Execution

A shell would not be of much use without interaction. Your shell will work like the standard shells in how it executes commands. There are at least 2 kinds of commands that the standard shells use

executable commands

built in commands.

Your shell should have a built in command that is not a standard UNIX command (programs on disk), that work in the shell.

When a parent kicks off a child process, the parent will need to wait for a signal from the child process on exit so that the child process does not become <defunct>.

       

There are many pieces to a shell, and trying to write one is not a simple task. I would suggest taking time to write a piece at a time, and implement some version of source control to minimize the loss of code per iteration of your program. Please do not worry about all of the details of a shell, I am just looking for a working shell that does all of the above sections. If you have questions about the depth of your shell, or how detailed it should be, please contact me for further instructions.

   New Process Namespace

Namespaces allow for virtualization and sharing of spaces between parent and child processes. This is a part of the Linux operating system since 2008 that allows for the creation of different models to create containers for software applications. The most popular version of Linux namespaces is Docker. Your task for this lab is to create the option inside your shell through “built in” commands to move your shell into a container. The options for different containers can be added together in a clone() or clone2() call. Here are some of the options:

CLONE_NEWIPC   - New namespace for IPC

CLONE_NEWUTS   - Setup new hostname and domain

CLONE_NEWUSER   - User and group changes

CLONE_NEWNET   - New network namespace

CLONE_NEWNS    - New mount namespace

When using a clone() function, you will have the ability to run another function. To test your clone() call, you will need to be able to demonstrate the change, and the best way to do that is to spawn another shell to “look around” at what changed. The best way to do this is to spawn another shell to be “in” the cloned process so that you can see what changed.

You will need to run the commands below before entering your clone, and then again in your clone to show the difference between the namespaces.

Once in your “sub-shell” you will test the clone options with the following commands (as examples):

CLONE_NEWNET

sh-4.1# ip link

CLONE_NEWNS

sh-4.1# readlink /proc/[your process id]/ns/mnt

E.g. if your PID is 2324, then the command would be

readlink / proc/2324/ns/mnt

You can find your process ID with the ‘ps’ command (look for your shell name) as in:

sh-4.1# ps

PID TTY          TIME CMD

2249 pts/1    00:00:00 bash    // This is my default

4381 pts/1    00:00:00 sh      // This is my sub-shell - to test clone

5236 pts/1    00:00:00 ps

sh-4.1#

CLONE_NEWIPC / CLONE_NEWUSER / CLONE_NEWUTS

All of these clone arguments can be seen by looking in the /proc directory.

Look under /proc/$$/ns/* for the filename (number). Note it change when you pass in one of the arguments above for IPC/USER/UTS.

NOTE: In the shell, the $$ will print out your Process ID (PID)

Namespace Requirements

Must run on Linux >= 2.6.25

Must run as root (at least for some clone calls)

You will need to create commands or a single command with arguments that will identify how you would invoke one or more of the above options. It is suggested that you create a single built in command that will take one or more options listed above.

       

To test the different options listed you will need to have functions that will be called with the clone() call that allow you to show what has been done to the process. An example is:

       Option : CLONE_NS - this will create a new mount namespace

Test : function will need to be a sub shell to allow a user to run commands like ls, cd, pwd to show where they are in the mount namespace.

Option : CLONE_NEWNET - this will create a new network namespace

Test : In the function, run a command to show the ip address(es) of the network cards known to the process (will be different than your “real” network addresses / cards.

             

I will be looking for style and testing as part of your grade. Please take time to comment your code well, and run some valid and useful test cases (remember that a good test case does not necessarily test how the code should work…).

Grading for this assignment will be based on the following guidelines:

Use “script” to capture your testing to a file. To use script, simply type script <filename> at a prompt (filename can be any name and if omitted the file will be called typescript). Once you have entered script, all I/O will be copied from the screen into the named file, and when you are done simply type “exit” to stop copying to the file.

NOTE: exit will only stop script, not exit your session.Write a README.TXT file that describes the various commands that your shell will support. This file should contain pertinent information on how you designed your shell, list the commands and usage of the commands, what works and what does not work, as well as who worked on the project with you (no name = no grade).

GIVE CLEAR INSTRUCTIONS ON USING THE SHELL IN YOUR README.TXT

Basic

1. Shell prompt

2. Quitting the shell [quit]

“Built in” command that your shell will support

1. clone [ argument ]

e.g., MyShell > clone net


Shell usage

The shell should exit gracefully at all conditions with proper error messages.

Should give proper usage statements on improper commands or arguments to commands

Specific testing for grading

Shell Execution

This should be very straightforward. You will make a determination if the command entered is an executable or a built in command such as clone, vs an executable like ls. If it is an executable, you will need to fork/exec the executable, and if it is a built in, then call the appropriate code/block to execute the built in command.

Explanation / Answer

A few commands your program should be able to handle include these2 : echo hello world > hw.txt wc –w < hw.txt cat < hw.txt > hw-copy.txt The first command causes the echo program to be executed to write two words on a single output line to the file named hw.txt . If hw.txt did not exist, then it would be created by your shell. If it did exist, then its content will be replaced. The second command uses the newly-created file hw.txt as input to the wc (word count) program. In particular, we’re interested in the number of words in the file; it should be 2. This command should succeed, but if the hw.txt file did not exist, then your shell would display an appropriate error message and not attempt to execute the wc program. The third command essentially copies the content of the hw.txt file to a copy named hw-copy.txt. 1 Note that the files opened for the standard input and standard output of the child process are automatically closed when the child process terminates, so no action by the parent – your shell – is needed. Also note that the standard input and output of your shell are not changed by the redirection done for the child process. 2 You may want to try these commands with the standard shell (usually bash) or the instructor’s solution to this assignment. Computer Science 4500/8506 Programming Assignment 1 Spring 2016 Problem Statement Specifically, you are to write a program will repeatedly do the following things: 1. Read a command line from the standard input. At the end of file, just quit. Also ignore lines that contain only blanks and tab characters. 2. Identify the “words” on this command line; 3. Verify that the first “word” is either a path to an executable command, or that it is the name of an executable file in one of the directories identified by the PATH environment variable; if it is neither, print an appropriate error message and repeat from step 1; 4. Create a child process (using fork) to execute the command; 5. In the child process just created: a. Redirect the standard input and the standard output, if necessary (as directed by the appropriate command line options); b. Prepare the argument structure necessary for the execve system call; and c. Invoke execve to begin execution of the child process; if execve returns, print an appropriate error message and exit (using the exit system call). 6. In the parent process, execute the wait system call to wait for the child process to terminate. When it does, display the exit status of the process and the reason for its termination. 7. Repeat from step 1. Details Let’s consider more detail about each of these actions. In step 1 you must use the read system call, not any other input mechanism provided by the C library. To avoid extra complexity, assume you are reading commands from a disk file, and read a single byte at a time. The file descriptor to use is 0, which corresponds to the standard input. When read returns 0 you have encountered the end of file. When the single character read is an end of line character (' '), then you have encountered the end of a line. You should echo the input you read; when you’re actually reading from the keyboard you’ll get an extra copy of the input, but when reading from a disk file, you’ll get a display of the command you’re about to process. You may assume that no input line contains more than 100 characters (including the end of line character). Step 2 is a simple parsing operation. Assume each “word” is separated from another word by one or more blanks or tab characters (i.e. “whitespace”). We will not worry about quoting arguments with single- or double-quotes or backslashes (as more complete shells will do). Additionally, you may assume that the characters used to specify redirection of input and output (i.e. '>' and '<') will be separated from other “words” by whitespace. You may assume there will be no more than 16 words in any input line, including the redirection characters. You may use C library functions like strtok to assist in this step. You may also assume no word will be longer than 64 characters, including a null terminator. At this point you have a sequence of words corresponding to a command name, its arguments, and possibly some input/output redirection information. In step 3 we will validate the name of the command