Process Creation and Execution Using Linux Terminal

University of Jeddah
Computer Science and Artificial Intelligence Department
CCCS 225 Operating Systems
Lab # 6
Process Creation and Execution – Part II
Objective:
This lab describes how a program can replace its code with that of another executable file. Actually,
there are three distinct operations involved: creating a new child process, causing the new process
to execute a program, and coordinating the completion of the child process with the original
program.
Executing a file
A child process can execute another program using one of the exec functions. The program that
the process is executing is called its process image. Starting execution of a new program causes
the process to forget all about its previous process image; when the new program exits, the process
exits too, instead of returning to the previous process image.
This section describes the exec family of functions, for executing a file as a process image. You
can use these functions to make a child process execute a new program after it has been forked.
The functions in this family differ in how you specify the arguments, but otherwise they all do the
same thing. They are declared in the header file “unistd.h”.
Function: int execv ( const char *filename, char *const argv[ ] )
The execv() function executes the file named by filename as a new process image. The argv
argument is an array of null-terminated strings that is used to provide a value for the argv
argument to the main function of the program to be executed. The last element of this array must
be a null pointer. By convention, the first element of this array is the file name of the program
sans directory names.
The environment for the new process image is taken from the environ variable of the current
process image.
Function: int execl (const char *filename, const char *arg0, …)
This is similar to execv, but the argv strings are specified individually instead of as an array. A
null pointer must be passed as the last such argument.
Function: int execvp (const char *filename, char *const argv[ ] )
The execvp function is similar to execv, except that it searches the directories listed in the
PATH environment variable to find the full file name of a file from filename if filename does not
contain a slash.
This function is useful for executing system utility programs, because it looks for them in the
places that the user has chosen. Shells use it to run the commands that user’s type.
Function: int execlp (const char *filename, const char *arg0, …)
This function is like execl, except that it performs the same file name searching as the execvp
function.
These functions normally don’t return, since execution of a new program causes the currently
executing program to go away completely. A value of -1 is returned in the event of a failure.
If execution of the new file succeeds, it updates the access time field of the file as if the file had
been read.
Executing a new process image completely changes the contents of memory, copying only the
argument and environment strings to new locations. But many other attributes of the process are
unchanged:

The process ID and the parent process ID.

Session and process group membership.

Real user ID and group ID, and supplementary group IDs.

Current working directory and root directory. In the GNU system, the root directory is not
copied when executing a setuid program; instead the system default root directory is used for
the new program.

File mode creation mask.

Process signal mask.

Pending signals.

