Oslab Inhouse Manual
Oslab Inhouse Manual
Oslab Inhouse Manual
PROCESS TERMINATION
At process termination OS need to do many activities like canceling pending timers and
signals, releasing virtual memory resources, releasing other process held system
resources such as locks, and closing files that are open. The OS records the process status
and resource usage, notifying the parent in response to a wait function.
_exit/_Exit :: will not call the user defined exit handler (ie 1 but will do the 2 )
#include <stdlib.h>
void exit(int status); // status = 0 means normal termination
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
#include <sys/wait.h>
WIFEXITED (int status) 🡪evaluates to a nonzero value when the child terminated
normally (ie status = = 0)
WEXITSTATUS (int status) 🡪 if WIFEXITED evaluates to a nonzero value, then
WEXITSTATUS evaluates to the low order 8 bits returned by the child through _exit(),
exit() or return from main
WIFSIGNALED (int status) 🡪evaluates to a nonzero value if child terminated because of
an uncaught signal
WTERMSIG (int status) 🡪 if WIFSIGNALED evaluates to non zero value, then
WTERMSIG evaluates to the no. of signal
WIFSTOPPED (int status) 🡪 evaluates to a nonzero value if a child is currently stopped.
WSTOPSIG (int status) 🡪 if WIFSTOPPED evaluates to a nonzero value, then
WSTOPSIG evaluates to the number of the signal that caused the child process to
stop.
#include <stdlib.h>
int atexit(void (*func)(void));
The sysconf function takes a single argument, which is the name of a configurable
system wide limit such as the no. of clock ticks per second (_SC_CLK_TCK) or
maximum no. of processes allowed per user (_SC_CHILD_MAX) and returns the
required system values
#include <unistd.h>
long sysconf(int name); //{_SC_CLK_TCK 🡪 defined in limits.h
#include <sys/times.h>
clock_t times(struct tms *buffer)
returns wall clock time in clock ticks (from some arbitrary time in the past
and returns -1 on error. So to calculate the elapsed time b/w two points in the program
call times twice at the required points/places in the program and calculate the
difference b/e the returned values (and divided by SC_CLK_TCK to get the time in
seconds)
members of struct tms
clock_t tms_utime; /* user cpu time of processes */
clock_t tms_stime; /* system cpu time on behalf of process */
clock_t tms_cutime /* user CPU time of process and terminated childrens */
clock_t tms_cstime; /* system CPU time of process and terminated children */
--------------------Program- 2.10-----------showtimes---------------------------------------
// a program with an exit handler that outputs CPU usage
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/times.h>
int main(void) {
if (atexit(showtimes)) {
fprintf(stderr, "Failed to install showtimes exit handler\n");
return 1;
}
/* rest of main program goes here */
return 0;
}
#include <unistd.h>
pid_t getpid(void)
pid_t getppid(void)
The getpid and getppid function returns the process ID and the parent process ID
respectively. The pid_t is an unsigned integer type that represents a process ID.
🡪 neither the getpid nor the getppid function can return an error.
-----------------EX 3.1---------------outputPID----------------------------------------------
#include <stdio.h>
#include <unistd.h>
------------------EX 3.2-----------outputIDS--------------------------------------------------
#include <stdio.h>
#include <unistd.h>
int main(void) {
printf("My real user ID is %5ld\n", (long)getuid());
printf("My effective user ID is %5ld\n", (long)geteuid());
printf("My real group ID is %5ld\n", (long)getgid());
printf("My effective group ID is %5ld\n", (long)getegid());
return 0;
}
fork()
#include <unistd.h>
pid_t fork(void)
A process can create a new process by calling fork. The calling process becomes the
parent and the created process is called the child. The fork function copies the parent’s
memory image so that the new process receives a copy of the address space of the parent.
Both processes continue at the instruction after the fork statement (executing in their
respective memory image).
The fork() function returns 0 to the child and returns the child’s process ID to the parent.
When fork fails, it returns -1 and sets the errorno. If the system does not have the
necessary resources to create the child or if limits on the no. of processes would be
exceeded – fork sets errorno. to EAGAIN. In case of failure the fork does not create a
child.
------------------EX 3.6------------------------twoprocs.c-----------------------------------------
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void) {
pid_t childpid;
childpid = fork();
if (childpid == -1) {
perror("Failed to fork");
return 1;
}
if (childpid == 0) /* child code */
printf("I am child %ld\n", (long)getpid());
else /* parent code */
printf("I am parent %ld\n", (long)getpid());
return 0;
}
------------------------program 3.1---------------simplechain--------------------------------
// a program that creates a chain of n processes, where n is a command line arguments
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
🡪 The parent can execute wait or waitpid (wait for a particular child) to block itself until
the child finishes.
🡪 The wait function causes the caller to suspend execution until a child’s status become
available (ie child terminates) or until the caller receives a signal.
🡪 if wait or waitpid returns because the status of a child is reported, these function return
the process ID of that child. If an error occurs, these function return -1 and set error no.. if
called with WNOHANG option , waitpid returns 0 to report that the specified child is not
available immediately and so parent will not wait/block.
🡪 some errors are like 🡪 EINTER (function was interrupted by a signal), EINVAL (
option parameter of waitpid was invalid)
--------EX 3.15-----------------------fanwait--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include "restart.h"
exec
The exec family of function provides a facility for overlaying the process image of the
calling process with a new image.
#include <unistd.h>
extern char ** environ;
int execl (const char *path, const char * arg 0, /* ………char * (0) */);
int execle (const char *path, const char *arg 0, /* …………char * (0) , char *const
envp{} */ );
int execlp (const char *file, const char *arg 0, /*………. Char * (0) */);
int execv (const char *path, char *const argv[]);
int execve (const char *path, char *const argv[], char *const envp[]);
int execvp (const char *file, char *const argv[]);
All exec function returns -1 and set errorno. if unsuccessful. In fact if any of these
function return at all, the call was unsuccessful and some errorno. will be set (like
E2BIG, EACCES, EINVAL etc)
🡪 setsid() 🡪 if setsid is set for a process than it does not get any signal because of ctrl c
from the controlling terminal.
-----------------Program 3.4--------------execls.c--------------------------------------------------
// aprogram that creates a child process to run ls -l
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
pid_t childpid;
childpid = fork();
if (childpid == -1) {
perror("Failed to fork");
return 1;
}
if (childpid == 0) { /* child code */
if(execl("/bin/ls", "ls", "-l", NULL) == -1)
perror("Child failed to exec ls");
return 1;
}
if (childpid != wait(NULL)) { /* parent code */
perror("Parent failed to wait due to signal or error");
return 1;
}
return 0;
}
------------Program 3.7---------------runback.c------------------------------------------------------
// the runback program creates a child process to execute a command string in the
background
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include "restart.h"
if (argc != 2) {
fprintf(stderr, "Usage: %s string\n", argv[0]);
return 1;
}
childpid = fork();
if (childpid == -1) {
perror("Failed to fork");
return 1;
}
if (childpid == 0) { /* child becomes a background process */
if (setsid() == -1)
perror("Child failed to become a session leader");
else if (makeargv(argv[1], delim, &myargv) == -1)
fprintf(stderr, "Child failed to construct argument array\n");
else {
execvp(myargv[0], &myargv[0]);
perror("Child failed to exec command");
}
return 1; /* child should never return */
}
return 0; /* parent exits */
}
…………………………………………………………………………………….
#include <errno.h>
#include <stdlib.h>
#include <string.h>
Unbuffered I/O -> Unbuffered refers to the fact that each read or write invokes a system
call in the kernel.
# include <unistd.h>
Maximum no. of open files at a time =64(but differs with various unix versions )
Mode – later
The argument mode specifies the permissions to use in case a new file is created. It is
modified by the process’s umask in the usual way: the permissions of the created file are
(mode & ~umask). Note that this mode only applies to future accesses of the newly
created file; the open() call that creates a read-only file may well return a read/write file
descriptor.
The following symbolic constants are provided for mode:
S_IRWXU
00700 user (file owner) has read, write and execute permission
S_IRUSR
00400 user has read permission
S_IWUSR
00200 user has write permission
S_IXUSR
00100 user has execute permission
S_IRWXG
00070 group has read, write and execute permission
S_IRGRP
00040 group has read permission
S_IWGRP
00020 group has write permission
S_IXGRP
00010 group has execute permission
S_IRWXO
00007 others have read, write and execute permission
S_IROTH
00004 others have read permission
S_IWOTH
00002 others have write permission
S_IXOTH
00001 others have execute permission
mode must be specified when O_CREAT is in the flags, and is ignored otherwise.
creat() is equivalent to open() with flags equal to
O_CREAT|O_WRONLY|O_TRUNC.
Create
Close
int close(int filedes); //filedes: file description
Returns: 0 if ok, -1 on error
Note: when a process terminate, the kernel automatically closes all open files.
lseek
off_t lseek (int filedes, off_t offset, int whence);
returns : new file offset if ok,-1 on error
Note 1: lseek only records the current file offset with in the kernel. It does not cause any
I/O to take place. This offset is then used by the next read or writes option.
Note 2 : The file’s offset can be greater then the file’s current size , in which case the next
write to the file will extend the file. This is referred to as creating a hole in a file and is
allowed. Any bytes in a file that have not been written are read back as 0.
read
ssize_t read (int fledes , void *buff , size_t nbytes)
returns : number of byte read , 0 if end of file, -1 on error.
Note : 1: there can be cases in which the no of bytes actually read is less than the amount
requested.
Note : 2: The read operation starts at the file’s current offset. Before a successful return,
the offset is incremented by the no of bytes actually read.
Write
ssize write (int filedes, const void *buff, size_t nbytes);
returns:no of bytes written if ok, -1 on error.
FILE Sharing
Unix supports the sharing of open files between different processes.
Note :->If we open a file with O_APPEND flag, then before each write the kernel
position the file offset to current end of file.
The new file description returned by dup is guaranteed to be the lowest numbered
available file description. With dup2,we specify the value of new description with the
filedes 2 arguments. If filedes2 is already open, it is first closed. If filedes equals filedes2
then dup2 returns without closing it.
#include <unistd.h>
int dup2 (int fildes, int fildes2)
The dup2 function takes two parameters fildes and fildes2. It closes entry fildes2 of the
file descriptor table, if it was open and then copies the pointer of entry fildes into entry
fildes2
fcntl function
The fcntl function can change the properties of a file that is already open.
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
int fcntl (int filedes, int cmd,………../*int arg*/);
cmd :
F_DUPFD
Duplicate the file description fields. The new file description is
returned as the value of the function (similar to the dup).
F_GETFT
Return the file status flags for filedes as the value of the function.
O_APPEND Append on each file
O_APPEND Append on each write
O_NONBLOCK No blocking mode
O_SYNC Wait for writes to complete
O_ASYNC Asynchronous I/O
1) They are not separate bits that can be tested, they are rather 0,1 & 2. Moreover
O_RDONLY,O_WRONLY and O_RDWR are mutually exclusive – that is for a
file only one of the three can be enabled so use O_ACCMODE mask.
Accmode = Val & O_ACCMODE; {Val is the value returned by the fcntl}
If (Accmode==O_RDONLY)->printf(“read only”);
If (val &O_APPEND)->printf(“append”);
F_SETFL
Set the file status flags to the value of third argument .the only flags that
can be changed are O_APPEND,O_NONBLOCK,O_SYNC and O_ASYNC.
F_GETOWN
Get the process id or process group id.
F_SETOWN
Set the process id or process group id.
F_GETFD
F_SETFD
/dev/fd -> some system provides a directory named /dev/fd where entries are files
names 0,1,2 and so on. Opening the file /dev/fd/n is equivalent to duplicating
description n.
----------------program 4.9------------------------copyfilemain.c---------------------------------
//a program to copy a file
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include "restart.h"
#include <unistd.h>
int dup2 (int fildes, int fildes2)
The dup2 function takes two parameters fildes and fildes2. It closes entry fildes2 of the
file descriptor table, if it was open and then copies the pointer of entry fildes into entry
fildes2
---------------program 4.18--------------------redirect.c---------------------------------------------
//a program that redirects standard output to the file my.file
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include "restart.h"
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main(void) {
int fd;
#include <unistd.h>
int chdir (const char *path)
🡪 The chdir function causes the directory specified by path to become the current
working dir for the calling process.
🡪 If successful , chdir returns 0, if unsuccessful chdir returns -1 and sets errno.
#include <unistd.h>
char *getcwd (char *buf, size_t size)
The getcwd function returns the pathname of the current working directory. The buf
parameter of getcwd represents a user supplied buffer for holding the pathname of
the current working directory. The size parameter specifies the maximum length
pathname that buf can accommodate, including the trailing string terminator.
If successful, getcwd returns a pointer to buf. If unsuccessful, getcwd returns NULL and
sets errorno.
🡪 errorno.
EINVAL 🡪 size is 0
ERANGE 🡪 size is greater than 0, but smaller than the pathname + 1
----------Program 5.1-------------------------getcwdpathmax.c------------------------------------
// a complete program to output the current working directory
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#ifndef PATH_MAX
#define PATH_MAX 255
#endif
int main(void) {
char mycwd[PATH_MAX];
# include<sys/types.h>
# include <sys/stat.h>
int stat (const char *pathname, struct stat *buf);
int fstat (int filedes, struct stat *buf);
int lstat (const char *pathname, struct stat *buf);
All three return : 0 if ok, -1 on error
🡺 buf –will contain the file related information when those function returns.
🡺 fstat – obtain information about the file that is already open on the description
filedes.
🡺 lstat – function is similar to stat, but when the named file is a symbolic link, lstat
returns information about the symbolic link, and not the file referenced by the
symbolic link.
🡺 Character special file S_ISCHR( )->A type of file used for certain type of
device an a system.(like keyboard)
🡺 Block special file S_ISBLK ()-> A type of file typically used for disk devices
devices.
All devices on a system are either character special file or
block special file.
🡺 FIFO S_ISFIFO ()->A type of file is used for inter
process communication between process. It is sometime
called named pipe.
🡺 st_uid and st_gid both have a bit called set-user-ID & set-group-ID.
🡺 These two bits can be tested against the constants S_ISUID and S_ISGID.
To set -> st_uid & S_ISUID
To see effective user ID of a process xyz use geteuid()
File access Permission
Read on dir -> no read then you can’t do ls on the dir but still you can display a file
in directory using cat.
Execute on dir ->user can change to that dir i.e. cd allowed.
->Also find or search on that dir is allowed.
->Open (“XYZ/ABC/EFG/ravi.c”,………..)// We need to have execute
permission on XYZ,ABC,EFG
write on dir ->allows the user to remove/create files in that dir. For removing you
need to be owner of the file removed.
The process\program creating a file say XYZ using creat or open(). System call will
have the user id &group id as the effective user id and effective group id of the
process.
chmod(“XYZ”,S_TRUSR|S_IWUSR|S_IRGRP|S_IROTH)
🡺 Only super user can set the sticky bit. When a process with a sticky bit terminates,
a copy of its text is kept in the swap space.
# chmod +t/bin/XYZ
# ls –l /bin/XYZ
-rwx- -x- -t
Umask function
Chown,Fchown,lchown functions.
file truncation :
# include <sys/types.h>
# include <unistd.h>
# truncate (const char* pathname , off _t length);
# ftruncate (int filedes , off _t length);
both returns o if on ,-1 on error
🡺 These two function truncate an existing file to length bytes
🡺 If the previous size of the file was greater than length ,the data beyond length is
no longer accessible. if the previous size was less than length, the effect is system
dependent, if the implementation does extend a file , data b/w the old end of file
and the new end of file will read as 0 (i.e. a hole is probably created in the file).
File System
Partition Partition Partition
File System
Boot block super block i - list Directory blocks & data
blocks
i-node file
no. name(xyz)
⮚ xyz .........
⮚ ls –l CSE
⮚ xyz.........
so reference count/link count
for file xyz will be 2
i-node
Permission
Owner
Group
Size in block
Single indirect
Double indirect
Triple indirect
🡺 Renaming a file -> Add new name in the directory & make it point to the file’s i-
node.
->Remove old file name from the directory entry.
🡺 Unix command :
ln –s lunch /home/CSE/final_year
⮚ ls –l
# include <unistd.h>
int link (const char* existing path , const char *new path);
returns : 0 if ok , -1 if error
🡺 The system call will create a new directory entry & will increment the link count in
the file’s i-node.
🡺 only a super user process can create a new link that points to a directory as such
directory links can form loops in the file systems.
# include <unistd.h>
int unlink(const char * pathname)
# include<stdio.h>
int remove(const char *pathname);
return: 0 if ok, -1 on error
🡺 For file remove is identical to unlink & for a directory remove is identical to rmdir.
# include<stdio.h>
int rename(const char *old name, const char *new name);
return: 0 if ok, -1 on error
🡺 Otherwise new name is removed and old name is renamed to new name.
🡺 we should have write permission on the directory containing new name and old name.
In case of directory
🡺 If new name is the name of existing directory then the new name directory should be
empty.
🡺 Remove the new name (empty dir) & renamed the old name to new name.
🡺 when we’re renaming a directory new name can not contain a path prefix that names
oldname. For example we can’t rename /user/foo to user/foo/feskir. Since the old
name is a path prefix of the new name & can not be removed.
Function that does not follow the symbolic link & (thus act on the name of the
symbolic link itself).
🡺 chown, lchown , lstat, readlink, remove, rename, unlink.
Function that follow the symbolic link.
🡺 access, chdir, chmod, creat, exec, link, mkdir, opendir, pathconf, mkfifo, mknod,
stat, truncate.
$ mkdir foo
$ touch foo/a -> Create a 0-length file.
// soft link
$ ln –s ../foo foo/test dir
$ unlink (“foo/test dir”) // Easy to remove, as unlink will not follow the symbolic
links.
🡺 you can create a symbolic link to a file that does not exist.
$ ln –s /no/such/file myfile
$ ls myfile
myfile
$ cat myfile
no such file // as the cat follow the symbolic link & the linked file /no/such/file
doesn’t exist.
$ ls –l myfile
lrwxrwxrwx-------------------------------------my file -> no/such/file
# include<unistd.h>
int symlink (const char * actualpath, const char *path);
return : 0 if ok , -1 on error
🡺 A new directory entry, sympath is created that point to actual path. It is not required
that the actual path exists. when the symbolic link is created. Also actual path and
sympath need not reside in the same file system.
# include <unistd.h>
🡺 Since the open function follows a symbolic link, we need a way to open the link
itself & read the name in the link. If the function is successful it return the no of
bytes placed into buffer. The contents of the symbolic link that are returned in
buf are not null terminated.
File times
Three time fields are maintained for each file.
Field
st_atime -> last access time of file data -> ex –>read {ls -u}
st_mtime ->last modification of file data -> ex -> write {ls –l (default)}
st_ctime -> last change time of i-node status -> ex -> chmod, chown {ls
–c}.
NOTE:- The system does not maintain the last access time for an i-node. This is why the
function access and stat, for example, don’t change any of the three times.
utime function
The access time & the modification time of a file can be changed with the utime
function.
#include<sys/types.h>
#include<utime.h>
int utime(const char *pathname, const struct utimebuf *times);
returns : 0 if ok, -1 on error
the structure used by this function is
struct utimebuf {
time_t actime; /* Access time */
time_t modtime; /* Modification time */
}
if times=null - file access & modification time are set to the current time of the system.
if times != null – the access & modification time are set to the value in the structure
pointed to by times.
#include<sys/types.h>
#include<sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
returns : 0 if ok, -1 on error
🡺 This function creates a new, empty directory. the entries for dot and dot_dot are
automatically created. the specified file access permission, mode are modified by the
file mode creation mask of the process.
🡺 An empty directory is deleted with the rmdir function.
#include<unistd.h>
int rmdir(const char *pathname);
returns : 0 if ok, -1 on error
if the link count of the directory becomes 0 with this call, and no other process has the
directory open, then the space occupied by the directory is used. if one or more
processes have the directory open when the link count reaches 0, the last link is
removed & the dot_dot entries are removed before this function returns. Additionally,
no new files can be created in the directory. the directory is not free, however, until
the last process closes it.
reading directories
directories can be read by anyone who has access permission to read the directory.
but only the kernel can write to a directory (to preserve file system security). recall
from section 4.5 that the write permission bits and execute permission bits for a
directory determine if we can create new files in the directory and remove files from
the directory they don’t specify if we can write to the directory itself.
#include<sys/types.h>
#include<dirent.h>
DIR *opendir (const char *pathname);
return pointer if ok, NULL on error
struct dirent * readdir (DIR *dp);
return pointer if ok, NULL at end of directory on error
🡺 struct dirent {
ino_t d_ino; /* i_node number */
char d_name [NAME_MAX *1] /* null terminated filename*/
}
🡺 the pointer to DIR structure that is returned by opendir is the used with other
three functions. opendir initializes things so that the first readdir reads the first
entry in the directory. the ordering of entries within the directory is
implementation dependent. it is usually not alphabetical.
#include<unistd.h>
int chdir(const char *pathname);
int fchdir(int filedes);
we can specify the new current working directory as either a pathname and through
an open file description.
$ pwd
/ usr/lib
$ mycd /* a program which changes current directory to /tmp */
chdir to /tmp suceeded
$ pwd
/usr/lib
the buf must be large enough to accommodate the absolute pathname plus a
terminating null bytes.
🡺 Every file system is known by it’s major and minor device number. the device
number is encoded in the primitive system datatype dev_t. recall that a disk drive
often contains several file system.
🡺 We can usually access the major and minor device number through two macro
defined by most implementation : major and minor (include <sys/types.h>). this
means we don’t care how the two number are stored in a dev_t object.
🡺 the st_dev value for every file name on a system is the device number of the file
system containing that file name and it’s corresponding i_node.
🡺 Only character special file and block special file have an st_rdev value. this value
contain the device number for the actual device.
#include<unistd.h>
void sync (void );
int fsync (int filedes);
return 0 if ok, -1 on error
Unix implementation have a buffer cache in the kernel through which most disk I/O
passes. when we write data to a file that data is normally copied by the kernel into one of
it’s buffer and queued for I/O at some later time. this is called delayed write.
sync just a queues all the modified block buffer for writing and return; it doesn’t wait for
actual I/O to take place.
🡺 The function sync is normally called every 30 seconds from a system daemon (often
called update). this is guarantees regular flushing of the kernel block buffer.
🡺 The function fsync refers to a single file and wait for the I/O to complete before
returning.
#include<sys/types.h>
#include<pwd.h>
struct passwd *getpwuid (uid_t uid);
struct passwd *getpwnam (const char *name);
#include<sys/types.h>
#include<pwd.h>
struct passwd *getpwent (void); /* read the next record, open file if not
already
open */
return pointer if ok, NULL on error or end of file.
void setpwent (void); /* open the file and goto the start (first record) of the
file */
void endpwent(void); /* close the file */
Shadow passwd
🡺 for login, passwd command the set_user_id root is set, so this command can read the
/etc/shadow as the they have root access when they are executing now /etc/passwd
can be left readable to the world.
Group file
/etc/group
<grp.h>
Description single group member
group name char *gr_name
encrypted password char *gr_passwd
numerical group ID int gr_gid
array of pointer to char **gr_mem
individual user name
The field gr_mem is an array of pointer to the usernames that belongs to this group.
the array is terminated by a NULL pointer.
#include<sys/types.h>
#include<grp.h>
struct group *getgrgid(gid_t gid);
struct group *getgrnam (const char *name);
both returns pointers if ok , NULL on error
#include<sys/types.h>
#include<grp.h>
struct group *getgrent (void); /* read the next record, open file if not already
open*/
void setgrent (void); /* open the file and goes to the start (first record) of the
file */
void endgrent (void); /* close the file */
Other data file - Similar commands are also available for other data files like
/etc/hosts, /etc/network, /etc/services (service provided by various network server).
/etc/protocols .etc
-------------------------Program 5.3--------------shownames.c--------------------------------------
// a program to list files in a directory
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
if (argc != 2) {
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
----------------Ex 5.10----------------------------isdirectory.c--------------------------------------
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
int link(const char *path1, const char *path2);
🡪The link function creates a new directory entry for the existing file specified by path1
in the directory specified by path2.
🡪 If successful the link function returns 0. if unsuccessful link returns -1 and sets errno.
#include <unistd.h>
int symlink(const char *path1, const char *path2);
🡪 The path1 parameter of symlink contains the string that will be the contents of the link
and path2 gives the pathname of the link. That is path2 is the newly created link
and path1 is what the new link points to.
🡪 If successful, symlink returns 0. if unsuccessful, synlink returns -1 and sets errorno.
pipes
The capacity to communicate is essential for process that cooperates to solve a problem.
The simplest UNIX inter-process communication mechanism is the pipe, which is
represented by a special file. The pipe function creates a communication buffer
that the caller can access through the file descriptor fildes[0] and fildes[1]. The
data written to fildes[1] can be read from fildes[0] on a first-in-first-out basis.
#include <unistd.h>
int pipe (int fildes[2]);
🡪 if successful pipe returns 0. if unsuccessful pipe returns -1 and sets errorno. (EMFILE,
ENFILE)
🡪 A pipe has no external or permanent name, so a program can access it only through its
two descriptor. For this reason, a pipe can be used only by the process that created
it and by descendents that inherit the descriptors on fork. The pipe function
described here creates a traditional unidirectional communication buffer.
🡪When a process calls read on a pipe, the read returns immediately, if the pipe is not
empty. The read blocks until something is written to the pipe as long as some
process has the pipe open for writing. On the other hand if no process has the pipe
open for writing, a read from an empty pipe returns o, indicating an end-of-file
condition.
🡪A single process with a pipe is not very useful. Usually a parent process uses pipe to
communicate with its children.
--------------Program 6.3------------------simpleredirect.c-------------------------------------
// a program to execute the equivalent of ls –l | sort –n +4
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void) {
pid_t childpid;
int fd[2];
Pipes are temporary in the sense that they disappear when no process has them open.
POSIX represents FIFOs or named pipes by special files that persist even after all
processes have closed them. A FIFO has a name and permission just like an
ordinary file and appears in the directory listing given by ls. Any process with
appropriate permissions can access a FIFO. We can create a FIFO by executing
the mkfifo command from a shell or by calling mkfifo function from program.
🡪 The mkfifo function creates a new FIFO special file corresponding to the pathname
specified by path. The mode argument specifies the permission for the newly
created FIFO.
#include <sys/stat.h>
int mkfifo(const char *path, mode_t mode);
-----------------------Program 6.7-----------------pipeserver.c--------------------------------------
//the program reads what is written to a named pipe and writes it to standard output
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "restart.h"
#define FIFOARG 1
#define FIFO_PERMS (S_IRWXU | S_IWGRP| S_IWOTH)
--------------Program 6.8-----------------pipeclient.c------------------------------------------------
//the client writes an informative message to a named pipe
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include "restart.h"
#define FIFOARG 1
curtime = time(NULL);
snprintf(requestbuf, PIPE_BUF, "%d: %s", (int)getpid(), ctime(&curtime));
len = strlen(requestbuf);
if (r_write(requestfd, requestbuf, len) != len) {
perror("Client failed to write");
return 1;
}
r_close(requestfd);
return 0;
}
-----------------------------------------------------------------------------------------------------------
#include <unistd.h>
pid_t getpid(void)
pid_t getppid(void)
The getpid and getppid function returns the process ID and the parent process ID
respectively. The pid_t is an unsigned integer type that represents a process ID.
🡪 neither the getpid nor the getppid function can return an error.
fork()
#include <unistd.h>
pid_t fork(void)
A process can create a new process by calling fork. The calling process becomes the
parent and the created process is called the child. The fork function copies the parent’s
memory image so that the new process receives a copy of the address space of the parent.
Both processes continue at the instruction after the fork statement (executing in their
respective memory image).
The fork() function returns 0 to the child and returns the child’s process ID to the parent.
When fork fails, it returns -1 and sets the errorno. If the system does not have the
necessary resources to create the child or if limits on the no. of processes would be
exceeded – fork sets errorno. to EAGAIN. In case of failure the fork does not create a
child.
#include <sys/wait.h>
pid_t wait(int *state_loc);
pid_t waitpid(pid_t pid, int *state_loc, int options);
🡪 The parent can execute wait or waitpid (wait for a particular child) to block itself until
the child finishes.
🡪 The wait function causes the caller to suspend execution until a child’s status become
available (ie child terminates) or until the caller receives a signal.
🡪 if wait or waitpid returns because the status of a child is reported, these function return
the process ID of that child. If an error occurs, these function return -1 and set error no.. if
called with WNOHANG option , waitpid returns 0 to report that the specified child is not
available immediately and so parent will not wait/block.
🡪 some errors are like 🡪 EINTER (function was interrupted by a signal), EINVAL (
option parameter of waitpid was invalid)
exec
The exec family of function provides a facility for overlaying the process image of the
calling process with a new image.
#include <unistd.h>
extern char ** environ;
int execl (const char *path, const char * arg 0, /* ………char * (0) */);
int execle (const char *path, const char *arg 0, /* …………char * (0) , char *const
envp{} */ );
int execlp (const char *file, const char *arg 0, /*………. Char * (0) */);
int execv (const char *path, char *const argv[]);
int execve (const char *path, char *const argv[], char *const envp[]);
int execvp (const char *file, char *const argv[]);
All exec function returns -1 and set errorno. if unsuccessful. In fact if any of these
function return at all, the call was unsuccessful and some errorno. will be set (like
E2BIG, EACCES, EINVAL etc)
🡪 setsid() 🡪 if setsid is set for a process than it does not get any signal because of ctrl c
from the controlling terminal.