UNIT3 Complete
UNIT3 Complete
UNIT3 Complete
File management system calls : Regular file management system calls – open( ),
read( ), write( ), lseek( ), Close(),unlink( ),stat( ), getdents( ). Miscellaneous file
management system calls – chown( ) and fchown( ), chmod( ) and fchmod( ),
dup( ) and dup2( ), fcntl( ), ioctl( ), link( ), mknod( ), sync( ), truncate( ) and
ftruncate( ).
A single file may be opened several times and may thus have several file descriptors associated
with it.
Each file descriptors has its own private set of properties, such as the following
A file pointer that records the offset in the file it is reading or writing. When a file
descriptor is created, its file pointer is positioned at offset 0 in the file by default.
A file that indicates whether the descriptor should automatically be closed if the
process execs.
A flag indicates whether all of the output to the file should be appended to the end of
the file.
A flag that indicates whether a process should block on input from the file if the file
doesn’t currently any input.
A number that indicates a process ID or process group that should be sent a SIGIO signal
if input becomes available on the file.
File-management system calls ::
File-management system calls allow you to manipulate the full collection of regular,
directory, and special files, including:
4 disk-based files
4 terminals
4 printers
4 inter process communication facilities, such as pipes and sockets
mode
• Optional and relevant only when creating a new file, defines the file permissions. These
include read, write or execute the file by the owner, group or all users.
Identifying errors:
• How can we tell if the call failed?
– the system call returns a negative number
• How can we tell what was the error?
– Using errno – a global variable set by the system call if an error has occurred.
– Defined in errno.h
– Use strerror to get a string describing the problem
– Use perror to print a string describing the problem
#include <errno.h>
int fd;
fd = open( FILE_NAME, O_RDONLY, 0644 );
if( fd < 0 ) {
printf( "Error opening file: %s\n", strerror( errno ) );
return -1;
}
Create () ::
A new file can also be created by create function.
Create function opens the file in write mode only, but with open function you can create
or open a file in read and write mode.
Header files ::
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
Syntax::
int creat(const char *pathname, mode_t mode)
Equivalent to:
open(pathname, O_WRONLY|O_CREAT|O_TRUNC, mode)
read () ::
Once we got a file descriptor from opened file, we may read data from a file using read ()
system call.
This call takes three parameters::
i. The file descriptor to read from
ii. A buffer to read data into ,and
iii. The number of characters to read data into the buffer.
This buffer must be large enough to contain the data.
Header file required ::
#include<unitsd.h>
Syntax:
ssize_t read(int fd, void *buf, size_t nbyte);
Note :: if nbytes =0 ,the read()function returns 0 other wise no results .
write () ::
Just like read() system call ,we use write () system call ,to write data to the file .
The write operation is done in the location of these current file offset of the given file .
It writes data, in bytes as specified by the caller, from a buffer declared by the user in
the program and then writes it into the file supplied by the calling process.
Header file required ::
#include<unistd.h>
Syntax:
size_t write(int fd, const void *buf, size_t nbytes);
lseek() ::
The UNIX system file system treats an ordinary file as a sequence of bytes.
Generally, a file is read or written sequentially -- that is, from beginning to the end of
the file. Sometimes sequential reading and writing is not appropriate.
Random access I/O is achieved by changing the value of this file pointer using the lseek()
system call.
It is used for positioning a file descriptor and move the read /write file offset.
It allows the file offset to be set beyond the end of the existing data in the file
Header files ::
#include<unistd.h>
#include<sys/types.h>
Syntax::
lseek(int fildes, off_t offset, int whence)
lseek – errno
• lseek() will fail and the file pointer will remain unchanged if:
– EBADF - fd is not an open file descriptor.
– ESPIPE - fd is associated with a pipe, socket, or FIFO.
– EINVAL - Whence is not a proper value, or calculated offset is negative.
fcntl ()::
The fcntl function can change the properties of a file that is already open.
The fcntl() function performs the requested operation on the file descriptor fd.
The operation is defined by oprand is operating system dependent .
fcntl() performs the operation encoded by cmd on the file associated with the file
descriptor fd ,arg is an optional argument for cmd.
Function name ::
fcntl-file control
Header file required ::
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
Syntax::
int fcntl(int fd, int cmd, int arg)
ioctl ()::
The ioctl system call is an all purpose interface for controlling hardware devices.
ioctl (an abbreviation of input/output control) is a system call for device-specific
input/output operations and other operations which cannot be expressed by regular
system calls.
It takes a parameter specifying a request code; the effect of a call depends completely
on the request code.
Header files :
#include<unistd.h>
#include<sys/ioctl.h>
Syntax:
Int ioctl(int filedes,int request,…);
A Unix ioctl call takes as parameters:
1. an open file descriptor
2. a request code number
3. either an integer value, possibly unsigned (going to the driver) or a pointer to data
(either going to the driver, coming back from the driver, or both).
The kernel generally dispatches an ioctl call straight to the device driver, which can interpret
the request number and data in whatever way required.
Stat()
We have seen how to create files and manipulate files data. we often need more than that ;
i. what are the exact set of permission flags of the file?
ii. When it was last changed?
iii. Which user and group owns the file?
iv. How large is the file?
All these are answered by the stat() system call.
There are three variants: i. stat() ii. fstat() iii. lstat()
Function name ::
stat,lstat,fstat -- get file status
Header file required::
#include <sys/types.h>
#include <sys/stat.h>
Syntax::
int stat(const char *path, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *path, struct stat *buf);
It obtains information about the file pointed to by path.
No permissions are required on the file itself, but — in the case of stat() and lstat() —
execute (search) permission is required on all of the directories in path that lead to the
file.
stat() stats the file pointed to by path and fills in buf.
lstat() is identical to stat(), except that if path is a symbolic link, then the link itself is
stat-ed, not the file that it refers to.
fstat() is identical to stat(), except that the file to be stat-ed is specified by the file
descriptor filedes.
Structure stat::
Struct stat {
mode_t st_mode; /* file type and mode (type & permissions) */
ino_t st_ino; /* inode’s number */
dev_t st_dev; /* device number (file system) */
nlink_t st_nlink; /* number of links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID */
off_t st_size; /* size in bytes */
time_t st_atime; /* last access */
time_t st_mtime; /* last modified */
time_t st_ctime; /* last file status change */
long st_blksize; /* I/O block size */
long st_blocks; /* number of blocks allocated */
}
link() ::
The UNIX system file structure allows more than one named reference to a given file, a
feature called "aliasing".
Making an alias to a file means that the file has more than one name, but all names of
the file refer to the same data.
Any file can have multiple directory entries pointing to its i-node.
To create a link to an existing file ,you use link function .
Header file ::
#include<unistd.h>
Syntax:
Int link (const char *existing path, const char *newpath);
The function creates a new directory entry ,new path that reference the existing
file ,existing path.If new path already exists an error is returned .
The creation of the new directory entry and the increment of the link count must be an
atomic operation.
Only super user process can create a new link that points to a directory.
unlink () ::
To remove an existing directory entry ,we use the unlink function.
Header file ::
#include<unistd.h>
Syntax:
Int unlink( const char *filename);
This function removes the directory entry and decrements the link count of the file
referenced by pathname.
chown()and fchown() ::
“chown()” and “fchown()” change the owner and/or group of a file .
“chown()” causes the owner and group IDs of fileName to be changed to ownerId and
groupId, respectively.
A value of -1 in a particular field means that its associated value should remain
unchanged.
fchown():takes an open descriptor as an argument instead of a filename.
Syntax:
int chown( const char* fileName, uid_t ownerId, gid_t groupId )
int fchown( int fd, uid_t ownerId, gid_t groupId )
Example, ::
changed the group of the file “test.txt” from “music” to “cs”. which has a group ID
number of 62.
Program::
main()
{
int flag;
flag = chown(“test.txt”, -1, 62 ); /* Leave user ID uchanged */
if ( flag == -1 )
perror(“mychown.c”);
}
Syntax:
int chmod( const char* fileName, int mode )
int fchmod( int fd, mode_t mode );
Example ::
changed the permission flags of the file “test.txt” to 600 octal,which corresponds to read and
write permission for the owner only:
program::
main()
{
int flag;
flag = chmod(“test.txt”, 0600); /* Use an octal encoding */
if ( flag==-1 )
perror(“mychmod.c”);
}
dup() and dup2()::
“dup()”, “dup2()” used to duplicate file descriptors .
“dup()” finds the smallest free file-descriptor entry and points it to the same file to
which oldFd points.
“dup2()” closes newFd if it’s currently active and then points it to the same file to
which oldFd points.
The original and copied file descriptors share the same file pointer and access mode.
It return the index of the new file descriptor if successful and a value of -1 otherwise.
Syntax::
int dup( int oldFd )
int dup2( int oldFd, int newFd )
example :
created a file called “test.txt” and wrote to it via four different file descriptors:
4The first file descriptor was the original descriptor.
4The second descriptor was a copy of the first, allocated in slot 4.
4The third descriptor was a copy of the first, allocated in slot 0 ( the standard input
channel ), which was freed by the “close(0)” statement.
4The fourth descriptor was a copy of the third descriptor,copied over the existing
descriptor in slot 2 ( the standard error channel ).
#include <stdio.h>
#include <fcntl.h>
main()
{
int fd1, fd2, fd3;
fd1 = open( “test.txt”, O_RDWR | O_TRUNC );
printf(“fd1 = %d”\n”, fd1 );
write( fd1, “what’s “, 6 );
fd2 = dup(fd1); /* Make a copy of fd1 */
printf( “fd2=%d\n”, fd2);
write( fd2, “up”, 3 );
close(0); /* Close standard input */
fd3 = dup(fd1); /* Make another copy of fd1 */
printf(“fd3 = %d\n”, fd3);
write(0, “ doc“, 4);
dup2(3,2); /* Duplicate channel 3 to channel 2 */
write(2, “?\n”, 2 );
}
Process Management
When a child process terminates, its death is communicated to its parent so that the
parent may take some appropriate action.
When a shell executes a utility in the foreground, it duplicates into two shell processes;
the child-shell process replaces its code with that of the utility, whereas the parent shell
waits for the child process to terminate.
When the child process terminates, the original parent process awakens and presents
the user with the next shell prompt.
Creating a new process:: fork()
The fork() function creates a new process. The new process (the child process) is an
exact copy of the calling process (the parent process).
Header file :: #include <unistd.h>
Syntax: pid_t fork(void);
The child process inherits the following attributes from the parent process:
• Real and effective user and group IDs
• Environment settings
• Signal handling settings
• Attached shared memory segments
• Memory mapped segments
• Process group ID
• Current working directory
• File mode creation mask
• Controlling terminal
• nice value
The child process differs from the parent process in the following ways:
• The child process has a unique process ID, which also does not match any active process
group ID.
• The child process has a different parent process ID (that is, the process ID of the process
that called fork()).
• The child process has its own copy of the parent's file descriptors Each of the child's file
descriptors refers to the same open file structures as the file descriptor of the parent.
• The child process has its own copy of the parent's open directory streams.
• The child process' process execution times (as returned by times()) are set to zero.
• Pending alarms are cleared for the child.
• All semaphore adjustment values are cleared.
• File locks set by the parent process are not inherited by the child process.
• The set of signals pending for the child process is cleared.
• Interval timers are reset.
Example 1:: write a c program to explain simple fork()
#include<stdio.h>
main()
{
int pid;
pid=fork();
if(pid==0)
{
printf("iam the child and my processid is%d\n",getpid());
printf("the child's parent process id is %d\n",getppid());
}
else
{
printf("iam the parent ,my process id is %d\n",getpid());
printf("the parents parent process id is %d\n",getppid());
}
}
Output::
iam the child and my processid is 17407
the child's parent process id is 17406
iam the parent ,my process id is 17406
the parents parent process id is 17086
Orphan process::
• unix supports the concept of orphans. In Unix after execution of the fork()function, if the
parent terminates first ,the child is helpless. This creates situation of orphan
Exit ():
In general a process can terminate in two modes.
1. normal mode and
2. abnormal mode .
However in any mode a process is terminated the code which is executed by kernel is
same.
In every mode the every case (or) mode the terminating process should notify its parent
about its termination.
In the case of exit/_exit function it is done by passing an exit status as the argument to
these functions.
In the case of abnormal termination ,however ,the kernel generates a termination status
to indicate the reason for abnormal termination.
Syntax:
void exit(int status) -- terminates the process which calls this function and returns
the exit status value
Wait() ::
• You can control the execution of child processes by calling wait() in the parent.
• Wait () forces the parent to suspend execution until the child is finished.
• Wait returns the process id of a child process that finished.
• If the child finishes before the parent gets around to calling wait(),then when wait()is
called by the parent ,it will return immediately with error message.
Syntax:
int wait(status)
int *status;
Where status is a pointer to an integer where the unix system stores the value returned by the
child process .
• Wait returns the process ID of the process that ended .
• Wait () fails if any of the following condition holds:
1. the process has no children to wait for.
2.status points to an invalid address.
Example :
Write a c program to illustrate wait () and exit ()
#include<stdio.h>
#include<unistd.h>
main()
{
int status,childpid,pid;
printf("im the parent process and my pid is%d\n",getpid());
pid=fork(); /*creating child*/
if(pid!=0) /*pid is non zero ,so it must be the parent*/
{
printf("iam the parent process with pid %d and ppid %d \n",getpid(),getppid());
childpid=wait(&status);
printf("a child with pid %d teriminated with exit code %d\n",childpid,status>>8);
}
else
{
printf("iam the child process with pid%d and ppid%d\n" ,getpid(),getppid());
exit(42);
}
printf("pid%d teriminates \n",getpid());
return 0;
}
Exec ()::
• The UNIX system provides several system calls to create and end program, to send and
receive software interrupts, to allocate memory, and to do other useful jobs for a
process.
• Four system calls are provided for creating a process, ending a process, and waiting for a
process to complete.
• These system calls are fork(), the "exec" family, wait(), and exit().
• The exec is a collection of functions of Unix-like operating systems cause the running
process to be completely replaced by the program passed as an argument to the
function.
• When a process calls one of the exec functions, that process is completely replaces by
the new program, and the new program starts executing at its main function.
• A new program is run using the exec(l, lp, le,v ,vp) family of system calls.
Exec family of functions ::
• int execl ( const char *path, const char *arg, ...);
• int execlp ( const char *file, const char *arg, ...);
• int execle ( const char *path, const char *arg , ..., char * const envp[]);
• int execv ( const char *path, char *const argv[]);
• int execvp ( const char *file, char *const argv[]);
Letters added to the end of exec indicate the type of arguments:
• l argn is specified as a list of arguments.
• v argv is specified as a vector (array of character pointers).
• e environment is specified as an array of character pointers.
• p user's PATH is searched for command, and command can be a shell program.
path
• The argument specifies the path name of the file to execute as the new process .
Arguments beginning at arg0 are pointers to arguments to be passed to the new
process image. The argv value is an array of pointers to arguments.
arg0
• The first argument arg0 should be the name of the executable file. Usually it is the
same value as the path argument. Some programs may incorrectly rely on this
argument providing the location of the executable, but there is no guarantee of this nor
is it standardized across platforms.
envp
• Argument envp is an array of pointers to environment settings. The exec calls named
ending with an e alter the environment for the new process image by passing a list of
environment settings through the envp argument.
Exec family of functions ::
1. execl Takes the path name of an executable program (binary file) as its first
argument. The rest of the arguments are a list of command line arguments to the new
program (argv[]).
The list is terminated with a null pointer:
execl("/bin/cat", "cat", "f1", "f2", (char *) 0);
execl("a.out", "a.out", (char *) 0);
2. execle Same as execl(), except that the end of the argument list is followed by a pointer
to a null-terminated list of character pointers that is passed a the environment of the
new program (i.e., the place that getenv() searches for exported shell variables):
static char *env[] = { "TERM=vt100",
"PATH=/bin:/usr/bin",
(char *) 0 };
execle("/bin/cat", "cat", "f1", "f2", (char *) 0, env);
3. execv i. Takes the path name of an executable program (binary file) as it first
argument.
ii. The second argument is a pointer to a list of character pointers (like argv[])
that is passed as command line arguments to the new program:
static char *args[] = { "cat",
"f1",
"f2", (char *) 0 };
execv("/bin/cat", args);
5. execlp () Same as execl(), except that the program name doesn't have to be a full
path name, and it can be a shell program instead of an executable module:
execlp("ls",
"ls",
"-l",
"/usr",
(char *) 0);
6. execvp() searches the PATH environment variable to find the specified
program. execvp Same as execv(), except that the program name
doesn't have to be a full path name, and it can be a shell program
instead of an executable module:
static char *args[] = { "cat",
"f1",
"f2",
(char *) 0 }; execvp("cat", args);
Example:
• In this example, the program displays a small message and then replaces its code with
that of the “ls”.
#include <stdio.h>
main()
{
printf(“I’m process %d and I’m about to exec an ls -l \n”, getpid() );
execl( “/bin/ls”, “ls”, “-l”, NULL ); /* Execute ls */
printf(“This line should never be executed \n”);
}
Output:
$ myexec ---> run the program.
I’m process 13623 and I’m about to exec an ls -l
total 125
-rw-r--r-- 1 glass 277 Feb 15 00:47 myexec.c
-rwxr-xr-x 1 glass 24576 Feb 15 00:48 myexec
$_
Zombie process:
• A process that terminates cannot leave the system until its parent accepts its return
code.
• If its parent process is already dead. It’ll already have been adopted by the “init”
process, which always accepts its children ‘s return codes.
• However, if a process parent is alive, but never executes a wait() , the child process
return code will never be accepted and the process will remain a zombie.
• A zombie process doesn’t have any code, data or stack , so it doesn’t use up many
system resources , but it does continue to habit the system ‘s fixed-size process table.
Example, program created a zombie process, which was indicated in the output from the ps
utility. When I killed the parent process, the child was adopted by “init” and allowed to rest in
peace .
#include<stdio.h>
Main()
{
Int pid;
Pid=fork(); /*create a child*/
If(pid!=0)
{
while(1) /* never terminate, and never execute a wait()*/
sleep(1000);
}
else
{
exit(42);
}
}
Output:
$ zombie & …………….execute the program in the background.
[1] 13545
$ ps …………..obtain process status.
PID TT STAT TIME COMMAND
13535 p2 S 0:00 -ksh (ksh) ……….the shell
13545 p2 S 0:00 zombie ……..the parent process.
13546 p2 Z 0:00 <defunct> ……the zombie child.
13547 p2 R 0:00 ps
$ kill 13545 ………kill the parent process.
[1] Terminated zombie
$ ps ………….notice the zombie is gone now
PID TT STAT TIME COMMAND
13535 p2 S 0:00 -ksh(ksh)
13548 p2 R 0:00 ps