Week 2
The Crunchy Shell to the
Soft and Chewy Kernel
Sarah Diesburg
8/3/2010
COP4610 / CGS5765
1
Why is the Shell Important?
Shells provide us with a way to interact with
the core system
Executes programs on our behalf
Shows us our stuff
No OS should be without one!
Can think of a shell as built around a
component
So what are some examples of shells?
2
How do we Crack the Shell?
In other words, how will our shell interact with
the soft and chewy kernel?
/proc file system
System calls
3
What is /proc?
Virtual file system created to pass information
via files to and from the kernel
Inside /proc directory
Often used in kernel debugging or when a
developer does not want to create a new
system call
4
Why /proc?
You will be reading and displaying a bunch of
goodies from the kernel through the /proc
interface
Date
Up Time
Idle Time
CPU Info
Memory Info
Kernel Version
Terminal Process Details
5
How /proc?
Looking to our good friend bash
$> cat /proc/cpuinfo
(Hint your viewproc command
should do something similar)
6
System Calls
What are they again?
The traditional way to ask the OS to do
something on the users behalf
Some important ones
Fork()
Execv()
7
Shell Basics (Project 1)
8
Inside main()
Continuous loop
Parse user input
Make something happen
9
Inside main()
while(1)
{
10
Inside main()
while(1)
{
*/ Get user input */
11
Inside main()
while(1)
{
*/ Get user input */
*/ Exit? */
12
Inside main()
while(1)
{
*/ Get user input */
*/ Exit? */
*/ Do something with input */
13
Inside main()
while(1)
{
*/ Get user input */
*/ Exit? */
*/ Do something with input */
*/ Reset the shell */
14
I/O Streams
Standard I/O Stream File descriptor
Standard input (stdin) 0
Standard output (stdout) 1
Standard error (stderr) 2
Examples
scanf() reads from standard input
fscanf() reads from any I/O stream
printf() prints to standard output
fprintf() prints to any I/O stream
15
Environmental Variables
Gives programs specific information about your
environemnt, such as your execution paths
sarah@trogdor:~$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/games
May be set by you or other shell scripts (like .bashrc)
sarah@trogdor:~$ export TEST=hello
sarah@trogdor:~$ echo $TEST
hello
16
Environmental Variables
char *getenv(const char *name);
Returns value of an environmental variable
Returns NULL if not found
17
Environmental Variables
Important examples
$PATH
$USER
$PWD
(Hint: may want to use these in building the
shell prompt)
18
Command Line Parsing
Standard input (stdin) is the source of input
data for command line programs
Parsing can be done in multiple stages
Strip the whitespace
Interpret the command
Resolve the pathname
Variable expansion
I/O redirection
Final execution
19
Parsing Example
Too much
ls -l a whitespace!
20
Parsing Example
ls -l a
Parse out the
ls la whitespace
21
Parsing Example
ls -l a
ls la
Resolve the
pathname
/bin/ls -la
22
Resolving Pathnames?
You may not just pass ls to the execute
command
What is ls?
You must search all of the users paths
stored in the $PATH environmental variable
23
Finding full pathname for ls
$PATH=/usr/local/bin:/usr/bin:/bin
Does /usr/local/bin/ls exist?
No
Does /usr/bin/ls exist?
No
Does /bin/ls exist?
Yes!
24
Processes
Our shell process must continually run
but we need to execute other stuff on the users
behalf
How can we create children processes to
do our work?
Fork!
25
Fork
Child pid==0
Parent pid==something else
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
pid_t pid;
if ((pid = fork()) == 0) {
printf(I am a child with pid %d\n, pid);
} else {
printf(I am the parent with pid %d\n, pid);
}
return 0;
}
26
Exec
Once we have created a child process, we
need the child to execute a command for us
Exec has many forms
Execl
Execlp
Execle
Execv
Execvp
Must use execv() for project 1!
27
Execv()
Takes two arguments
Absolute pathname
Array of string arguments, ending with NULL
What is an absolute pathname?
Full execution path starting from root /
/bin/ls
28
Execv()
char *command = /bin/ls;
char *argv[] =
{/bin/ls, -l, NULL};
execv(command,argv);
Execv() replaces running image of child with
a new process!
29
Wait up?
How does our parent process know to wait
until the child is done?
waitpid()
Performing a wait allows the system to
release the resources associated with the
child
If child is not waited on, it will become a zombie!
30
Zombie?
Process that shows up with a Z status or
the word <defunct>
Child process has terminated, but parent has
not waited on it
Child process stays allocated on the system
until
Wait() or waitpid() is called by the parent
The parent exits, and init adopts the zombie
processes and performs a wait()
31
waitpid()
int waitpid(pid_t pid, int
*status, int options);
pid type of children to wait on
For this project, pid==0 to mean wait for any child
process created by our parent
*status returns the status of the child process
options return if additional things have
happened to the child
32
waitpid()
Comment waitpid() line to see a defunct
process for 10 seconds through ps
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main() {
pid_t pid;
if ((pid = fork()) == 0) {
printf(I am a child with pid %d\n, pid);
} else {
printf(I am the parent\n);
waitpid(-1, status, 0);
sleep(10);
}
return 0;
}
33
In Summary
Pieces necessary for some of project 1
Part 1 Command line parsing
Part 2 Environmental variables and expansion
Part 3 Command execution
Part 7 Built-ins including /proc
Hint: chdir() may be of some use
Part 8 The prompt via parsing environmental
variables and updating $PWD
34
Next Recitation
Part 4 Input/output redirection
Part 5 Pipes
Part 6 Background processing
35
Any Questions?
Time for some of my demos?