\documentclass{ictlab}

\RCS $Revision: 1.1 $

\usepackage{alltt,key,color,answer2,float}
\usepackage[nolineno,noindent]{lgrind}
%\usepackage[leftnum,lineno5,noindent]{lgrind}
\ifx\pdftexversion\undefined \else
  \usepackage[pdfpagemode=None,pdfauthor={Nick Urbanik}]{hyperref}
\fi

\renewcommand*{\subject}{Operating Systems and Systems Integration}

\newcommand*{\labTitle}{Processes: Writing a Simple Shell}

\definecolor{light-blue}{rgb}{0.4,0.4,1}
\newcommand*{\gl}[1]{\textcolor{light-blue}{#1}} % good link
\newcommand*{\ex}[1]{\textcolor{green}{#1}} % executable file
\newcommand*{\bl}[1]{\colorbox{red}{\textcolor{white}{\textbf{#1}}}} % bad link

\renewcommand{\floatpagefraction}{0.75} % default is .5, to increase
% density.
\renewcommand*{\bottomfraction}{0.6} % default is 0.3
\renewcommand*{\topfraction}{0.85} % default is 0.7
\renewcommand*{\textfraction}{0.1} % default is 0.2

\setlength{\extrarowheight}{1pt}
\floatstyle{ruled}
\floatname{program}{Program}
\newfloat{program}{tbh}{lop}
\begin{document}

\section{Aim}
\label{sec:aim}

The successful student will write a very simple shell, i.e., a program
that can interactively start other programs.

\section{Background}
\label{sec:background}

A \emph{shell} is a program that can start other programs.  A real
shell can do lots of other things (it supports a programming language,
for example), but here we keep it very simple, and restrict it to
starting other programs.


\subsection{How do you Run an External Program as a New Process?}
\label{sec:new-process}
\begin{itemize}
\item Replace the instructions in a running process with a new set of
  instructions, using the \texttt{exec} function
\item First make an exact copy of your process using \texttt{fork()}
\item Then replace the contents of this new process with another
  program, using \texttt{exec()}.
\end{itemize}


\subsection{The \texttt{exec*()} functions}
\label{sec:exec}
\begin{itemize}
\item There are six kinds of \texttt{exec*()} function; see \texttt{man
  3 exec} and \texttt{man 2 execve}
\item We will use \texttt{execl()}:
  \begin{alltt}
int execl(const char *path, const char *arg, ...);
\end{alltt}
  Parameter number:
  \begin{enumerate}
  \item gives full path of the program file you want to execute
  \item gives name of the new process
  \item specifies the command line arguments you pass to the program
  \item (in this example) is a \texttt{NULL} pointer to end the paramter list.
    We \emph{must} always put a \texttt{NULL} pointer at the end of this list.
  \end{enumerate}

\item Program~\vref{prg:fork-1} is a simple example, without error checking.
  \begin{program}
    %\smallskip%
\vspace*{-2ex}
%[
#include <stdio.h>
#include <unistd.h> 

int main()
{
        printf( "hello world\n" );
        int pid = fork();
        printf( "fork returned %d\n", pid );
        if ( pid == 0 )
                execl( "/bin/ls", "ls", NULL );
        else
                printf( "I'm the parent\n" );
}
%]
\vspace*{-3ex}
    \caption{A simple program using \texttt{fork()} and
      \texttt{execl()}.  It does no error checking.}
    \label{prg:fork-1}
  \end{program}
\end{itemize}

As we saw in the lecture, Linux and Unix provide simple system calls
to manage processes:
\begin{alltt}
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
\end{alltt}
\textnormal{Returns \emph{twice}; returns 0 if child, returns child's
\PID if parent, returns \(-1\) if error.}

\subsection{What Happens Between fork() and exec() and After?}
\label{sec:what-fork-exec-do}

\begin{itemize}
\item Before calling \texttt{fork()}:
  \begin{itemize}
  \item There is one process, the parent process.
  \end{itemize}
\item After calling \texttt{fork()}:
  \begin{itemize}
  \item Two process are running, both still have the original code
  \end{itemize}
\item After calling \texttt{exec()}:
  \begin{itemize}
  \item The child process, which called \texttt{exec()}, now has
    completely different code.
  \end{itemize}
\end{itemize}

Program~\vref{prg:print} is called \texttt{print.c} and prints a number $n$
times.
  \begin{program}
    %\smallskip%
%\begin{verbatim}
\vspace*{-2ex}
%[
#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{
        // argv[0] is the program name
        int num = atoi( argv[1] );
        int loops = atoi( argv[2] );
        int i;
        for ( i = 0; i < loops; ++i )
                printf( "%d ", num );
}
%]
\vspace*{-3ex}
%\end{verbatim}
    \caption{A simple program \texttt{print.c} that takes two numbers as
      parameters, and repeats the first number the number of times
      given by the second number.}
    \label{prg:print}
  \end{program}
  Program~\vref{prg:call-print} is called \texttt{call-print.c}, and
  is written to call the program \texttt{print.c},
  using \texttt{execl()}.
  \begin{program}
    %\smallskip%
%\begin{verbatim}
\vspace*{-2ex}
%[
#include <stdio.h>
#include <unistd.h>

int main()
{
        printf( "hello world\n" );
        int pid = fork(); 
        printf( "fork returned %d\n", pid );
        if  ( pid == 0 )
                execl( "./print", "print", "1", "100", NULL ); 
        else
                execl( "./print", "print", "2", "100", NULL );
}
%]
\vspace*{-3ex}
%\end{verbatim}
    \caption{A program \texttt{call-print.c} that uses
      \texttt{execl()} to call program~\vref{prg:print},
      \texttt{print.c}, in two separate processes.}
    \label{prg:call-print}
  \end{program}
  
\subsection{Exercise Set 1}
\label{sec:exercise-1}
\begin{enumerate}
\item Copy the programs from the network filesystem at
  \texttt{/home/nfs/processes-and-threads} to a new directory in your
  \texttt{\$HOME}\e.
\item Compile and run program~\vref{prg:fork-1}.
\begin{alltt}
$ \textbf{gcc -o fork-1 fork-1.c}
$ \textbf{./fork-1} 
\end{alltt}

\item Modify the program \vref{prg:fork-1} so that it runs the
  program \texttt{ls} with the option \texttt{-l}.
\item Compile the program \texttt{print.c} in program~\vref{prg:print}
  and run it:
\begin{alltt}
$ \textbf{gcc -o print print.c}
$ \textbf{./print 10 5}
\end{alltt}
Try running it with a few different numbers.

\item Compile the main program \texttt{call-print.c} in
  program~\vref{prg:call-print} and run it.
\item Try printing each number: 100 times, 1000 times, 10,000 times,
  100,000 times.
\end{enumerate}


\subsection{Implementing a Shell}
\label{sec:shell}
\begin{alltt}
Prompt user
Get command
If not time-to-exit
     Fork new process
     Replace new process with either \texttt{who}, \texttt{ls} or \texttt{uptime}
Read next command 
\end{alltt}
Program~\vref{prg:simple-shell-program} is a simple example shell.
\begin{program}
  %\smallskip%
%\begin{verbatim}
\vspace*{-2ex}
%[
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void print_menu( void )
{
       printf( "Enter 1=who, 2=ls, 3=uptime -> " );
}

int main()
{
        int cmd; 
        print_menu();
        scanf( "%d", &cmd );
        while ( cmd != 0 ) { 
                int pid = fork(); 
                if ( pid == 0 ) { 
                        if ( cmd == 1 )
                                execl( "/usr/bin/who", "who", NULL ); 
                        if ( cmd == 2 )
                                execl( "/bin/ls", "ls", NULL ); 
                        if ( cmd == 3 )
                                execl( "/usr/bin/uptime", "uptime", NULL ); 
                        exit( 1 ); 
                }
                /* add: wait( NULL ); here */
                print_menu();
                scanf( "%d", &cmd );
        }
}
%]
\vspace*{-3ex}
%\end{verbatim}
  \caption{A simple shell program, \texttt{shell-1.c.}}
  \label{prg:simple-shell-program}
\end{program}

\subsection{Exercise Set 2}
\label{sec:exercise-2}

\begin{enumerate}
\item Implement program~\vref{prg:simple-shell-program} and run it.
  What if you give it a wrong number?
\item Open a second shell window, and monitor the creation of zombie
  processes by executing the command \texttt{watch -n1 "ps aux \textbar{} grep ' [Z] '"}
\item Modify the program to print an error message if a command is not
  supported.
\item Add the the call to \texttt{wait()} in the loop before printing
  the menu.  What is the difference in the behaviour of your program?
\item Modify the program and add two more commands to your shell, such
  as \texttt{date} and \texttt{hostame}.
\item Modify the program so that it will exit cleanly if it reads end
  of file.  You can manually provide end of file to a process reading
  standard input by pressing \key{Control-d}.  Hint: see \texttt{man
    scanf}.
\item Examine the program \texttt{simplesh.c}.  Modify it to implement
  background or foreground processes.
\end{enumerate}


\end{document}