Elapsed processor time associated with the process; see section Processor Time.
Examples
The following programs execs the commands “ls -l -a” and “echo hello there” using the 4
most-used forms of exec. Enter each, compile, and run.
Lab1.c (Using execl)
#include
#include
int main ( ) {
execl (“/bin/ls”,
“ls”,
“-l”,
“-a”,
NULL) ;
/* program to run – give full path */
/* name of program sent to argv[0] */
/* first parameter (argv[1])*/
/* second parameter (argv[2]) */
/* terminate arg list */
printf (“EXEC Failed\n”) ;
/* This above line will be printed only on error and not otherwise */
}
Lab2.c (Using execlp)
#include
#include
int main ( ) {
execlp ( “ls”,
/* program to run – PATH Searched */
“ls”,
/* name of program sent to argv[0] */
“-l”,
/* first parameter (argv[1])*/
“-a”,
/* second parameter (argv[2]) */
NULL) ;
/* terminate arg list */
printf (“EXEC Failed\n”) ;
/* This above line will be printed only on error and not otherwise */
}
Lab3.c (Using execv)
#include
#include
int main (int argc, char *argv[] )
{
execv (“/bin/ls”,
/* program to load – full path only */
&argv[0] ) ;
printf (“EXEC Failed\n”) ;
/* This above line will be printed only on error and not otherwise */
}
Lab4.c (Using execvp)
#include #include
int main (int argc, char *argv[] )
{
execvp (“ls”,
/* program to load – PATH searched */
&argv[0] ) ;
printf (“EXEC Failed\n”) ;
/* This above line will be printed only on error and not otherwise */
Lab5.c : Write a program where a child is created to execute a command.
}
#include
#include
#include
#include
int main ( ) {
int forkresult ;
printf (“%d: I am the parent. Remember my number!\n”, getpid( ) ) ;
printf (“%d: I am now going to fork … \n”, getpid( ) ) ;
forkresult = fork ( ) ;
if (forkresult != 0)
{ /* the parent will execute this code */
printf (“%d: My child’s pid is %d\n”, getpid ( ), forkresult ) ;
}
else /* forkresult == 0 */
{
/* the child will execute this code */
printf (“%d: Hi ! I am the child.\n”, getpid ( ) ) ;
printf (“%d: I’m now going to exec ls!\n\n\n”, getpid ( ) ) ;
execlp (“ls”, “ls”, NULL) ;
printf (“%d: AAAAH ! ! My EXEC failed ! ! ! !\n”, getpid ( ) ) ;
exit (1) ;
}
printf (“%d: like father like son. \n”, getpid ( ) ) ; }
Sample Output:
vlsi> gcc lab5.c
vlsi>./a.out
24639: I am the parent. Remember my number!
24639: I am now going to fork …
24640: Hi ! I am the child.
24640: I’m now going to exec ls!
24639: My child’s pid is 24640
24639: like father like son.
vlsi> a.out
lab1.c lab11.c lab2.c lab8.c myecho
lab3.c lab9.c vlsi>
Run this program several times. You should be able to get different ordering of the output lines
(sometimes the parent finished before the child, or vice versa). This means that after the fork, the
two processes are no longer synchronized.
Process Completion Status
If the exit status value of the child process is zero, then the status value reported by wait is also
zero. You can test for other kinds of information encoded in the returned status value using the
following macros. These macros are defined in the header file “sys/wait.h”.
Macro: int WIFEXITED (int status)
This macro returns a nonzero value if the child process terminated normally with exit() or
_exit().
Here’s a program, which forks. The parent waits for the child. The child asks the user to type in a
number from 0 to 255 then exits, returning that number as status.
Examples
Lab6.c
#include
#include
#include
#include
int main ( ) {
int number=0, statval ;
printf (“%d: I’m the parent !\n”, getpid ( ) ) ;
printf (“%d: number = %d\n”, getpid ( ), number ) ;
printf (“%d: forking ! \n”, getpid ( ) ) ;
if ( fork ( ) == 0 )
{
printf (“%d: I’m the child !\n”, getpid ( ) ) ;
printf (“%d: number = %d\n”, getpid ( ), number ) ;
printf (“%d: Enter a number : “, getpid ( ) ) ;
scanf (“%d”, &number) ;
printf (“%d: number = %d\n”, getpid ( ), number ) ;
printf (“%d: exiting with value %d\n”, getpid ( ), number ) ;
exit (number) ;
}
printf (“%d: number = %d\n”, getpid ( ), number ) ;
printf (“%d: waiting for my kid !\n”, getpid ( ) ) ;
wait (&statval) ;
if ( WIFEXITED (statval) )
{
printf (“%d: my kid exited with status %d\n”,
getpid ( ), WEXITSTATUS (statval) ) ;
}
else
{
printf (“%d: My kid was killed off ! ! \n”, getpid ( ) ) ;
}
}
Process Groups
The setpgrp ( ) System Call :
The setpgrp() system call creates a new process group. The setpgid() system call
adds a process to a process group.
The synopsis for setpgrp() follows:
#include
#include
pid_t setpgrp (void);
int setpgid (pid_t pid, pid_t pgid);
If the process calling setpgrp() is not already a session leader, the process becomes one
by setting its GID to the value of its PID. setpgid() sets the process group ID of the
process with PID pid to pgid. If pgid is equal to pid then the process becomes the
group leader. If pgid is not equal to pid , the process becomes a member of an existing
process group.
Compile and Run the following program to understand the process groups creation.
Example
Lab8.c
#include
#include
#include
#include
#include
#include
int main ( )
{
int parent_pid, child_pid, fork_pid, wait_pid ;
int parent_grp, child_grp, grpid ;
int child_stat;
parent_pid = getpid ( ) ;
parent_grp = getpgrp ( ) ;
printf (“\nParent process: process ID: %ld group ID: %ld\n”,(long) parent_pid, (long)
parent_grp) ;
fork_pid = fork ( ) ;
switch (fork_pid)
{
case -1:
perror (“FORK FAILED\n”) ;
break ;
case 0:
child_pid = getpid ( ) ;
child_grp = getpgrp ( ) ;
printf (“Child process: process ID: %ld group ID: %ld ”
“parent process ID: %ld\n”, (long) child_pid,
(long) child_grp, (long) getppid ( ) ) ;
grpid = setpgrp ( ) ;
/* Change the group of child */
setpgid (child_pid, grpid) ;
child_grp = getpgrp ( ) ;
printf (“Child process again: process ID: %ld group ID: %ld ”
“parent process ID: %ld\n”, (long) child_pid,
(long) child_grp, (long) getppid ( ) ) ;
printf (“Child process: terminate with \”exit\” – value: %d\n”,
10) ;
exit (10) ;
break ;
default:
printf (“Parent process: child process with ID %ld created.\n”,
(long) fork_pid) ;
wait_pid = wait (&child_stat) ;
if (wait_pid == -1)
{
perror (“wait”) ;
errno = 0 ;
}
else
{
printf (“Parent process: child process %ld has terminated.\n”, (long) wait_pid) ;
}
}
}
Exercises
Give an example for each of these macros to explain its work:
Macro: int WIFSIGNALED (int status)
This macro returns a nonzero value if the child process terminated because it received a signal that
was not handled.
Macro: int WTERMSIG (int status)
If WIFSIGNALED is true of status, this macro returns the signal number of the signal that
terminated the child process.
Macro: int WCOREDUMP (int status)
This macro returns a nonzero value if the child process terminated and produced a core dump.
Macro: int WIFSTOPPED (int status)
This macro returns a nonzero value if the child process is stopped.
Macro: int WSTOPSIG (int status)
If WIFSTOPPED is true of status, this macro returns the signal number of the signal that caused
the child process to stop.

Save Time On Research and Writing
Hire a Pro to Write You a 100% Plagiarism-Free Paper.
Get My Paper
Still stressed from student homework?
Get quality assistance from academic writers!

Order your essay today and save 25% with the discount code LAVENDER