System Calls
System Calls
AGENDA
• Operating System Modes
• File System Calls
• File Descriptor
• File Permissions
• File System Calls with Programs
Operating System Modes
User Mode MODE bit = 1
1 1
0 0
Modes of Operating System Execute System
Call
Tag Description
EACCES Permission to read or search a component of the filename was denied.
int main(void) {
long max;
char *buf;
max= pathconf(“/”,_PC_PATH_MAX);
buf=(char*)malloc(max);
if (getcwd(buf,max)==NULL)
{ printf(Error: Could not obtain current working directory.\n"); }
else
{ printf(“Path: current working directory is: %s\n", buf); }
return 0;
}
chdir() system call
Syntax in C language: int chdir(const char *pathname);
Parameters :
– pathname : The Directory path which the user want to make the current
working directory
Returns :
– On success: zero is returned and the current working directory changes to the
specified path.
– On failure: Returns -1. errno is set to indicate the error.
Functioning:
– The getcwd() function copies an absolute pathname of the current working
directory to the array pointed to by buf, which is of length size.
chdir() system call errors
ENOENT A directory component in pathname does not exist or is a dangling symbolic link.
ENOMEM Insufficient kernel memory was available.
ENOSPC The device containing pathname has no room for the new directory.
ENOSPC The new directory cannot be created because the user’s disk quota is exhausted.
ENOTDIR A component used as a directory in pathname is not, in fact, a directory.
EPERM The filesystem containing pathname does not support the creation of directories.
EROFS pathname refers to a file on a read-only filesystem.
rmdir() system call
Syntax in C language: int rmdir(const char *pathname);
Parameters :
– pathname : The Directory to be removed.
Returns :
– On success: zero is returned.
– On failure: Returns -1. errno is set to indicate the error.
Functioning:
– Removes a directory, pathname, provided that the directory is empty.
– If no process currently has the directory open, rmdir() deletes the directory itself.
The space occupied by the directory is freed for new use.
– If one or more processes have the directory open when it is removed, the
directory itself is not removed until the last process closes the directory.
rmdir() system call errors
Tag Description
EACCES Write access to the directory containing pathname was not allowed, or one of the directories in the path prefix of
pathname did not allow search permission.
EBUSY pathname is currently in use by the system or some process that prevents its removal. On Linux this means
pathname is currently used as a mount point or is the root directory of the calling process.
EFAULT pathname points outside your accessible address space.
EINVAL pathname has . as last component.
ELOOP Too many symbolic links were encountered in resolving pathname.
ENAMETOOLONG pathname was too long.
ENOENT A directory component in pathname does not exist or is a dangling symbolic link.
ENOMEM Insufficient kernel memory was available.
ENOTDIR pathname, or a component used as a directory in pathname, is not, in fact, a directory.
ENOTEMPTY pathname contains entries other than . and .. ; or, pathname has .. as its final component.
EPERM The directory containing pathname has the sticky bit (S_ISVTX) set and the process’s effective user ID is neither the
user ID of the file to be deleted nor that of the directory containing it, and the process is not privileged (Linux: does
not have the CAP_FOWNER capability).
EPERM The filesystem containing pathname does not support the removal of directories.
EROFS pathname refers to a file on a read-only filesystem.
mkdir() and rmdir() system call
Example
int main(int argc,char *argv[])
{ int md, rd;
//DIR *ds;
struct dirent *dir;
if(argc!=3)
{
printf("give sufficient filenames \n");
exit(1);
}
md = mkdir(argv[1],0777);
if(md == 0)
printf("%s directory is created\n",argv[1]);
else
printf("%s directory is not created\n",argv[1]);
rd = rmdir(argv[2]);
if(rd == 0)
printf("%s directory is removed\n",argv[2]);
else
printf("%s directory is not removed\n",argv[2]);
}
opendir() system call
Syntax in C language: DIR* opendir(const char *path);
Parameters :
– path : path name of the directory to be opened.
Returns :
– On success: a DIR pointer.
– On failure: Returns NULL. errno is set to indicate the error.
Functioning:
– opens a directory stream corresponding to the directory named by the path
argument.
– Note: add # include<dirent.h>
closedir() system call
Syntax in C language: int closedir(DIR *dirp);
Parameters :
– dirp : DIR pointer from opendir
Returns :
– On success: returns 0.
– On failure: Returns -1. errno is set to indicate the error.
Functioning:
– closes the directory stream associated with dirp.
– Note: add # include<dirent.h>
readdir() system call
Syntax in C language: struct dirent *readdir (DIR *dirp );
Parameters :
– dirp : A pointer to a DIR that refers to the open directory stream to be read.
Returns :
– On success: A pointer to a dirent structure describing the next directory entry in
the directory stream
– On failure: Returns NULL. errno is set to indicate the error.
Functioning:
– Describes the next directory entry in the directory stream associated with dirp.
– If readdir() reached the end of the directory stream, the errno global variable is
not changed.
– If readdir() was not successful, the errno is set.
– Note: add # include<dirent.h>
dirent structure
struct dirent {
ino_t d_ino; /* inode number */
char d_name[256]; /* filename */
…
};
Program to display the files in current
working directory.
int main(int argc,char *argv[])
{
DIR *ds; struct dirent *dir;
ds = opendir(argv[1]);
if(ds == NULL)
printf("directory %s is not opened\n",argv[1]);
else
printf(“Directory opened/n”);
printf("list of files and directories\n");
while((dir = readdir(ds)) != NULL)
printf("%s\n",dir->d_name);
if((closedir(ds)) == 0)
printf("%s is successfully closed\n",argv[1]);
else
printf("%s is not successfully closed\n",argv[1]);
}
getpid() & getppid() system calls
● To obtain current process id, use getpid() system call.
● To obtain parent process id, use getppid() system call.
#include <stdio.h>
#include <unistd.h>
#include<sys/types.h>
int main() {
printf("I am process %ld\n",(long)getpid());
printf("My Parent process is %ld\n",(long)getppid());
}
fork() and exec() system calls
• fork()
– It creates a new process which is an identical copy of an existing process.
– The newly created process will contain all the instructions and data of its parent process.
– Hence it executes the same parent process.
– fork() is the only way to create new processes in UNIX
• exec()
– This on the other hand re-initializes the existing process with some other designated program.
– It does not create a new process.
– It merely flushes the current context of a program and loads a new context (new program).
– exec() call is the only way to execute programs in UNIX. In fact, the kernel boots itself using the
exec() call.
fork() system call
• fork() call creates a “new” process.
• The child process’ context will be the same as the parent process.
• After a fork() call, two copies of the same context exist, one belonging to the child
and another to the parent.
• Contrast this to exec(), where a single context will exist because of child context
over-writing the parent.
• Return values: The child receives a 0 as return value from fork() and the parent
receives the process-ID of the child.
• # include<unistd.h>
• int fork(void);
• /*Returns child process-ID and 0 on success and -1 on error */
fork() system call
#include<stdio.h>
int main()
{
printf(“************ Before Fork************\n”);
fork();
printf(“************ After Fork *************\n”;
return 0;
}
Multiple Fork System Call
Repeated fork() calls (also known as fork bombs) #include <stdio.h>
can eventually lead to resource exhaustion and
may collapse the system. #include <sys/types.h>
Program to demonstrate repeated forking int main()
int main(void){ {
int cnt=0; fork();
int pid; fork();
for(cnt=0;cnt<3;cnt++){
fork();
pid=fork();
printf("Now in process %d\n",getpid()); printf("hello\n");
} return 0;
return 0; }
}
how many new processes would be created?
Output
S.no Fork() system call in Print output Parent process Child Process
. program “Hello”
1 Fork() 2 1 1
2 Fork() 4 1 3
Fork()
3 Fork() 8 1 7
Fork()
Fork()
exec() System Call
⚫exec() re-initializes the existing process with some other designated program.
⚫It does not create a new process.
⚫It merely flushes the current context of a program and loads a new context (new
program).
⚫exec() call is the only way to execute programs in UNIX.
exec() System Call family
1. int execl(const char *path, const char *arg, …, NULL);
2. int execlp(const char *file, const char *arg, …, NULL );
3. int execv(const char *path, char *const argv[]);
4. int execvp(const char *file, char *const argv[]);
5. int execle(const char *path, const char *arg, …, NULL, char * const envp[] );
6. int execve(const char *file, char *const argv[], char *const envp[]);
exec() System Call family execAB
S.No. A B Name Meaning
4 e Environment pointer
5 l p execlp Execute file with arguments explicitly in call and PATH search
7 l e execle Execute file with argument list and manually passed environment pointer
8 v e execve Execute file with argument vector and manually passed environment pointer
exec() System Call family syntax
int execl (
const char *path, /* Program pathname*/
const char *arg0, /*First Argument(filename) */
const char *arg1, ……
(char *) NULL /* Arg list terminator */
);
int execle ( int execlp (
const char *path, /* Program pathname */ const char *file, /* Program filename */
const char *arg0, /*First Argument(filename) */ const char *arg0, /*First Argument(filename) */
const char *arg1, const char *arg1,
… …
(char *) NULL, /* Arg list terminator */ (char *) NULL /* Arg list terminator */
char *const envv[] /* Environment vector */
);
);
exec() System Call family syntax
int execv (
const char *path, /* Program pathname */
char* const argv[] /* Argument vector */
);
# include<stdio.h>
# include<unistd.h>
int main(int argc, char ** argv){
printf("Hello World!");
execl("/bin/echo","echo","Print","from","execl",NULL);
return 0;
}
In execl() system function takes the path of the executable binary file (i.e. /bin/ls) as the
first and second argument. Then, the arguments (i.e. -lh, /home) that you want to pass to
the executable followed by NULL. Then execl() system function runs the command and
prints the output. If any error occurs, then execl() returns -1. Otherwise, it returns
nothing.
Other exec system calls
• The other exec calls are very similar to execl(). They provide the following three
features that are not available in execl().
• Arguments can be put into a vector/array instead of explicitly listing them in the
execl call. This feature is useful if the arguments are not known at compile time.
• Search an executable using the value of the PATH environment variable. When this
feature is used, we don’t have to specify the complete path in the exec call.
• Manually passing an explicit environment pointer instead of automatically using
environ.
2. execv() System Call
Syntax: int execv (
const char *path, /* Program pathname */
char* const argv[] /* Argument vector */
);
Parameters:
• Like execl(), this function takes the path of the executable binary file (i.e. /bin/ls) as
the first argument.
• With execv(), you can pass all the parameters in a NULL terminated array argv. The
first element of the array should be the path of the executable file.
Return Value:
• If any error occurs, then execl() returns -1.
• Otherwise, it returns nothing.
execv() System call Example
#include <unistd.h>
int main(void) {
char *binaryPath = "/bin/ls";
char *args[] = {binaryPath,"-lh", "/home", NULL};
execv(binaryPath, args);
return 0;
}
3. execlp() System Call
Syntax: int execlp (
const char *file, /* Program filename */
const char *arg0, /*First Argument(filename) */
const char *arg1,
…
(char *) NULL /* Arg list terminator */
);
Parameters:
• First argument is the program filename - the full path of the executable file is not required. The PATH
Environment variable is used to find the executable file location.
• Parameters to the executable are passed as arguments in a sequential order and terminated with a
null pointer.
Return Value:
• If any error occurs, then execlp() returns -1.
• Otherwise, it returns nothing.
execlp() System call Example
#include <unistd.h>
int main(void) {
char *programName = "ls";
char *arg1 = "-lh";
char *arg2 = "/home";
execlp(programName, programName, arg1, arg2, NULL);
return 0;
}
In execlp() system function takes the Command_name (example: ls). Then, the arguments
(i.e. -lh, /home) that you want to pass to the executable followed by NULL. Then execlp()
system function runs the command and prints the output. If any error occurs, then
execlp() returns -1. Otherwise, it returns nothing.
4. execvp() System Call
Syntax: int execvp (
const char *file, /* Program filename */
char* const argv[] /* Argument vector */
);
Parameters:
• First argument is the program filename - the full path of the executable file is not
required. The PATH Environment variable is used to find the executable file location.
• Like execv(), you can pass all the parameters in a NULL terminated array argv. The
first element of the array should be the name of the executable file.
Return Value:
• If any error occurs, then execvp() returns -1.
• Otherwise, it returns nothing.
execvp() System call Example
#include <unistd.h>
int main(void) {
char *programName = "ls";
char *args[] = {programName, "-lh", "/home", NULL};
execvp(programName, args);
return 0;
}
Works the same way as execv() system function. But, the PATH environment variable is
used. So, the full path of the executable file is not required just as in execlp().
5. execle() System Call
Syntax: int execle (
const char *path, /* Program pathname */
const char *arg0, /*First Argument(filename) */
const char *arg1,
…
(char *) NULL, /* Arg list terminator */
char *const env[] /* Environment vector */
);
Parameters:
• Like execl(), this function takes the path of the executable binary file (i.e. /bin/ls) as the first and second
argument.
• The environment variables are passed as an array envv. The last element of the envv array should be NULL.
All the other elements contain the key-value pairs as string.
Return Value:
• If any error occurs, then execle() returns -1.
• Otherwise, it returns nothing.
execle() System call Example1
#include <unistd.h>
int main(void) {
char *binaryPath = "/bin/bash";
char *arg1 = "-c";
char *arg2 = "echo YOU ARE THE PART OF $A $B";
char *const env[] = {“A=BITS“,”B=PILANI”, NULL};
Works just like execl() but you can provide your own environment variables along with it.
The environment variables are passed as an array envp. The last element of the envp array
should be NULL. All the other elements contain the key-value pairs as string.
execle() Program Example2
#include <unistd.h>
int main(void) {
char *binaryPath = "/bin/bash";
char *arg1 = "-c";
char *arg2 = "echo Visit $HOSTNAME:$PORT from your browser.";
char *const env[] = {"HOSTNAME=www.bits.com", "PORT=8080", NULL};
execle(binaryPath, binaryPath,arg1, arg2, NULL, env);
return 0;
}
6. execve() System Call
Syntax: int execve (
const char *path, /* Program pathname */
char *const argv[], /* Argument vector */
char *const env[] /* Environment vector */
);
Parameters:
• Like execl(), this function takes the path of the executable binary file (i.e. /bin/ls) as the first
argument.
• With execv(), you can pass all the parameters in a NULL terminated array argv. The first element of
the array should be the path of the executable file. The environment variables are passed as an array
envv. The last element of the envv array should be NULL. All the other elements contain the key-
value pairs as string.
Return Value:
• If any error occurs, then execle() returns -1.
• Otherwise, it returns nothing.
execve() System call Example1
#include <unistd.h>
int main(void) {
char *binaryPath = "/bin/bash";
char *const args[] = {binaryPath, "-c", "echo YOU ARE THE PART OF $A $B ", NULL};
char *const env[] = {“A=BITS“,”B=PILANI”, NULL};
Just like execle() you can provide your own environment variables along with execve(). You
can also pass arguments as arrays as you did in execv().
wait() System Call
• The wait() system call suspends execution of the current process until one of its
children terminates or a signal is received. At that moment, the caller resumes its
execution.
• One of the main purposes of wait() is to wait for completion of child processes.
• If any process has more than one child processes, then after calling wait(), parent
process has to be in wait state if no child terminates.
• In the case of a terminated child, performing a wait allows the system to release the
resources associated with the child; if a wait is not performed, then terminated the
child remains in a "zombie" state
wait() System Call
Returns:
• If any process has no child process then wait() returns immediately “-1”.
• If the parent process has a child that has terminated, that child's PID is returned and
it is removed from the process table.
• If only one child process is terminated, then return a wait() returns PID of the
terminated child process.
• If the parent process has a child that is not terminated, it (the parent) is suspended
till it receives a signal. The signal is received as soon as a child dies.
Fork() and wait() system call
#include<stdio.h>
if (pid == -1) /* check for error in fork */{
#include<unistd.h>
perror("fork failed");
int main(void)
exit(1);}
{
if (pid == 0)
int pid;
printf("I am the child process. %d\n",getpid());
int status;
else{
printf("Hello World!\n");
wait(&status); /* parent waits for child to finish */
pid = fork( );
printf("Child Process with pid = %d completed with a status
%d\n",pid,status);
printf("I am the parent process.%d\n",getpid());}
}
Fork() and wait() system call
Output:
Hello World!
I am the child process. 24995
Child Process with pid = 24995 completed with a status 0
I am the parent process. 24994
Multiple fork() and wait() system calls
#include<stdio.h>
else if (second == -1){
#include<unistd.h>
perror("2nd fork: something went wrong\n") ; exit(1);
int main(){
}
pid_t whichone, first, second ; int howmany, status ;
printf("This is parent\n");
if((first = fork()) == 0) /* Parent spawns 1st child */ {
howmany = 0;
printf("I am the first child, & my ID is %d\n", getpid());
while(howmany < 2) {/* Wait Twice */
sleep(10); exit(0); }
whichone = wait(&status);
else if(first == -1) {
howmany++;
perror("1st fork: something went wrong\n") ; exit(1); }
if(whichone == first)
else if((second = fork()) == 0) /* Parent spawns 2nd child
printf("First child exited\ncorrectly");
*/ {
else
printf("I am the second child, & my ID is %d\n", getpid( ));
printf("Second child exited\ncorrectly");}}
sleep(15); exit(0);
}
Multiple fork() and wait() system calls
Output:
I am the first child, & my ID is 77
This is parent
I am the second child, & my ID is 78
<after 10 seconds>
First child exited
Correctly
<after 15 seconds>
Second child exited
correctly
Zombie Process
• On Unix and Unix-like computer operating systems, a zombie process or defunct
process is a process that has completed it’s execution but still has an entry in the
process table.
• This entry is still needed to allow the parent process to read its child’s exit status.
• You cannot kill zombie process directly because it is already dead.
• To kill the zombie process, you should kill the parent process. However, if the parent
process is init (i.e., 1), then only thing you can do is reboot.
• It takes very tiny memory(description info) but will take process ID which is limited.
So, it is better not to have zombie process.
Zombie Process
init(1)
F1(19)
Z or Z+ [Defunct]
(Died
process)
You can’t kill a zombie process(F1) because it’s already dead – like an actual zombie.
Zombie Process
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
// Fork returns process id // in parent process
pid_t child_pid = fork();
// Parent process
if (child_pid > 0)
sleep(50);
// Child process
else
exit(0);
return 0;
}
Zombie Process
int main() {
int pid ;
pid = fork(); /* Duplicate. Child and parent continue from here */
if ( pid != 0){
printf("Its a Parent Process with pid=%d, goes to sleep\n",getpid());
/* pid is non-zero, so I must be the parent */
while (1) /* Never terminate and never execute a wait ( ) */
sleep (10); /* stop executing for 10 seconds */
}
else{
printf("Child Process with pid = %d\n",getpid());
/* pid is zero, so I must be the child */
exit (1) ; /* exit with any number */
}
}
Getting Rid of Zombie Processes
• Send the signal with the kill command, replacing pid in the command below with the
parent process’s PID:
$ kill defunct-pid
• Still zombie process(defunct) present:
$ kill -9 defunct-pid(Force kill)
• Still zombie process(defunct) present:
$ kill parent-id-of-defunct-pid
If you still find defunct process eating up RAM then last and final solution is to reboot
your machine.
Orphan Process
int main()
{
/* Create a child process */
int pid = fork();
if (pid > 0)
printf("In parent process");
/* Note that pid is 0 in child process & negative if fork() fails */
else if (pid == 0){
sleep(30);
printf("In child process");
}
return 0;
}
Orphan Process Example
main()
{
int pid ;
printf("I'am the original process with PID %d and PPID %d.\n", getpid(), getppid()) ;
pid = fork ( ) ; /* Duplicate. Child and parent continue from here*/
if ( pid != 0 ) /* pid is non-zero, so I must be the parent*/
{
printf(“I’m the parent with PID %d and PPID %d.\n", getpid(), getppid()) ;
printf("My child's PID is %d\n", pid ) ;
}
else /* pid is zero, so I must be the child */
{
sleep(4); /* make sure that the parent terminates first */
printf("I'm the child with PID %d and PPID %d.\n", getpid(), getppid()) ;
}
printf ("PID %d terminates.\n", getpid()) ;
}
Orphan Process
Output:
I'am the original process with PID 2219 and PPID 1754.
I'm the parent with PID 2219 and PPID 1754.
My child's PID is 2220
PID 2219 terminates.
After 4 seconds
I'm the child with PID 2220 and PPID 1.
PID 2220 terminates.
Orphan Process Example
main()
{
int pid ;
printf("I'am the original process with PID %d and PPID %d.\n", getpid(), getppid()) ;
pid = fork ( ) ; /* Duplicate. Child and parent continue from here*/
if ( pid != 0 ) /* pid is non-zero, so I must be the parent*/
{
printf(“I’m the parent with PID %d and PPID %d.\n", getpid(), getppid()) ;
printf("My child's PID is %d\n", pid ) ;
sleep(10); /* make sure that the parent terminates first */
}
else /* pid is zero, so I must be the child */
{
sleep(20); /* make sure that the parent terminates first */
printf("I'm the child with PID %d and PPID %d.\n", getpid(), getppid()) ;
}
printf ("PID %d terminates.\n", getpid()) ;
}
vfork() System call Example
int main() {
pid_t pid = vfork(); //creating the child process Output:
if (pid == 0) //if this is a child process Child process started
{ finished process
printf("Child process started\n");
Now I’m coming back to parent process
}
else //parent process execution finished process
{
printf("Now I’m coming back to parent process\n");
}
printf("finished process”);
return 0;
}
Corresponding fork() Example
int main() {
pid_t pid = fork(); //creating the child process
Output:
if (pid == 0) //if this is a child process Now I’m coming back to parent process
{ finished process
printf("Child process started\n"); Child process started
} finished process
else //parent process execution
{
printf("Now I’m coming back to parent process\n");
}
printf("finished process”);
return 0;
}
fork() comparison with vfork()
System call create a new process and blocks the parent process.
BASIS FOR
FORK() VFORK()
COMPARISON
Basic Child process and parent process has separate Child process and parent process shares the same address
address spaces. space.
Execution Parent and child process execute Parent process remains suspended till child process
simultaneously. completes its execution.
Modification If the child process alters any page in the If child process alters any page in the address space, it is
address space, it is invisible to the parent visible to the parent process as they share the same address
process as the address space are separate. space.
Copy-on-write fork() uses copy-on-write as an alternative vfork() does not use copy-on-write.
where the parent and child shares same pages
until any one of them modifies the shared
page.
Outcome of Usage Behavior is predictable Behavior is not predictable
Pipes (Byte Stream)
Shell Command
$ ls | wc –l
to execute the above command, the shell creates two processes, executing ls and wc,
respectively using fork() and exec() system calls.
two processes are connected to the pipe so that the writing process (ls) has its
standard output (file descriptor 1) joined to the write end of the pipe, while the
reading process (wc) has its standard input (file descriptor 0) joined to the read end of
the pipe.
Pipes are unidirectional
Creating and Using Pipes
#include <unistd.h>
int pipe(int filedes[2]);
Returns 0 on success, or –1 on error
A successful call to pipe() returns two open file descriptors in the array filedes: one for the read end of
the pipe ( filedes[0]) and one for the write end ( filedes[1]).
we can use the read() and write() system calls to perform I/O on the pipe.
File descriptor
filedes:
one for the read end of the pipe ( filedes[0]) and
one for the write end ( filedes[1]).
Pipe between parent and child process
int main()
{
int filedes[2];
if (pipe(filedes) == -1) printf("error creating pipe \n");
else
printf("Pipe Created Successfully\nfiledes[0] = %d,filedes[1] = %d\n",filedes[0],filedes[1]);
switch (fork()) { /* Create a child process */
case -1:
printf("fork failed \n");
case 0: /* Child */ $ ./a.out
printf("Child Process.......%d\n",getpid());
Pipe Created Successfully
if (close(filedes[1]) == -1) printf("failed to close \n");
else printf("Closed write end, read file descriptor = %d\n",filedes[0]);
filedes[0] = 3,filedes[1] = 4
break; Child Process.......1966
default: /* Parent */ Closed write end, read file descriptor = 3
wait(NULL); Parent Process.......1965
printf("Parent Process.......%d\n",getpid()); Closed read end, write file descriptor = 4
if (close(filedes[0]) == -1) printf("failed to close \n");
else
printf("Closed read end, write file descriptor = %d\n",filedes[1]);
break; } }
Using a pipe to communicate between a parent and child process
Int main(int argc, char *argv[]) if (numRead == -1)
{ printf("read error\n");
int pfd[2]; if (numRead == 0)
char buf[BUF_SIZE]; break; /* End-of-file */
ssize_t numRead; if (write(STDOUT, buf, numRead) != numRead)
if (argc != 2 || strcmp(argv[1], "--help") == 0) printf("child - partial/failed write\n");
printf("%s %s \n", argv[0],argv[1]); write(STDOUT, "\n", 1);
if (pipe(pfd) == -1) if (close(pfd[0]) == -1)
printf("failed to create pipe\n"); printf("failed to close");
exit(EXIT_SUCCESS);
else
default:
printf("Pipe created successfully\n read file des =
%d, write file des = %d\n",pfd[0],pfd[1]); /* Parent- write to pipe */
switch (fork()) { printf("Parent continues %d\n",getpid());
case -1: if (close(pfd[0]) == -1)/* Read end is unused */
printf("failed to fork\n"); printf("failed to close read end in - parent\n");
if(write(pfd[1],argv[1],strlen(argv[1]))!=strlen(argv[1]))
case 0:
printf("parent - partial/failed write\n");
/* Child - reads from pipe */
else
printf("ChildCreated.........%d\n",getpid());
printf("Parent successfully write to pipe (%d):
numRead = read(pfd[0], buf, BUF_SIZE); %s\n",pfd[1],argv[1]);
printf("text read from pipe by child : %s , numRead if (close(pfd[1]) == -1)
= %d\n",buf,numRead);
printf("failed to close");
wait(NULL);
exit(EXIT_SUCCESS);
}
}
Usage of Pipes to execute
commands ls|wc
• ls | wc
o Create a pipe in the parent
o Fork a child
o Duplicate the standard output descriptor to write end of pipe
o Exec ‘ls’ program
o In the parent wait for the child.
o Duplicate the standard input descriptor to read end of pipe
o Exec ‘wc’ program
ls|wc command using pipe
int main(){
int fd[2]; // array of 2 size fd[0] is for reading and fd[1] is for writing over a pipe
pipe(fd);
if(!fork())
{
close(1); // closing normal stdout
dup(fd[1]); // making stdout same as fd[1]
close(fd[0]); // closing reading part of pipe
execlp("ls","ls",NULL);
}
else
{
close(0); // closing normal stdin
dup(fd[0]); // making stdin same as fd[0]
close(fd[1]);
File descriptor Abbreviation
execlp("wc","wc",NULL);
} 0 Stdin
} 1 Stdout
2 Stderr
Creating a pipe using mkfifo()
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int res;
char Path= “~/Desktop/Tutorial9/fifo”;
res =mkfifo(Path , 0777);
printf("Pipe Created Successfully\n");
}
//Sender side with write system call //Reader side with read system call
//Reader side with read system call //Sender side with write system call
//Blocking MODE //Blocking MODE
//User2: Reader //User1: Reader
// Send.c //Receiver.c
int main() int main()
{ {
int fd; int fd;
char * myfifo = "~/Desktop/Tutorial9/fifo"; char * myfifo = "~/Desktop/Tutorial9/fifo";
mkfifo(myfifo, 0777); mkfifo(myfifo, 0777);
printf("Name pipe create\n"); printf("Name pipe create\n");
char arr1[80], arr2[80]; char arr1[80], arr2[80];
while (1) { while (1) {
fd = open(myfifo, O_WRONLY); // Open FIFO for write only fd1 = open(myfifo,O_RDONLY); // Open FIFO for read only
fgets(arr2, 80, stdin); read(fd1, str1, 80);
write(fd, arr2, strlen(arr2)+1); printf("User1: %s\n", str1);
close(fd); close(fd1);
fd = open(myfifo, O_RDONLY); // Open FIFO for read only fd1 = open(myfifo,O_WRONLY); // Open FIFO for write only
read(fd, arr1, sizeof(arr1)); fgets(str2, 80, stdin);
printf("User2: %s\n", arr1); write(fd1, str2, strlen(str2)+1);
close(fd); } close(fd1); }
return 0; return 0;
} }
Message Queues
• Data transfer happens through fixed Message Queue Item
length messages.
Next
• Messages are delimited.
Type
• Messages are transferred in its entirety.
Size
• Transfer of partial message is not
allowed.
message
Structure of Message Queue struct msg {
struct msg *msg_next; /* pointer to next message on q */
System Message long msg_type; /* message type */
Permission Structure ushort msg_ts; /* message text size */
Queue Structure short msg_spot; /* message text map address */
First Message };
Last Message
.
.