Unix File API's: Chapter 7 & 8-Terrance Chan Chapter 7 & 8 - Richard Stevens
Unix File API's: Chapter 7 & 8-Terrance Chan Chapter 7 & 8 - Richard Stevens
#include <sys/types.h>
#include <fcntl.h>
int open (const char *pathname, int access
mode , mode_t permission);
Pathname : It can be absolute path
name or a relative path
name
Access_mode : An integer which
specifies how file is to be
accessed by calling
process
Access mode flag Use
O_APPEND
O_CREAT
O_EXCL
O_TRUNC
O_NONBLOCK
O_NOCTTY
O_APPEND : appends data to end of file
O_TRUNC : if the file already exists,
discards its contents and
sets file size to zero
O_CREAT : creates the file if it does not
exist
O_EXCL : used with O_CREAT only.
This flag causes open to
fail if the file exists
O_NONBLOCK : specifies that any
subsequent read or write
on the file should be non
blocking
#include <sys/types.h>
#include <unistd.h>
Int creat (const char* pathname,mode_t mode)
Read
#include <sys/types.h>
#include <unistd.h>
ssize_t read (int fdesc ,void* buf, size_t size);
Write
#include <sys/types.h>
#include <unistd.h>
ssize_t read (int fdesc ,void* buf, size_t size);
Close
#include <unistd.h>
int close (int fdesc);
#include <sys/types.h>
#include <unistd.h>
Off_t sleek (int fdesc , off_t pos, int whence)
Pos :
specifies a byte offset to be added to a
reference location in deriving the new file
offset value
Whence location reference
SEEK_CUR current file pointer
address
SEEK_SET the beginning of a
file
SEEK_END the end of a file
link
#include <unistd.h>
int link (const char* cur_link ,const char*
new_link)
unlink
#include <unistd.h>
int unlink (const char* cur_link );
#include <sys/types.h>
#include <unistd.h>
int stat (const char* path_name,struct
stat* statv)
int fstat (const int fdesc,struct stat* statv)
Struct stat
{
dev_ts t_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
off_t st_size;
time_t st_mtime
time_t st_ctime
};
If pathname specified in stast is a
symbolic link then the attributes of the
non-symbolic file is obtained
To avoid this lstat system call is used
It is used to obtain attribites of the
symbolic link file
{
switch (st_mode &S_IFMT)
{
case S_IFDIR: ofs << 'd'; return;
/* directory file */
case S_IFCHR: ofs << 'c'; return;
/* character device file */
case S_IFBLK: ofs << 'b'; return;
/* block device file */
case S_IFREG: ofs << ' '; return;
/* regular file */
case S_IFLNK: ofs << 'l'; return;
/* symbolic link file */
case S_IFIFO: ofs << 'p'; return;
/* FIFO file */
}
}
/* Show access permission for owner, group,
others, and any special flags */
static void display_access_perm ( ostream&
ofs, int st_mode )
{
char amode[10];
for (int i=0, j= (1 << 8); i < 9; i++, j>>=1)
amode[i] = (st_mode&j) ? xtbl[i] : '-
';
/* set access permission */
/* set access permission */
if (st_mode&S_ISUID)
amode[2] = (amode[2]=='x') ? 'S' : 's';
if (st_mode&S_ISGID)
amode[5] = (amode[5]=='x') ? 'G' : 'g';
if (st_mode&S_ISVTX)
amode[8] = (amode[8]=='x') ? 'T' :
't';
ofs << amode << ' ';
}
/* List attributes of one file */
static void long_list (ostream& ofs, char*
path_name)
{
struct stat statv;
struct group *gr_p;
struct passwd *pw_p;
if (stat (path_name, &statv))
{
perror( path_name );
return;
}
display_file_type( ofs, statv.st_mode );
display_access_perm( ofs, statv.st_mode );
ofs <<
statv.st_nlink;
/* display hard link count */
gr_p =
getgrgid(statv.st_gid);
/* convert GID to group name */
pw_p =
getpwuid(statv.st_uid);
/*convert UID to user name */
ofs << ' ' << pw_p->pw_name << ' ' <<
gr_p->gr_name << ' ';
if ((statv.st_mode&S_IFMT) == S_IFCHR ||
(statv.st_mode&S_IFMT)==S_IFBLK)
ofs << MAJOR(statv.st_rdev) << ','
<< MINOR(statv.st_rdev);
else ofs << statv.st_size;
/* show file size or major/minor no. */
ofs << ' ' << ctime (&statv.st_mtime);
/* print last modification time */
ofs << ' ' << path_name <<
endl; /* show file name */
}
/* Main loop to display file attributes one file
at a time */
int main (int argc, char* argv[])
{
if (argc==1)
cerr << "usage: " << argv[0] << " <file
path name> ...\n";
else while (--argc >= 1) long_list( cout,
*++argv);
return 0;
}
Access
#include <unistd.h>
int access (const char* path_name, int flag);
The flag contains one or more bit flags
Bit flags USE
#include <unistd.h>
#include <sys/types.h>
#include <utime.h>
int utime (const char* path_name,
struct utimbuf* times);
Struct utimbuf
{
time_t actime;
time_t modtime;
};
FILE AND RECORD LOCKING
UNIX systems allow multiple processes to
read and write the same file concurrently.
It is a means of data sharing among
processes.
Why the need to lock files?
It is needed in some applications like
database access where no other process
can write or read a file while a process is
accessing a file-locking mechanism.
File locking is applicable only to regular
files
Shared and exclusive locks
A read lock is also called a shared lock and a
write lock is called an exclusive lock.
These locks can be imposed on the whole
file or a portion of it.
A write lock prevents other processes from
setting any overlapping read or write locks
on the locked regions of the file. The
intention is to prevent other processes from
both reading and writing the locked region
while a process is modifying the region.
A read lock allows processes to set
overlapping read locks but not write
locks. Other processes are allowed to
lock and read data from the locked
regions.
A mandatory locks can cause problems:
If a runaway process sets a mandatory
exclusive lock on a file and never unlocks
it, no other processes can access the
locked region of the file until either a
runaway process is killed or the system is
rebooted.
If a file lock is not mandatory it is
advisory. An advisory lock is not enforced
by a kernel at the system call level
The following procedure is to be followed
Try to set a lock at the region to be
accessed. if this fails, a process can
either wait for the lock request to become
successful or go do something else and
try to lock the file again.
After a lock is acquired successfully, read
or write the locked region
Release the lock
Advisory locks
A process should always release any lock
that it imposes on a file as soon as it is
done.
An advisory lock is considered safe, as no
runaway processes can lock up any file
forcefully. It can read or write after a fixed
number of failed attempts to lock the file
Drawback: the programs which create
processes to share files must follow the
above locking procedure to be
cooperative.
FCNTL file locking
intfcntl(intfdesc,intcmd_flag,;)…
Cmd_flag Use
F_SETLK Sets a file lock. Do not block if this
cannot succeed immediately.
F_SETLKW Sets a file lock and blocks the
calling process until the lock is
acquired.
F_GETLK Queries as to which process locked
a specified region of a file.
For file locking the third argument is struct
flock-typed variable.
struct flock
{
short l_type;
short l_whence;
off_t l_start;
off_t l_len;
pid_t l_pid;
};
l_type and l_whence fields of flock
Opendir:
DIR*opendir (const char* path_name);
This opens the file for read-only
Readdir:
Dirent* readdir(DIR* dir_fdesc);
The dir_fdesc value is the DIR* return
value from an opendir call.
Closedir :
int closedir (DIR* dir_fdesc);
It terminates the connection between the
dir_fdesc handler and a directory file.
Rewinddir :
void rewinddir (DIR* dir_fdesc);
Used to reset the file pointer associated
with a dir_fdesc.
Rmdir API:
int rmdir (const char* path_name);
Used to remove the directory files. Users
may also use the unlink API to remove
directories provided they have superuser
privileges.
TheseAPI’srequirethatthedirectoriesto
be removed be empty, in that they contain
nofilesotherthan“.”and“..”links.
Device file APIs
Device files are used to interface physical
devices (ex: console, modem) with
application programs.
Device files may be character-based or
block-based
The only differences between device files
and regular files are the ways in which
device files are created and the fact that
lseek is not applicable for character
device files.
To create:
int mknod(const char* path_name, mode_t
mode,int device_id);
The mode argument specifies the access
permission of the file
The device_id contains the major and
minor device numbers. The lowest byte of
a device_id is set to minor device number
and the next byte is set to the major
device number.
MAJOR AND MINOR NUMBERS
When a process reads from or writes to a
device file, the file’s major device number
is used to locate and invoke a device
driver function that does the actual data
transmission.
The minor device number is an argument
being passed to a device driver function
when it is invoked. The minor device
number specifies the parameters to be
used for a particular device type.
A device file may be removed via the
unlink API.
If O_NOCTTY flag is set in the open call,
the kernel will not set the character device
file opened as the controlling terminal in
the absence of one.
The O_NONBLOCK flag specifies that the
open call and any subsequent read or
write calls to a device file should be
nonblocking to the process.
FIFO File APIs
These are special device files used for
interprocess communication.
These are also known as named files
#include <stdlib.h>
void _Exit (int status);
void exit (int status);
#include <unistd.h>
void _exit (int status);
The exit status is undefined if
#include <stdlib.h>
int atexit (void (*fun) void));
Atexit function calls these functions in rev
erse order of their registration
NULL
Memory layout of a C program
Text segment – sharable copy
Initialized data segment – variables
heap
Uninitialised data Intialized to 0 by exec
initialised data
Text
Low address
Shared libraries
Shared libraries remove the common
library routines from the executable file ,
instead maintaining a single copy of the
library routine some where in memory that all
processes reference
Advantage: reduces size of executable file
#include <stdio.h>
int setjmp (jmp_buf env);
void longjmp (jmp_buf env, int val);
env is of type jmp_buf ,this data type is
form of array that is capable of holding all
information required to restore the status
of the stack to the state when we call
longjmp.
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit (int resource ,struct
rlimit *rlptr);
int setrlimit (int resource ,const struct
rlimit *rlptr);
Struct rlimit
{
rlim_t rlim_cur; /*soft limit*/
rlim_t rlim_max; /*hard limit */
}
• Soft link can be changed by any process
to a value <= to its hard limit
• Any process can lower its hard limit to a
value greater than or equal to its soft
limit
• Only super user can raise hard limit
RLIMIT_CORE – max size in bytes of a
core file
RLIMIT_CPU – max amount of CPU time in
seconds
RLIMIT_DATA – max size in bytes of data
segment
RLIMIT_FSIZE – max size in bytes of a file
that can be created
RLIMIT_MEMLOCK – locked in-memory
address space
RLIMIT_NOFILE – max number of open
files per process
RLIMIT_NPROC – max number of child
process per real user ID
RLIMIT_OFILE – same as RLIMIT_NOFILE
RLIMIT_RSS – max resident set size in
bytes
RLIMIT_STACK – max size in bytes of the
stack
RLIMIT_VMEM – max size in bytes of the
mapped address space
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "ourhdr.h"
#definedoit(name) pr_limits(#name, name)
static voidpr_limits(char *, int);
int main(void)
{
doit(RLIMIT_CORE);
doit(RLIMIT_CPU);
doit(RLIMIT_DATA);
doit(RLIMIT_FSIZE);
#ifdef RLIMIT_MEMLOCK
doit (RLIMIT_MEMLOCK);
#endif
#ifdef RLIMIT_NOFILE /* SVR4 name */
doit (RLIMIT_NOFILE);
#endif
#ifdef RLIMIT_OFILE /* 44BSD name */
doit (RLIMIT_OFILE);
#endif
#ifdef RLIMIT_NPROC
doit (RLIMIT_NPROC);
#endif
#ifdef RLIMIT_RSS
doit(RLIMIT_RSS);
#endif
doit(RLIMIT_STACK);
#ifdef RLIMIT_VMEM
doit(RLIMIT_VMEM);
#endif
exit(0);
}
static void
pr_limits(char *name, int resource)
{
struct rlimit limit;
if (getrlimit(resource, &limit) < 0)
err_sys("getrlimit error for %s", name);
printf("%-14s ", name);
if (limit.rlim_cur == RLIM_INFINITY)
printf("(infinite) ");
else
printf("%10ld ", limit.rlim_cur);
if (limit.rlim_max == RLIM_INFINITY)
printf("(infinite)\n");
else
printf("%10ld\n", limit.rlim_max);
}
Kernel support for processes
Kernel region table
Process table
data
parent File table
text
Fd table
child
Fd table
stack
data
Besides open files the other properties inhe
rited by child are
Real user ID, group ID, effective user ID, ef
fective group ID
Supplementary group ID
Process group ID
Session ID
Controlling terminal
#include <sys/types.h>
#include <unistd.h>
pid_t fork (void);
The new process created by fork is called
child process
The function is called once but returns
twice
The return value in the child is 0
The return value in parent is the process
ID of the new child
The child is a copy of parent
Child gets a copy of parents data , heap
and stack
Instead of completely copying we can use
COW ( copy on write) technique
#include <sys/types.h>
#include "ourhdr.h"
int glob = 6;
/* external variable in initialized data */
char buf[ ] = "a write to stdout\n";
int main(void)
{
int var;
/* automatic variable on the stack */
pid_t pid;
var = 88;
if (write(STDOUT_FILENO, buf, sizeof(buf)
-1) != sizeof(buf)-1)
err_sys("write error");
printf("before fork\n");
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0)
{ /* child */
glob++; /* modify variables */
var++;
}
else
sleep(2);
/* parent */
The process ID
Parent process ID
by child
Pending alarms are cleared for the child
exit(0);
}
wait3 and wait4 functions
#include <sys/types.h>
#include "ourhdr.h"
static void charatatime(char *);
int main(void)
{
pid_t pid;
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0)
{
charatatime("output from child\n");
}
else
{
charatatime("output from parent\n");
}
exit(0);
}
static void
charatatime(char *str)
{
char *ptr;
int c;
setbuf(stdout, NULL);
/* set unbuffered */
for (ptr = str; c = *ptr++; )
putc(c, stdout);
}
/*altered program*/
#include <sys/types.h>
#include "ourhdr.h"
static void charatatime(char *);
Int main(void)
{
pid_t pid;
TELL_WAIT();
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0)
{
WAIT_PARENT(); /* parent goes first */
charatatime("output from child\n");
}
else {
charatatime("output from parent\n");
TELL_CHILD(pid);
}
exit(0);
}
static void charatatime(char *str)
{
char *ptr;
int c;
setbuf(stdout, NULL);
/* set unbuffered */
for (ptr = str; c = *ptr++; )
putc(c, stdout);
}
exec functions
execl execle
execlp
Build argv Build argv Build argv