Create System Call: Prototype
Create System Call: Prototype
Prototype:
#include<unistd.h>
#include<sys/types.h>
int creat(const char *pathname, mode_t mode);
-- Returns: file descriptor opened for write-only if OK, -1 on error.
-- The first argument pathname specifies name of the file to be
created.
-- The second argument mode_t, specifies permission of a file to be
accessed by owner group and others.
-- The creat function can be implemented using open function as:
#define creat(path_name, mode) open (pathname, O_WRONLY | O_CREAT | O_TRUNC,
mode);
lseek() System call
• The lseek function is also used to change the
file offset to a different value.
• Thus lseek allows a process to perform
random access of data on any opened file.
• The prototype of lseek is
#include<unistd.h>
#include<sys/types.h>
off_t lseek(int fdesc, off_t pos, int whence);
• On success it returns new file offset, and –1 on
error.
• The first argument fdesc, is an integer file
descriptor that refer to an opened file.
• The second argument pos, specifies a byte
offset to be added to a reference location in
deriving the new file offset value.
• The third argument whence, is the reference
location.
• They are defined in the header <unistd.h>.
• If an lseek call will result in a new file offset
that is beyond the current end-of-file, two
outcomes possible are:
If a file is opened for read-only, lseek will fail.
If a file is opened for write access, lseek will
succeed.
The data between the end-of-file and the
new file offset address will be initialized with
NULL characters.
• lseek(fd, 0, SEEK_SET); /* Start of file */
• lseek(fd, 0, SEEK_END); /* Next byte after the
end of the file */
• lseek(fd, -1, SEEK_END); /* Last byte of file */
• lseek(fd, -10, SEEK_CUR); /* Ten bytes prior to
current location */
• lseek(fd, 10000, SEEK_END); /* 10001 bytes
past last byte of file */
Creating a file exclusively
Querying file attributes: stat(), fstat(), lstat()
• The stat, fstat and lstat function retrieves the file attributes of a given file.
• The only difference between stat and fstat is that the first argument of a stat is a file
pathname, where as the first argument of fstat is file descriptor.
• dup3():
• The dup3() system call performs the same task as
dup2(), but adds an additional argument, flags,
that is a bit mask that modifies the behavior of the
system call.
• Currently, dup3() supports one flag, O_CLOEXEC,
which causes the kernel to enable the close-on-
exec flag (FD_CLOEXEC) for the new file descriptor.
• Linux 2.6.24 and onwards also supports an
additional fcntl() operation for duplicating file
descriptors: F_DUPFD_CLOEXEC. This flag does the
same thing as F_DUPFD, but additionally sets the
close-on-exec flag (FD_CLOEXEC) for the new file
descriptor.
Example program 1:
int main()
{
char buff[11],buff1[11];
int fd=open("/home/CSE/CS054/a1.txt",O_RDONLY);
if(fd==-1)
{
perror("Open error");
exit(0);
}
printf("Original file descriptor for a1.txt=%d\n",fd);
int f=fcntl(fd,F_DUPFD,4);
if(f==-1)
{
perror("fcntl error");
exit(0);
}
printf("Duplicate file descriptor for a1.txt=%d\n",f);
int rdc=read(3,&buff,10);
if(rdc==-1)
perror("Read error:original fd");
buff[10]='\0';
printf("10 bytes of data read using original file descriptor=%s\n",buff);
int rdc1=read(f,&buff1,10);
if(rdc1==-1)
perror("Duplicate file descriptor read error");
buff1[10]='\0';
printf("10 bytes of data read using duplicate file descriptor=%s\n",buff1);
return 0;
}
Example Program 2:
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
int main()
{
char buff[21];
int
fd=open("/home/CSE/CS054/a1.txt",O_RDONLY);
if(fd==-1)
perror("Open error");
close(0);
int f=fcntl(fd,F_DUPFD,0);
if(f==-1)
perror("fcntl error");
int rdc=read(f,&buff,20);
if(rdc==-1)
perror("Read error");
buff[20]='\0';
printf("20 bytes of data read using f=%d.\nData=
%s\n",f,buff);
return 0;
}
File I/O at a Specified Offset: pread() and
pwrite()
• The pread() and pwrite() system calls operate
just like read() and write(), except that the file
I/O is performed at the location specified by
offset, rather than at the current file offset.
The file offset is left unchanged by these calls.
• Prototype:
Scatter-Gather I/O: readv() and writev()
• Instead of accepting a single buffer of data to be
read or written, these functions transfer multiple
buffers of data in a single system call. The set of
buffers to be transferred is defined by the array iov.
The integer count specifies the number of
elements in iov. Each element of iov is a structure
of the following form:
struct iovec
{
void *iov_base; /* Start address of buffer */
size_t iov_len; /* Number of bytes to transfer to/from buffer */
};
Int main(int argc, char *argv[])
{
int fd;
struct iovec iov[3];
struct stat myStruct; /* First buffer */
int x; /* Second buffer */
#define STR_SIZE 100
char str[STR_SIZE]; /* Third buffer */
ssize_t numRead, totRequired;
if (argc != 2 || strcmp(argv[1], "--help") == 0)
printf(Uage:"%s file\n", argv[0]);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
perror("open");
totRequired = 0;
iov[0].iov_base = &myStruct;
iov[0].iov_len = sizeof(struct stat);
totRequired += iov[0].iov_len;
iov[1].iov_base = &x;
iov[1].iov_len = sizeof(x);
totRequired += iov[1].iov_len;
iov[2].iov_base = str;
iov[2].iov_len = STR_SIZE;
totRequired += iov[2].iov_len;
numRead = readv(fd, iov, 3);
if (numRead == -1)
errExit("readv");
if (numRead < totRequired)
printf("Read fewer bytes than requested\n");
printf("total bytes requested: %ld; bytes read: %ld\n",(long) totRequired, (long) numRead);
Exit(0);
}
Gather output
• The writev() system call performs gather
output.
• It concatenates (“gathers”) data from all of the
buffers specified by iov and writes them as a
sequence of contiguous bytes to the file
referred to by the file descriptor fd.
• The buffers are gathered in array order,
starting with the buffer defined by iov[0].
Performing scatter-gather I/O at a
specified offset
Truncating a File: truncate() and
ftruncate()
• If the file is longer than length, the excess data is
lost.
• If the file is currently shorter than length, it is
extended by padding with a sequence of null bytes
or a hole.
• The difference between the two system calls lies in
how the file is specified.
• With truncate(), the file, which must be accessible
and writable, is specified as a pathname string. If
pathname is a symbolic link, it is dereferenced.
• The ftruncate() system call takes a descriptor for a
file that has been opened for writing.
Creating Temporary Files
• Some programs need to create temporary files
that are used only while the program is
running, and these files should be removed
when the program terminates.
• For example: many compilers create
temporary files during the compilation
process.
• Here, we describe : mkstemp().
mkstemp() function
• Generates a unique filename based on a template supplied by
the caller and opens the file, returning a file descriptor that can
be used with I/O system calls.
if (close(fd) == -1)
perror("close");
PROCESS CREATION
#include <unistd.h>
pid_t getpid(void);
Returns: process ID of calling process
pid_t getppid(void);
Returns: parent process ID of calling process
Fork() System Call
• An existing process can create a new one by calling the fork function.
#include <unistd.h>
pid_t fork(void);
Returns: 0 in child, process ID of child in parent, -1 on error.
• The reason the child's process ID is returned to the parent is that a process can have more than one child,
and there is no function that allows a process to obtain the process IDs of its children.
• The reason fork returns 0 to the child is that a process can have only a single parent, and the child can
always call getppid to obtain the process ID of its parent. (Process ID 0 is reserved for use by the kernel, so
it's not possible for 0 to be the process ID of a child.)
• Both the child and the parent continue executing with the instruction that follows the call to fork.
• For example, the child gets a copy of the parent's data space, heap, and stack.
• Note that this is a copy for the child; the parent and the child do not share these portions of memory.
Program 2
/* Program name – fork2.c */
#include<sys/types.h>
#include<unistd.h>
int main( )
{
printf(“\n Creating Child“);
fork( );
printf(“\n Child Created”);
}
Output : $ cc fork2.c
$ ./a.out
Creating Child
Child Created
Child Created
Note: The statement Creating Child is executed only once by the parent because it is
called before fork and statement Child Created is executed twice by child and parent.
Program 3
/* Program name – fork3.c */
#include<sys/types.h>
#include<unistd.h>
int main( )
{
fork();
fork();
fork();
printf(“\n Child Created”);
}
Output : $ cc fork3.c
$ ./a.out
/* what is the output */
Program 4
int glob = 6;
int main(void)
{
int var;
pid_t pid;
var = 88;
if ((pid = fork()) < 0)
{
perrror(“fork error");
}
else if (pid == 0)
{
/* child */
glob++; /* modify parent's variables */
var++;
printf(“Child pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
/* child terminates */
}
/* * Parent continues here. */
printf(“Parent pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
}
Output: $ ./a.out
Child pid = 29039, glob = 7, var = 89
Parent pid=29038, glob=6, var=88