Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

CS 214 Fall 2023

Project III: My shell

For this project, you and your partner will design and implement a simple command-line shell, similar to bash or zsh.  Your program, mysh, will provide  interactive and batch modes, both of which will read and interpret a sequence of commands.

This project will provide experience of

.  Posix (unbuffered) stream IO

.  Reading and changing the working directory

.  Spawning child processes and obtaining their exit status

.  Use of dup2() and pipe()

.  Reading the contents of a directory

1    Overview

Your program mysh takes up to one argument. When given one argument, it will run in batch mode. When given no arguments, it will run in interactive mode.

For full credit, your program must have one input loop and command parsing algorithm that works for both modes.

Batch mode   When called with an argument, mysh will open the specified file and interpret its contents as sequence of commands (see section 2).  The command are given by lines of text, separated by newlines. mysh will execute each command as soon as it is complete, before proceeding to execute the next command.  mysh terminates once it reaches the end of the input file or encounters the command exit.

Interactive mode   When called with no arguments, mysh will read commands from standard input. Before reading a command, mysh will write a prompt to standard output. After executing the command, mysh will print a new prompt and read the next command.  To ensure that prompts are printed appropriately, mysh must be careful not to call read() again if a newline character has already been entered.

mysh terminates once it reaches the end of the input file or encounters the command exit.

In this mode, mysh should print a greeting before the first prompt and a message when terminating normally. The format of these are left to you.

Prompt format   When running in interactive mode, mysh will print a prompt to indicate that it is ready to read input. The prompt is normally the string “mysh> ”  (note the trailing space).

Usage   Batch mode:

$  cat myscript.sh

echo  hello

$  ./mysh myscript.sh

hello

$

Interactive mode:

$  ./mysh

Welcome  to my  shell!

mysh>  cd  subdir

mysh>  echo  hello

hello

mysh>  cd  subsubdir

mysh>  pwd

/current/path/subdir/subsubdir

mysh>  cd  directory_that_does_not_exist

cd:  No  such  file  or  directory

mysh>  cd  ../ . .

mysh>  exit

mysh:  exiting

$

2    Command format

mysh reads one command per line, which describes a job. A typical job will involve one or more child processes executing specified programs with specified arguments and possibly overridden standard input or output files.

When processing a command, mysh must determine the number of child processes to start and, for each one,

1. The path to the executable file

2. The list of argument strings

3. Which files to use for standard input and output

To accomplish this, mysh will process the command line in stages.

The command itself is made of tokens. For our purposes, a token is a sequence of non-whitespace characters, except that >, <, and  |  are always a token on their own.  Thus, a string foo  bar<baz consists of four tokens: “foo”, “bar”, “<”, and “baz”.

The token stream determines the argument list and whether the command includes redirection. We can build the argument list as we step through the token stream.

