Lab Two (2) Forks, Wait, getenv, strtok, execl
SYNOPSIS
#include
#include
pid_t fork(void);
DESCRIPTION
fork() creates a child process that differs from the parent process only
in its Process Identification (PID) and Parent Process Identification (PPID),
and in the fact that resource utilizations are set to 0. File locks and pending
signals are not inherited.
A call to the fork() system call returns a zero (0) to the child process
and returns the child PID to the parent.
Simple example calling fork().
#include
//example 1
int main()
{
pid_t pid;
pid=fork();
printf("my value of pid is %d\n",pid);
}
Another simple example showing that the father gets the son's PID.
//example 2
int main()
{
pid_t pid;
pid=fork();
if(pid==0)
printf("I am the son. I don't know my own PID. \n");
else
printf("I am the father. I don't know my own PID, but my son's PID is %d.\n" , pid);
}
An example showing that multiple calls to fork creates more processes by a factor of 2.
(Question: When will hello be printed? Answer: When son has a son. Why?)
// example 3
void main()
{
if(fork()==fork())
printf("hello\n");
printf("bye\n");
}
The wait system call.
Use these libraries:
#include
#include
Function prototype:
pid_t wait(int *status)
wait() waits for process termination to occur.
The wait function suspends execution of the current process until a
child has exited, or until a signal is delivered whose action is to
terminate the current process or to call a signal handling function.
If a child has already exited by the time of the call (a so-called
"zombie" process), the function returns immediately. Any system
resources used by the child are freed. I.e. the child is not really dead
until his parent process 'waits' for him. This is so in order to allow
the parent process to find out the child's exit status after he terminated.
// example 4
/*In the following example the father will wait until the child process
terminates and returns its pid to its father.
*/
#include
main()
{
int status;
pid_t pid,child1;
if(fork()==0)
printf("child is running\n");
else
{
wait(&status); //father will wait here
printf("child has terminated\n");
}
}
// example 5
/*In the following example the father will wait until one of his child processes
terminates. That child's PID is returned to its father. The first child to die
will have his PID stored in the variable pid in the father process.
*/
main()
{
int status;
pid_t pid,child1,child2;
if((child1=fork())==0)
printf("child 1 is running\n");
else
{
if ((child2=fork())==0)
printf("child 2 is running\n");
else
{
pid=wait(&status);
if(pid==child1)
printf("child1 has terminated first\n");
else
printf("child2 has terminated first\n");
printf("goodbye\n");
}
}
}
// example 6
/*In the following example the father will wait until
both child processes terminate. The last child to die will have his PID
stored in the variable pid in the father process.
*/
#include
main()
{
int status;
pid_t pid,child1,child2;
if((child1=fork())==0)
printf("child 1 is running\n");
else
{
if ((child2=fork())==0)
printf("child 2 is running\n");
else
{
pid=wait(&status);
pid=wait(&status);
if(pid==child1)
printf("child1 has terminated last\n");
else
printf("child2 has terminated last\n");
printf("goodbye\n");// only father prints this
}
}
}
An environment variable is a variable inherited by the child
process from his parent process. It is usually used to set
parameters for how that child should run. For example,
the shell's child processes can be made to know the user's mode
running his shell. (ex. which editor he uses.)
Non-system call getenv. The function gets an environment variable from
the system.
Library:
#include
Functional prototype:
char *getenv(const char *name);
Example to get the environment variable HOME (HOME is the home directory
of the user).
# include
int main(void)
{
char *s_ptr;
s_ptr=getenv("HOME");
printf("%s \n", s_ptr);
}
Example to get the environment variable PATH
# include
int main(void)
{
char *s_ptr;
s_ptr=getenv("PATH");
printf("%s \n",s_ptr);
}
Non-system function (found in section 3 of man pages)
strtok - extract tokens from strings
SYNOPSIS
#include
char *strtok(char *s, const char *delim);
DESCRIPTION
A `token' is a nonempty string of characters not occurring in the
string delim, followed by \0 or by a character occurring in delim.
The strtok() function can be used to parse the string s into tokens.
The first call to strtok() should have s as its first argument. Subse-
quent calls should have the first argument set to NULL. Each call
returns a pointer to the next token, or NULL when no more tokens are
found.
If a token ends with a delimiter, this delimiting character is over-
written with a \0 and a pointer to the next character is saved for the
next call to strtok(). The delimiter string delim may be different for
each call.
/* strtok1.c by Ari Cirota 2002
This is a short example demonstrating the use of strtok.
The strtok function is used to split a string
NOTE: This program must be compiled with g++
*/
#include
#include
void main (void)
{
char string[]="This is just a boring sentence";
char Token[]=" ";
char* tokenPtr;
cout<<"The string to be tokenized is: "<
#include
main()
{
int status;
// char ch, str[20];
status=system("vmstat 1");
printf("hello");
}
Non-system call execl and execv.
SYNOPSIS
#include
int execl( const char *path, const char *arg, ...);
int execv( const char *path, char *const argv[]);
extern char **environ;
DESCRIPTION
The exec family of functions replaces the current process image with a
new process image.
The initial argument for these functions is the pathname of a file
which is to be executed.
execl expects a complete list of the commands and all the arguments
you want it to be run with, followed by NULL (or 0).
execv expects its second parameter to be a pointer to an array
where the array itself contains a list of the command and all the
arguments you want it to be run with, and followed by NULL.
Example to run ls inside a c program.
Note: Program control passes to the program ls and none of the
other statements (if there are any) in the original program are executed.
If execl occurs in a fork, then, of course, the father will continue execution
of the original program.
main()
{
printf("Files in Directory are:\n");
execl("/bin/ls","ls", "-l",0);
printf("This line will not execute.\n");//this line will not execute
}
Example with execv
Exercise
A.
Write a C program where a parent process creates two zombie children,
one child in a sleeping mode and a forth child which runs the ps -aux
command every 2 seconds in order to show the states of all 4 of the children.
(Use grep to show ONLY the 4 children processes and not all the
processes on the machine.) After 30 seconds the the zombies should
die and the sleeping process should wake up. Then the 4th child
should also finish and the parent should also finish.
For full credit, have the 4th child make sure there are no other children
before he dies. You can do this by checking the result of
the ps command.
B.
Your mission is to write and run a shell.
Your program must loop doing the following:
1] Display a prompt on the screen
2] Receive any shell command from user including parameters (like "ls -l file")
3] Carry out the command using execv or execl and fork;
your shell must "wait" for its child to terminate before displaying the prompt.
Exit loop upon receiving the string "Quit"
You must find the location of the particular shell command requested by
the user. This can only be done by looking for it in all of the addresses
in your enviroment variable "PATH".
You will need to use the getenv() function in order to get the PATH.
In order to seperate the various libraries in it you must use the
strtok() function.
If a given command was not found, display an error message
on the screen such as "Command not found." and return a prompt.
The exercize may be done together in pairs.
Each individual will be questioned on it!
The exercize must be handed in one week.
For those who want some help on beginning the program, see here
© Nachum Danzig