Wildcards   If a token includes the wildcard character *, it describes a pattern of file path names. For simplicity, we will assume that patterns contain only one asterisk, which is always in the final  path segment (e.g., foo*txt or ../bar/*.c). The wildcard only applies to file names, not paths, so  any names it produces will be in the same directory.

Open the directory that would contain these files and search for names matching the pattern. Add each name to the argument list.

If no names match the pattern, add the original token to the argument list.

Redirection   The special tokens < and > introduce input and output redirection, respectively. The first argument following the redirection flag is not added to the argument list, but instead kept as a redirection filename.

Note that redirection can occur anywhere in a command. Tokens following the redirection file name are treated as regular arguments.

Pipelines   The special token  |  separates two programs in a pipeline, each of which will have a separate argument list and file redirection targets. Additionally, mysh will use pipe() to arrange that standard output for the first process will be written to standard input for the second process.

For simplicity, you may limit mysh to pipelines involving two processes.

Conditionals   If the first token is then or else, it is not added to the argument list.  Instead, mysh will check the exit status of the previously executed command. A command beginning with then is only executed if the previous command succeeded, and a command beginning with else is only executed if the previous command failed.

Conditionals apply to the entire command, even if it includes a pipeline. Use of then or else after a  |  is invalid.

Examples   This command,

then  foo  <  bar  baz

includes a conditional, and describes the argument list (“foo”, “baz”), and redirects standard input to “bar”.

This command,

foo  bar  <  baz  |  quux  *.txt  >  spam

executed in a directory containing files “bacon.txt” and “eggs.txt” will start a pipeline with two processes.

The first has argument list (“foo”, “bar”), with input redirected to “baz”.

The second has argument list (“quux”, “bacon.txt”, “eggs.txt”), with output redirected to spam”.

2.1    Program name

The first argument determines which program is executed. This argument may be the name of a program, apath to a program file, or a “built-in” command.

Pathnames   If the first argument contains a slash character, /, mysh will assume it is a path to an executable file.

Bare  names   If the  first  argument  does  not  contain  a slash,  and is not one of the built-in names, mysh will search for the program.  For this assignment, we will only search the directories /usr/local/bin, /usr/bin, and /bin, in that order.

You may use access() to determine whether a file with the appropriate name exists in these directories without needing to traverse the directory itself.

Note that most commands are executed in this way and are not built in to the shell. Do not attempt to implement common Unix commands (cp, mv, cat, etc.) yourself!

Built-in commands   The commands cd, pwd, and which are implemented by mysh itself.  (Pro- grams by these names may exist in the three directories above, but you should ignore those.)

cd is used to change the working directory.  It expects one argument, which is a path to a directory. mysh should use chdir() to change its own directory.  cd should print an error message and fail if it is given the wrong number of arguments, or if chdir() fails.

pwd prints the current working directory to standard output.   This can be obtained using getcwd().

which takes a single argument, which is the name of a program. It prints the path that mysh would use if asked to start that program.  (That is, the result of the search used for bare names.) which prints nothing and fails if it is given the wrong number of arguments, or the name of a built-in, or if the program is not found.

While these built-in commands are implemented by the shell, and do not usually involve creating a subprocess, mysh should otherwise treat them as regular commands and allow them to participate in redirection and pipes.  (All three of these commands will simply ignore standard input, but pwd and which do have output that could be sent to a file or piped to another program.)

2.2    Wildcards

A token containing an asterisk (*) is a wildcard (or glob), representing a set of files whose names match a pattern.  We allow a single asterisk in a file name or in the last section of a path name. Any file in the specified directory whose name begins with the characters before the asterisk and  ends with the characters after the asterisk is considered to match.

In other words, any name where we can replace a sequence of zero or more characters with an asterisk to obtain the pattern is considered a match.

Thus, foo*bar matches filenames in the working directory that begin with “foo” and end with “bar” .

Similarly, baz/foo*bar matches filenames in the subdirectory “baz” that begin with “foo” and end with bar”.

When a command includes a wildcard token, it will be replaced in the argument list by the list of names matching the pattern.

If no names match the pattern, mysh should pass the token to the command unchanged.

Hidden files   Patterns that begin with an asterisk, such as *.txt, will not match names that begin with a period.

2.3    Redirection

The tokens < and > are used to specify files for a program to use as standard input and standard output, respectively. The token immediately following the < or > is understood as a path to the file, and is not included in the argument list for the program.

Normally, a child process will use the same standard input and output as its parent.  When using file redirection, mysh should open the specified file in the appropriate mode and use dup2() in the child process to redefine file 0 or 1 before calling execv().

When redirecting output, the file should be created if it does not exist or truncated if it does exist. Use mode 0640 (S_IRUSR|S_IWUSR|S_IRGRP) when creating.

If myshis unable to open the file in the requested mode, it should report an error and set the last exit status to 1.

2.4    Pipes

A pipe connects standard input from one program to the standard output from another, allowing  data to “flow” from one program to the next. myshallows for a single pipe connecting two processes.

Before starting the child processes, use pipe() to create a pipe, and then use dup2() to set standard output of the first process to the write end of the pipe and standard input of the second process to the read end of the pipe.

If the pipe cannot be created, mysh should print an error message and set the last exit status to 1. Otherwise, the exit status of the command is the exit status of the last sub-command.

2.5    Additional notes

When a wildcard does not match any files, it should be included in the argument list as-is.  For simplicity, we do not permit wildcards in the token immediately following a < or >.

Note that more than one token may have a wildcard.  Be sure to handle them in a uniform manner.

It is recommended that you use execv() to execute programs, as it can easily be given a variable number of arguments. Note that the arraylist code from earlier can be used to efficiently create an array by repeatedly appending items to its end, without needing to know in advance how long the array will be. This is ideal for creating an argument list in the presence of wildcard tokens.

Do not use execvp() or execlp() to start programs. They will search a different set of directories than the ones mandated for mysh.

A single command can redirect both standard input and standard output.  These are not required to be given in any particular order. The following commands are equivalent:

foo  quux  <  bar  >  baz

foo  <  bar  quux  >  baz

foo  >  baz  <  bar  quux

Pipes and redirection can both override the standard input or output of a subprocess. In the event that both are specified, the redirection takes precedence. For example, this command line

foo  |  bar  <  baz

will send the output of foo to a pipe, but bar will have its standard input connected to the file baz, not the pipe.  (The data sent to the pipe will be lost, as presumably intended.)

3    Submission

A system will be provided for you to declare your partnership prior to submission, details forthcoming. Determine in advance which partner will be responsible for submitting the completed assignment. Communication and coordination is key to a successful project!

Submit a Tar archive containing:

. Your source code file(s), including testing code

. Your make file

. Your README

. Any test inputs used by your testing process

Your README should be a plain text document containing the names and NetIDs of both partners.

Your test plan should be part of the README, and detail your testing strategy and test cases. Describe the scenarios you considered it important to check and how you performed those checks. Note that having a good test suite is an excellent way to detect errors that have been introduced or  reintroduced into your code.