You are on page 1of 37

Title of Assignment:

Shell programming and AWK programming with suitable application (student database)
and use of advanced filters and report generation.

Relevant Theory / Literature Survey: (Brief Theory Expected)


About Shell:
The shell is a command interpreter that provides a line-oriented interactive and
noninteractive interface between the user and the operating system. You enter
commands on a command line; they are interpreted by the shell and then sent as
instructions to the operating system.

The Shell makes available three files.


1)Standard input 2)Standard Output 3)Standard Error

It can manipulate the default source and destination of input and output streams by
assigning them to disk files.

How it Works:
(1)Parsing : The shell first breaks up the command line into words using spaces and
tabs as delimiters, unless quoted. All consecutive occurrence of a space or tabs is
replaced with single space.
(2)Variable Evaluation : All $-prefixed strings are evaluated as variables, unless
quoted or escaped.
(3)Command Substitution : Any command surrounded by back quotes is executed by
the shell, which then replaces standard output of the command into command line.
(4)Redirection : The shell then looks for the characters >, < and >> to open the files
they point to.
(5)Wild-card interpretation : The shell finally scans the command line for wild-cards
(*, ?, [ and ] ). Any word containing a wild-card is replaced by a sorted list of file
names that match the pattern. The list of these filenames then forms arguments to
the command.
(6)PATH evaluation : It finally looks for the PATH variable to determine the
sequence of directories it has to search in order to hunt for the command.

Linux Shell : Shell accepts user instruction or commands and if its a valid command it is
passed to kernel. Shell provides an environment for user interaction. Shell is a command
language interpreter that executes commands read from the standard input device or from
a file. Shell is not part of system kernel but uses the system kernel to execute programs.
Several shells available with Linux are as below.
BASH ( Bourne-Again SHell ) : Most commonly used shell in Linux. It is Freeware
shell. It was developed by Brian Fox and Chet Ramey at Free Software Foundation.

CSH (CShell) : The C shell's syntax and usage are very similar to the C programming
language. It was developed by Bill Joy at University of California (For BSD).

KSH (Korn Shell) : It was developed by David Korn AT & T Bell Labs.

TCSH : TCSH is an enhanced but completely compatible version of the Berkeley UNIX
C shell.

To find all available shells in the system use the following command
$ cat /etc/shells
To find the current shell use the following command
$ echo $SHELL

Shell Script : Shell Script is series of command written in plain text file. Shell script is
just like batch file is MS-DOS.

Steps required to write shell script:


1. Use any editor like vi or mcedit to write shell script.
2. After writing shell script set execute permission for user written script by using
chmod command.
Ex: chmod permission script-name
Comments : Comments in shell programming start with # and go until the end of the
line.
Variables in Shell : In shell programming all variables have the data type string and no
need to declare them. There are two types of variable.

1. System variables : Created and maintained by Linux itself. These variables are
defined in capital letters.
2. User defined variables (UDV) : Created and maintained by user. This type of variable
is defined in lower letters.

In shell program there are also environment variables which are preceded by the keyword
export.

Shell commands and control structures:There are three categories of commands which
can be used in shell scripts:
1) Unix commands:
Shell script can make use of any unix commands. Some of the commands which are
more often used than others are as below.

Command syntax Purpose


echo "some text" write some text on your screen
Ls list files
wc -l file count lines in file or
wc -w file count words in file or
wc -c file count number of characters
cp sourcefile destfile copy sourcefile to destfile
search for strings in a file
grep 'pattern' file
Example: grep 'searchstring' file.txt
Most of the time awk is used to extract fields from a text
line. The default field separator is space. To specify a
Awk different one use the option -F.
cat file.txt | awk -F, '{print $1 "," $3 }'

2) Pipes and redirection


Pipes (|): send the output of one program to the input of another program.
Ex.: grep "hello" file.txt | wc -l
It is used to find the lines with the string hello in file.txt and then counts the lines. The
output of the grep command is used as input for the wc command.

Redirection: writes the output of a command to a file or appends data to a file


> writes output to a file and overwrites the old file in case it exists
>> appends data to a file or creates a new one if it doesn't exist already but it never
overwrites anything.

3) Control structures
"if" statement : It tests the condition and if the condition is true "then" part gets
executed otherwise else part is executed.

if ....; then
....
elif ....; then
....
else
....
fi

case statement : It can be used to match a given string against a number of possibilities.
case ... in
...) do something here;;
esac

Loop statements :The while-loop will run while the expression given if it is true. The
keyword "break" can be used to leave the loop at any point in time. With the keyword
"continue" the loop continues with the next iteration and skips the rest of the loop body.
while ...; do
....
done
The for-loop takes a list of strings (strings separated by space) and assigns them to a
variable.
for var in ....; do
....
done

AWK: awk is a programming language designed to search for, match patterns, and
perform actions on files.Programs in awk are different from programs in most other
languages, because awk programs are data-driven.

STRUCTURE OF AN AWK PROGRAM :

awk scans input lines one after the other, searching each line to see if it matches a set of
patterns or conditions specified in the awk program. For each pattern, an action is
specified. The action is performed when the pattern matches that of the input line. Thus,
an awk program consists of a number of patterns and associated actions. Actions are
enclosed using curly braces and separated using semi-colons.

pattern { action }
pattern { action }

When awk scans an input line, it breaks it down into a number of fields. Fields are
separated by a space or tab character. Fields are numbered beginning at one, and the
dollar symbol ($) is used to represent a field. Field zero ($0) refers to the entire line. awk
scans lines from a file(s) or standard input.

printf: Built in function of awk called printf operates the same way as in the C
programming language. It is terminated by a semi-colon. Brackets are used to enclose the
argument, and the text is enclosed using double quotes.

awk Control Flow Statements :

if ( expr) statement [ else statement]


if ( subscript in array) statement [ else statement]
while ( expr) statement
for ( expr ; expr ; expr ) statement
for ( var in array ) statement
do statement while ( expr)
# Shell Program for Listing Files in Current Dir
# Whose size >= 4096 Bytes
echo "SIZE FILE NAME"
SizeLimit=4
count=0
for f in * # for all files in current Directory
do
if test -f $f # Check file Types and compare values
then
fsize=`ls -s $f |awk '{print $1} '`
if test $fsize -ge $SizeLimit
then
csize=`expr $fsize \* 1024`
echo $csize - $f
count=$[count+1]
fi
fi
done
echo "Total Number of Files:: $count"

root@localhost Unix_Pro]# ./file_size.sh


SIZE FILE NAME
4096 - abc.awk
16384 - a.out
4096 - child_process.c
4096 - db.awk
4096 - db.txt
4096 - File_Manage.c
4096 - file_size.sh
4096 - fork1.c
16384 - install.log
4096 - out.txt
4096 - temp.txt
4096 - thread_a.c
4096 - t_join.c
4096 - z.txt
Total Number of Files:: 14

Conclusion:
Studied the various shell programming and AWK commands and their use for generation
of required output.
Title of Assignment:

Using fork system call, create child process, suspend it using wait system call
and transfer it into zombie state.

Relevant Theory / Literature Survey: (Brief Theory Expected)

Process: Process is an active entity that executes a given piece of code. It has its own
execution stack, own set of memory pages, own file descriptors table and a unique
process ID. Several processes may be executing the same or different program at the
same time for the same user or for several different users.

Data Structures for Process :

Every process has an entry in the kernel process table, and each process alocated a user
area that contains private data manipulated only by the kernel. The process table contains
(or points to) per process region table, whose entries point to entries in the region table.A
region table is a contiguous area of process address's space, such as text, data and stack.

Process States and Transitions :


Fork() : This system call is used to create processes. It takes no arguments and returns a
process ID. The purpose of fork() is to create a new process, which becomes the child
process of the caller. After a new child process is created, both processes will execute the
next instruction following the fork() system call. Every process has an entry in the The
identification of the parent from the child can be done by testing the returned value of
fork().

• If fork() returns a negative value, the creation of a child process is unsuccessful.


• fork() returns a zero to the newly created child process.
• fork() returns a positive value, the process ID of the child process, to the parent.
The process ID is an integer. A process can use function getpid() to retrieve the
process ID assigned to this process.

Unix will make an exact copy of the parent’s address space and give it to the child. So the
parent and child processes have separate address spaces. Since both processes have
identical but separate address spaces, those variables initialized before fork() call have
the same values in both address spaces. Since every process has its own address space,
any modifications will be independent of the others. In other words, if the parent changes
the value of its variable, the modification will only affect the variable in the parent
process's address space. Other address spaces created by fork() calls will not be affected
even though they have identical variable names. When the main program executes fork(),
an identical copy of its address space, including the program and all data, is created.
System call fork() returns the child process ID to the parent and returns 0 to the child
process.

Zombie state of process : Once a child process is created , there are two possibilities.
Either the parent process exits before the child, or the child exits before the parent.
When a child process exits, it is not immediately cleared off from the process table.
Instead, a signal is sent to its parent process, which needs to acknowledge it's
child's death, and only then the child process is completely removed from the
system. In the duration before the parent's acknowledgment and after the child's
exit, the child process is in a state called "zombie". When the parent process is not
properly coded, the child remains in the zombie state forever. Such processes can
be noticed by running the 'ps' command (shows the process list) and seeing
processes having string "<defunct>" as their command name.

wait() :This system call blocks the calling process until one of its child processes exits or
a signal is received. wait() takes the address of an integer variable and returns the
process ID of the completed process. Some flags that indicate the completion status
of the child process are passed back with the integer pointer. One of the main
purposes of wait() is to wait for completion of child processes.

The simple way of a process to acknowledge the death of a child process is by using the
wait() system call. When wait() is called, the process is suspended until one of its child
processes exits, and then the call return with the exit status of the child process. If it has a
zombie child process, the call returns immediately, with the exit status of that process.

The execution of wait() could have two possible situations.

1. If there are at least one child processes running when the call to wait() is made,
the caller will be blocked until one of its child processes exits. At that moment,
the caller resumes its execution.
2. If there is no child process running when the call to wait() is made, then this
wait() has no effect at all. That is, it is as if no wait() is there.

exit() : This system call is used to terminate the current process.The exit code or return
code is a numeric value returned by a terminating process to its parent process.
Conclusion:

Studied the creation of a child process, identification of child and parent process,
suspension of a process and transferring the process to zombie state.
Addition of six numbers………………………………

#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>

int main()
{
int x[6] = {1,2,3,4,5,6};
int a,b,c;
static int i = 0 ;
pid_t pid;

pid = fork();
if(pid == 0) {
a = x[i] + x[i+1];
i += 2;

pid = fork();
if(pid == 0){
b = x[i] + x[i+1];
i += 2;
pid = fork();
if(pid == 0) {
c = x[i] + x[i+1];
i += 2;
pid = fork();
if(pid == 0) {
a = a + b;
pid = fork();
if(pid == 0){
c = a + c;
printf("\nSUM = %d\n",c);
}
}
}
}
}
if(pid != 0) {
int stat_val;
pid_t child_pid;
child_pid = wait(&stat_val);
}

exit(0);
}
ER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.3 0.0 1372 476 ? S 03:32 0:05 init
root 2 0.0 0.0 0 0 ? SW 03:32 0:00
[migration/0]
root 3 0.0 0.0 0 0 ? SW 03:32 0:00
[migration/1]
root 4 0.0 0.0 0 0 ? SW 03:33 0:00 [keventd]
root 5 0.0 0.0 0 0 ? SWN 03:33 0:00
[ksoftirqd_CPU0]
root 6 0.0 0.0 0 0 ? SWN 03:33 0:00
[ksoftirqd_CPU1]
root 11 0.0 0.0 0 0 ? SW 03:33 0:00 [bdflush]
root 7 0.0 0.0 0 0 ? SW 03:33 0:00 [kswapd]
root 8 0.0 0.0 0 0 ? SW 03:33 0:00
[kscand/DMA]
root 9 0.0 0.0 0 0 ? SW 03:33 0:00
[kscand/Normal]
root 10 0.0 0.0 0 0 ? SW 03:33 0:00
[kscand/HighMem]
root 12 0.0 0.0 0 0 ? SW 03:33 0:00
[kupdated]
root 13 0.0 0.0 0 0 ? SW 03:33 0:00
[mdrecoveryd]
root 17 0.1 0.0 0 0 ? SW 03:33 0:02
[kjournald]
root 75 0.0 0.0 0 0 ? SW 03:33 0:00 [khubd]
root 3874 0.0 0.0 0 0 ? SW 03:33 0:00
[kjournald]
root 4129 0.0 0.1 1444 548 ? S 03:33 0:00 syslogd
-m 0
root 4133 0.0 0.0 1372 432 ? S 03:33 0:00 klogd -x
root 4267 0.0 0.2 3508 1504 ? S 03:33 0:00
/usr/sbin/sshd
root 4281 0.0 0.1 2024 864 ? S 03:33 0:00 xinetd
-stayalive -reuse -pidfile /var/run/xinetd.pid
root 4301 0.0 0.4 5916 2496 ? S 03:33 0:00
[sendmail]
root 4320 0.0 0.0 1412 444 ? S 03:33 0:00 gpm -t
imps2 -m /dev/mouse
root 4329 0.0 0.1 1416 568 ? S 03:33 0:00 crond
root 4340 0.0 0.3 7496 1916 ? S 03:33 0:00 cupsd
root 4408 0.0 0.1 1396 608 ? SN 03:33 0:00 anacron
-s
root 4425 0.0 0.0 1348 396 tty1 S 03:33 0:00
/sbin/mingetty tty1
root 4426 0.0 0.0 1348 396 tty2 S 03:33 0:00
/sbin/mingetty tty2
root 4427 0.0 0.0 1348 396 tty3 S 03:33 0:00
/sbin/mingetty tty3
root 4428 0.0 0.0 1348 396 tty4 S 03:33 0:00
/sbin/mingetty tty4
root 4429 0.0 0.0 1348 396 tty5 S 03:33 0:00
/sbin/mingetty tty5
root 4430 0.0 0.0 1348 396 tty6 S 03:33 0:00
/sbin/mingetty tty6
root 4587 0.0 0.2 4356 1440 pts/0 S 03:34 0:00 bash
root 4613 0.0 0.5 8048 2816 pts/0 S 03:34 0:00 vim
File_Manage.c
root 4616 0.0 0.2 4360 1444 pts/1 S 03:34 0:00 bash
root 4731 0.0 0.2 4368 1460 pts/2 S 03:56 0:00 bash
root 4757 0.0 0.5 8024 2816 pts/2 S 03:57 0:00 vim
child_process.c
root 4767 0.0 0.2 4364 1444 pts/3 S 03:57 0:00 bash
root 4807 0.0 0.0 1340 236 pts/1 S 04:01 0:00 ./a.out
root 4808 0.0 0.0 0 0 pts/1 Z 04:01 0:00 [a.out
<defunct>]
root 4809 0.0 0.1 2656 708 pts/3 R 04:01 0:00 ps ux

Title of Assignment:
File management using low level file access system calls such as write, read, open, lseek and
fstat.

Relevant Theory / Literature Survey: (Brief Theory Expected)

Unix file system is organized as a tree with single root node called root. Every non-leaf
node is of the file system is a directory of files and files at the leaf nodes of the tree are
either directories, regular files, or special device files. The name of the file is given by a
pathname which describes how to locate the file in the system hierarchy. Each file on
unix system has a unique inode. The inode contains the information necessary for a
process to access a file like file ownership, access rights, file size and location of file’s
data in the file system. Processes access the files by a well defined set of system calls
and specify the file by a character string that is the pathname. Unix provides system calls
for creation of file, deletion of file, reading the content of file, writing the information
into the file etc. Some of the system calls for accessing, creating, reading, writing
operations of file are as below.
An Overview of the File Subsystem :
Data Structures For File subsystem
The internal representation of a file is given by inode, which contains a description
of the disk layout of the file data and other information. Every file has one inode, but it
may have several names (link). When a process refers to a file by name, the kernel parses
the file name one component at a time, checks that process has permissions to search the
directories in the path, and eventually retrieves the inode for the file.
When a process creates a new file, the kernel assign it an unused inode. inodes are
stored in the file system, and reads them into an inode table when manipulating files.
The File System Layout is as shown in the Figure

(a) open system call :

The open system call creates an operating system object called an open file. The open file is
logically connected to the file as mentioned in the open system call. An open file has a file
location associated with it. It is the offset in the file where the next read or write will start. After
opening a file, read or write system calls are used to read or write the open file. Each read or
write system call increments a file location for a number of characters read or written. Thus, the
file is read (or/and written) sequentially by default.

Syntax : int open (char * pathname, int openFlags);

The named file is opened and a positive integer, the open file identifier is returned. The file
location is set to 0. The flags can be one of the following:

0 – open for reading

1 – open for writing

2 – open for reading and writing

If an error occurs in trying to open the file, a negative integer is returned.

(b) creat system call :


The named file is created as an empty file and opened for writing and a positive integer, the open
file identifier is returned. The file location is set to 0. The file mode defines file access rights. If
an error occurs in trying to create the file, a negative integer is returned. The open file identifiers
returned by open and creat are local to the process making the calls. Thus, an open file identifier
in one process is not related to an open file identifier in another process.

Syntax : int creat (char * pathname, int fileMode);

(c) close system call:

The file is closed by using close system call. A return code 0 means the close succeeded.
A return value -1 means that the openFileID did not refer to open file.
Syntax : int close (int openFileID);

(d) read system call :

The operating system tries to read count bytes from the open file designated by openFileID. The
bytes are read from the file starting at the offset provided by the file location. If fewer then count
bytes are left before the end of the file all remaining bytes are read. This is not considered to be
an error. The bytes read are places into the array of bytes starting at bufferAddress. The file
location is increased by the number of bytes read. The return value is the number of bytes that
were actually read, and this might be less than count. A return value 0 indicates that the end of
file has been reached and the file location is equal to the size of the file, thus no more bytes can
be read. A negative return value indicates some error occurred in the read.

Syntax: int read (int openFileID, char * bufferAddress, int count);

(e) write system call :

The operating system tries to write coun bytes to the open file designated by openFileID. The
bytes are written to the file starting at the offset provided by the file location. The bytes are taken
from the array of bytes starting at bufferAddress. The file location is increased by the number of
bytes read. The return value is the number of bytes that were actually written. A negative return
value indicates some error occurred in the write. For causes of different negative values see man
pages. Note that the write system call specifies into which file to write, and from where to take
and how many characters for writing, but it does not indicate where in the file to write. The
location into file is not passed with the call but it is kept with open file information as a part of
the file state.

Syntax : int write (int openFileID, char * bufferAddress, int count);


(f) lseek system call :

It is used to achieve random access into the file since it changes the file location that will be used
for the next read or write. Close the open file using the close system call after completing the
work with the open file.

Syntax : int lseek (int openFileID, inf offset, int moveMode);

The file location associated with the open file is changed to a new value. The new value is
computed by adding the offset to the base. The base is selected according to the moveMode as
follows:

0 – use 0 as a base (move from the beginning of the file)

1 – use the current file location as a base (for relative move)

2 – use the current file size as a base (move from the end of the file). Positive values of the offset
will cause the next write to be beyond the current end of the file. A 0 value will cause the next
write to extend the file.

The returned value is the new file position. An lseek with an offset of 0 and a moveMode
of 1 will not change the file position but will return the current file position. If an error
occurs, a negative integer is returned.
(i) unlink system call :

It is used to delete the file. A return code 0 means the unlink succeeded. If an error occurs
in trying to delete a file, a negative integer is returned.
Syntax : int unlink (char * pathname);

Conclusion:

Studied various file system commands and their uses.


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<unistd.h>
#include<sys/types.h>
void display(int fd){ //function for Displaying
FILE
int count,buff[2048];
printf("\n\n-------- The Content of FILE is -----------------\n\n");
while((count=read(fd,buff,sizeof(buff)))>0)
printf("%s",buff);
}

int file_open(char source[40],int mode){ // Function for Opening


File
int fd;
switch(mode){
case 0:fd=open(source,O_RDONLY);break;
case 1:fd=open(source,O_WRONLY);break;
case 2:fd=open(source,O_RDWR);break;
}
if(fd==-1) printf("\n\n\t\t*** Cannot OPEN the File...\n");
else printf("\n\n\t\t* * * The File is OPENED Successfully * *
*\n\n");

return fd;
}

void file_read(char source[40]){ // Function for


Reading File
int fd,count;
fd=file_open(source,0);
if(fd!=-1){
display(fd);
close(fd);
}
}

void file_write(char source[40]){


int fd,count;
char data[20];
fd=file_open(source,2);
if(fd!=-1){
display(fd);
printf("\n\n\nEnter the Data to write to File\n\n ");
scanf("%s",&data);
count=strlen(data);
write(fd,data,count);
lseek(fd,0L,0); //To read from Begining of File
display(fd);
close(fd);
}
}

void file_copy(char source[40]){ // Finction for Copying File


int count;
int fdold,fdnew;
char dest[40],buffer[2048];
printf("\nEnter Name of Destination File:: ");scanf("%s",&dest);

fdold=file_open(source,0);
fdnew=creat(dest,0666);
if(fdnew==-1) printf("\nCannot Creat the File...");
if((fdold!=-1)&&(fdnew!=-1)){
while((count=read(fdold,buffer,sizeof(buffer)))>0){
write(fdnew,buffer,count);
}
printf("\n\n----The FILE is Copied Successfully------");
file_read(dest);
close(fdold);
close(fdnew);
}
}

void file_status(char source[40]){ // Function for File Status


int fd;
struct stat *buf;
char id[20];
fd=file_open(source,0);
if(fd!=-1){
stat(source,buf);
printf("\n\n\t***The Status of File is***");
printf("\nInode = %d",buf->st_ino); /* inode */
printf("\nProtection Mode = %d",buf->st_mode); /* protection */
printf("\nHard Links = %d",buf->st_nlink); /* number of hard links
*/
printf("\nUser ID of Owner = %d",buf->st_uid); /* user ID of
owner */
printf("\nGroup ID of Owner = %d",buf->st_gid); /* group ID of
owner */
printf("\nDevice Type = %d",buf->st_rdev); /* device type (if
inode device) */
printf("\nSize(Bytes) = %d",buf->st_size); /* total size, in
bytes */
printf("\nBlock Size = %d",buf->st_blksize); /* blocksize for
filesystem I/O */
printf("\nBlocks Allocated = %d",buf->st_blocks); /* number of
blocks allocated */
//printf("\nLast Access = %d",buf->st_atime); /* time of last
access */
//printf("\nLast Modification = %d",buf->st_mtime); /* time of
last modification */
//printf("\nLast Change = %d",buf->st_ctime); /* time of last
change */
}
}

void file_delete(char source[40]){ // Function for DELETING File


int val;
val=unlink(source);
if(val==0) printf("\n\n\t***The File is Deleted SuccessFully***");
else printf("\n\n\tERROR Occured while deleting File....");
}
void file_seek(char source[40]){
int fd;
char c,d;
fd=file_open(source,2);
if(fd!=-1){
read(fd,&c,1);
printf("\n\n\tThe FIRST character in the FILE is :: %c",c);
lseek(fd,-2L,2);
read(fd,&d,1);
printf("\n\n\tThe LAST character in the FILE is :: %c",d);
close(fd);
}
}
main(){
int ch;
char s[40];
printf("\n\n\tEnter the Name of Source File:: ");scanf("%s",&s);
do{
printf("\n\t\tFile Management Operations");
printf("\n\t\t 1.Open File");
printf("\n\t\t 2.Read File");
printf("\n\t\t 3.Write to File");
printf("\n\t\t 4.fstat");
printf("\n\t\t 5.Copy File");
printf("\n\t\t\t 6.Seek File");
printf("\n\t\t\t 7.Delete File");
printf("\n\t\t 8.Exit");
printf("\n\t Your Choice ::");
scanf("%d",&ch);

switch(ch){
case 1:file_open(s,0);break;
case 2:file_read(s);break;
case 3:file_write(s);break;
case 4:file_status(s);break;
case 5:file_copy(s);break;
case 6:file_seek(s);break;
case 7:file_delete(s);break;
case 8:break;
default:printf("\n\n\tWRONG Choice...");
}
}while(ch!=8);
exit(0);
}

[root@localhost Unix_Pro]# gcc File_Manage.c


[root@localhost Unix_Pro]# ./a.out

Enter the Name of Source File:: /root/Unix_Pro/temp.txt


File Management Operations
1.Open File
2.Read File
3.Write to File
4.fstat
5.Copy File
6.Delete File
7.Seek File
8.Exit
Your Choice ::1

* * * The File is OPENED Successfully * * *

Enter the Name of Source File:: /root/Unix_Pro/temp_file.txt


File Management Operations
1.Open File
2.Read File
3.Write to File
4.fstat
5.Copy File
6.Delete File
7.Seek File
8.Exit
Your Choice ::2

* * * The File is OPENED Successfully * * *

-------- The Content of FILE is -----------------


Hi how are You

i am Fine Yar
what are you doing dud?

Nothing yar, just doing timepass with mobile games.

You have any paln fo the evining?


No.
then can you come with me to see a film 'Chak De'?
yes, why not.
I wil br veyr happy with that .

Thank You.

MurlidharRamdasRakshe

Enter the Name of Source File:: /root/Unix_Pro/temp_file.txt


File Management Operations
1.Open File
2.Read File
3.Write to File
4.fstat
5.Copy File
6.Delete File
7.Seek File
8.Exit
Your Choice ::5

Enter Name of Destination File:: /root/Unix_Pro/tempy.txt

* * * The File is OPENED Successfully * * *


----The FILE is Copied Successfully------
* * * The File is OPENED Successfully * * *
-------- The Content of FILE is -----------------

Hi how are You

i am Fine Yar
what are you doing dud?

Nothing yar, just doing timepass with mobile games.

You have any paln fo the evining?


No.
then can you come with me to see a film 'Chak De'?
yes, why not.
I wil br veyr happy with that .

Thank You.

MurlidharRamdasRakshe
Enter the Name of Source File:: /root/Unix_Pro/tempy.txt
File Management Operations
1.Open File
2.Read File
3.Write to File
4.fstat
5.Copy File
6.Delete File
7.Seek File
8.Exit
Your Choice ::6
***The File is Deleted SuccessFully***

Title of Assignment:

Simultaneous execution of two or more threads.

Relevant Theory / Literature Survey: (Brief Theory Expected)

Threads:

A thread is a single sequence stream within a process. Threads are


executed within a process. They are sometimes called lightweight
processes. In a process, threads allow multiple executions of streams.
Threads are popular way to improve application through parallelism. The
CPU switches rapidly back and forth among the threads giving illusion that
the threads are running in parallel. Like a traditional process i.e., process
with one thread, a thread can be in any of several states (Running, Blocked,
Ready or Terminated). Each thread has its own stack. A thread consists of a
program counter (PC), a register set, and a stack space. Threads are not
independent of one other like processes as a result threads shares with
other threads their code section, data section, OS resources also known as
task, such as open files and signals.
Processes Vs Threads:
Similarities

• Threads share CPU and only one thread active (running) at a time.

• Threads within a process, execute sequentially.

• Thread can create children.

• If one thread is blocked, another thread can run.

Differences:

• Threads are not independent of one another.

• All threads can access every address in the task belonging to same
process.

Advantages of threads:

o As threads can share common data, they do not need to


use IPC.
o They only need a stack and storage for registers for creation of
threads.

o Threads do not need new address space, global data, program


code.

o Contexts switching is fast when working with threads.

Disadvantage: There is no protection between threads.


Types of threads :

(1) User-Level Threads : User-level threads implement in user-level


libraries, rather than via systems calls, so thread switching
does not need to call operating system and to cause interrupt
to the kernel. In fact, the kernel knows nothing about user-level
threads and manages them as if they were single-threaded
processes.
The user can accomplish this by moving the stack point at his discretion. This
reduces the overhead for the initial programming by the writer of the
operating system. Also, user-level threads usually switch faster than kernel-
level threads which adds to processor efficiency.

There are three main disadvantages to user-level threads.

One, starvation can often occur if one thread takes up too much of the time-slice.

The second is if one thread gets blocked, all other threads in that process will lose
their timeslice.

Finally, it cannot take advantage of any operating systems that can use symmetric
multiprocessing.

(2) Kernel-Level Threads: Since the only advantage in Linux of using user-level

threads is cooperative multitasking, Linux primarily uses kernel-level threads. In


this method, the kernel knows about and manages the threads.
The kernel has a thread table that keeps track of all threads in
the system. In addition, the kernel also maintains the traditional
process table to keep track of processes. Operating Systems
kernel provides system call to create and manage threads.
There are many advantages of using this method. Input/output blocking is not a
problem as it is in user-level. Also, the operating system’s code can take advantage
of symmetric multiprocessing.
How the Kernel Accesses the Threads

Each process contains at least one parent thread and as each thread is spawned, it is
assigned a TID, thread identification. Each thread also contains a PID, parent
identification. All threads that are children of the same parent are assigned the same
PID. Each thread can be referred to individually or as a group. For example, an
application has three threads, one parent and two children, and the threads share
the parent's PID. If the TID for the parent is 0x00011234 and the children’s TID’s are
0x00021234 and 0x00031234, each thread can be accessed with the address
0x00001234.

Advantages of Threads over Multiple Processes


• Context Switching Threads are very inexpensive to create and destroy,
and they are inexpensive to represent. For example, they require space to
store, the PC, the SP, and the general-purpose registers, but they do not
require space to share memory information, Information about open files of
I/O devices in use, etc. With so little context, it is much faster to switch
between threads.

• Sharing Threads allow the sharing of a lot resources that cannot be


shared in process, for example sharing code section, data section, Operating
System resources like open file etc.

Disadvantages of Threads over Multi processes


• Blocking The major disadvantage if that if the kernel is single
threaded, a system call of one thread will block the whole process and CPU
may be idle during the blocking period.

• Security Since there is, an extensive sharing among threads there is


a potential problem of security. It is quite possible that one thread over writes
the stack of another thread although it is very unlikely since threads are
meant to cooperate on a single task.

Basic thread primitives: There are various primitives that a thread system
must provide.

thread_create : It is used to create a new thread.

Syntax :

Int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*


start_routine) (void *), void *arg)

Pthread_t : It is defining a thread pointer. When a thread is created


identifier is written into the variable to which the pointer points. This
identifier helps to refer to thread.

Pthread_attr_t : It is used to set the thread attributes. Usually there is no


need to set the thread attributes. Pass this argument as NULL.

Name of function : The name of the function to be started by the thread for
execution.

Arguments to be passed to the function : When a new thread is created


it executes the function pointed by the function variable name.

pthread_join : It is used to wait for the thread represented in the


thread_join call.It waits for the thread represented in the call to finish
executing. It is analogous to wait() in Unix. It waits for the specified thread
to complete, and gathers information about the thread's exit status.

Syntax : Int pthread_join(pthread_t th , void *threadreturn);

First argument is the thread for which to wait.Second argument is pointer to


pointer that points to return value from the thread.

Pthread_exit: This function is used to terminate the calling thread.

Syntax : Void pthread_Exit(void *retval);


/*Program : Multithreading*/
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>

int A[5][5],B[5][5],C[5][5],D[5][5],E[5][5],m,n,p,q;
void *Add(void *);
void *Sub(void *);
void *Mul(void *);
void accept();
void display(int X[5][5],int a,int b);

int main(){
pthread_t t_add,t_sub,t_mul;
void *retval;
int res1,res2,res3,res;
accept();
printf("\n\n\tThe Entered Matrices are \n ");
display(A,m,n);
display(B,p,q);
printf("\n");
if(m==p&&n==q){
pthread_create(&t_add, NULL, Add, (void *) res);
pthread_create(&t_sub, NULL, Sub, (void *) res);
pthread_create(&t_mul, NULL, Mul, (void *) res);

res1=pthread_join(t_add,&retval);
res2=pthread_join(t_sub,&retval);
res3=pthread_join(t_mul,&retval);
}
else{
printf("\n\tFor Addition and Substraction the order of Matrices
Should be Same\n\n ");
if(n==p){
pthread_create(&t_mul, NULL, Mul, (void *) res);
res3=pthread_join(t_mul,&retval);
}
else printf("\n\t\tFor Multiplaication A(n) Should be Equal to
B(p)");

}
exit(EXIT_SUCCESS);
}

void accept(){
int i,j;
printf("\n\n\tEnter The Order of Matrix A(m*n) :: ");scanf("%d
%d",&m,&n);
printf("\n\n\t\tEnter The Elements");
for(i=0;i<m;i++){
for(j=0;j<n;j++){
printf("\n\t\t\tA[%d][%d]==",i,j);scanf("%d",&A[i][j]);
}
}
printf("\n\n\tEnter The Order of Matrix B(p*q) :: ");scanf("%d
%d",&p,&q);
printf("\n\n\t\tEnter The Elements");
for(i=0;i<p;i++){
for(j=0;j<q;j++){
printf("\n\t\t\tB[%d][%d]==",i,j);scanf("%d",&B[i][j]);
}
}

void display(int X[5][5],int a,int b){


int i,j;
printf("\n\t\t\t");
for(i=0;i<a;i++){
for(j=0;j<b;j++){
printf(" %d",X[i][j]);
}
printf("\n\t\t\t");
}
}

void *Add(void *arg){


int i,j;
for(i=0;i<m;i++){
for(j=0;j<n;j++){
C[i][j]=A[i][j]+B[i][j];
printf("\n\tIn ADDITION Function");
sleep(1);
}
}
printf("\n\n\t\t\tThe Addition is Over");
display(C,m,n);
pthread_exit(NULL);
}
void *Sub(void *arg){
int i,j;
for(i=0;i<m;i++){
for(j=0;j<n;j++){
D[i][j]=A[i][j]-B[i][j];
printf("\n\t\tIn SUBSTRACTION Function");
sleep(1);
}
}
printf("\n\n\t\t\tThe Substraction is Over");
display(D,m,n);
pthread_exit(NULL);
}

void *Mul(void *arg){


int i,j,k;
for(i=0;i<m;i++){
for(j=0;j<q;j++){
E[i][j]=0;
for(k=0;k<n;k++){
E[i][j]+=A[i][k]*B[k][j];
printf("\n\t\t\tIn MULTIPLICATION Function");
sleep(1);
}
}
}
printf("\n\n\t\t\tThe Multiplaication is Over");
display(E,m,q);
pthread_exit(NULL);
}

-------------------OUTPUT--------------------

[root@localhost Thread]# gcc mat.c -lpthread


[root@localhost Thread]# ./a.out

Enter The Order of Matrix A(m*n) :: 2 2


Enter The Elements
A[0][0]==1
A[0][1]==2
A[1][0]==1
A[1][1]==3

Enter The Order of Matrix B(p*q) :: 2 2


Enter The Elements
B[0][0]==1
B[0][1]==3
B[1][0]==2
B[1][1]==1

The Entered Matrices are

1 2
1 3
1 3
2 1

In ADDITION Function
In SUBSTRACTION Function
In MULTIPLICATION Function
In ADDITION Function
In SUBSTRACTION Function
In MULTIPLICATION Function
In ADDITION Function
In SUBSTRACTION Function
In MULTIPLICATION Function
In ADDITION Function
In SUBSTRACTION Function
In MULTIPLICATION Function

The Addition is Over


2 5
3 4

The Substraction is Over


0 -1
-1 2

In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function

The Multiplaication is Over


5 5
7 6

[root@localhost Thread]# ./a.out

Enter The Order of Matrix A(m*n) :: 2 3


Enter The Elements
A[0][0]==1
A[0][1]==2
A[0][2]==1
A[1][0]==2
A[1][1]==3
A[1][2]==1

Enter The Order of Matrix B(p*q) :: 3 2


Enter The Elements
B[0][0]==1
B[0][1]==1
B[1][0]==1
B[1][1]==1
B[2][0]==1
B[2][1]==1
The Entered Matrices are

1 2 1
2 3 1

1 1
1 1
1 1

For Addition and Substraction the order of Matrices Should be


Same

In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function
In MULTIPLICATION Function

The Multiplaication is Over


4 4
6 6

Conclusion:

Studied difference between threads and processes, advantages and


disadvantages,

creation of threads and uses of threads.


Title of Assignment:

Write and insert linux kernel module.

Relevant Theory / Literature Survey: (Brief Theory Expected)

Linux operates in two modes--the Kernel mode (kernel space) and the User mode (user
space). The kernel works in the highest level (also called supervisor mode) where it has
all the authority, while the applications work in the lowest level where direct access to
hardware and memory are prohibited. Linux transfers the execution from user space to
the kernel space through system calls and the hardware interrupts. The Kernel code
executing the system call works in the context of the process, which invokes the system
call. As it operates on behalf of the calling process, it can access the data in the processes
address space. The kernel code that handles interrupts, works to the processes and
related to any particular process.

Linux Kernel Module :The Linux kernel is a monolithic kernel i.e. it is one single large
program where all the functional components of the kernel have access to all of its
internal data structures and routines. The alternative to this is the micro kernel structure
where the functional pieces of the kernel are broken out into units with strict
communication mechanism between them. This makes adding new components into the
kernel, via the configuration process, rather time consuming. This is the best alternative
to dynamically load and unload the components of the operating system using Linux
Kernel Modules. The Linux kernel modules are piece of codes, which can be dynamically
linked to the kernel even after the system bootup. They can be unlinked from the kernel
and removed when they are no longer needed. Mostly the Linux kernel modules are used
for device drivers such as network drivers or file system. When a Linux kernel module is
loaded, it becomes a part of the Linux kernel as the normal kernel code and functionality
and it posses the same rights and responsibilities as the kernel code. Every kernel module
needs to include linux/module.h.

Modules are pieces of code that can be loaded and unloaded into the kernel
upon demand. They extend the functionality of the kernel without the need to
reboot the system.

A program usually begins with a main() function, executes a bunch of instructions and
terminates upon completion of those instructions. Kernel modules work a bit differently.
Module always begin with either the init_module or the function specified with
module_init call. This is the entry function for modules; it tells the kernel what
functionality the module provides and sets up the kernel to run the module's functions
when they're needed. Once it does this, entry function returns and the module does
nothing until the kernel wants to do something with the code that the module provides.

All modules end by calling either cleanup_module or the function you specify with the
module_exit call. This is the exit function for modules; it undoes whatever entry
function did. It unregisters the functionality that the entry function registered.Every
module must have an entry function and an exit function.

Init_module(): The init_module is called when the module is inserted into the kernel The
module is registered to the kernel and attaches its data-structures and functionality to the
kernel. The kernel-defined external functions are also resolved.

cleanup_module(): This module is called just before removing the module from the
kernel. It `unregisters' the module functionality from the kernel.

Loading modules : insmod command loads the `loadable kernel modules' in the running
kernel. insmod tries to link a module into the running kernel by resolving all the symbols
from the kernel's exported `symbol table'. When the Linux kernel discovers the need for a
module, the kernel requests to the kernel daemon to load the appropriate module. The
kernel daemon is the process having exclusive superuser privileges. At the time of
booting, it opens the IPC channel to the kernel and uses it for transferring messages
(request for loading modules), to and from the kernel. While loading the module, the
kerneld calls modprobe and insmod to load the required module. The demand loadable
kernel modules are usually located at /lib/module/ directory.

Insmod : The insmod depends on some critical system calls to load the module to the
kernel. It is used to insert a module into the Linux Kernel.It uses the sys_create_module
to allocate kernel memory to hold module. It uses get_kernel_syms system call to get the
kernel symbol table in order to link the module. It then calls the sys_init_module system
call to copy the relocatable object code of the module to the kernel space. And soon after
this, insmod calls the initialization function of the concerned module i.e. init_module.
These system are in kernel/module.c.

Unloading modules : The modules can be unloaded using rmmod command. While removing
modules, rmmod ensures the restriction that the modules are not in use and they are not referred
by any other module or the part of the kernel. The cleanup_module function of the concerned
module is called to freeup the kernel resources it has allocated. After the successful execution of
the cleanup_module, the module datastructure is marked DELETED and it is unlinked from the
kernel and unlisted from the list of kernel modules. The reference list of the modules on which it
is dependent is modified and dependency is released. The kernel memory allocated to the
concerned module is deallocated and returned to the kernel memory spool.

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

static int a,b;


MODULE_PARM(a,"i");
MODULE_PARM(b,"b");

static int s_module(void)


{
int c=0;
printk("<1>hello world\n");
c=2+3;
printk("sum is %d\n",c);
return 0;
}

static void e_module(void)


{
printk("<1>good bye \n");
}

module_init(s_module);
module_exit(e_module);

MODULE_LICENSE("GPL");

[root@localhost root]# vi raj.c

[root@localhost root]# make file

gcc -DMODULE -D__KERNEL__ -isystem /lib/modules/`uname -r`/build/include


file.c -o file

file.c: In function `read1':

file.c:62: void value not ignored as it ought to be

file.c: In function `write1':

[root@localhost root]# make

gcc -DMODULE -D__KERNEL__ -isystem /lib/modules/`uname -r`/build/include


-c -o abhi.o abhi.c

[root@localhost root]# insmod -f raj.ko

Warning: kernel-module version mismatch

raj.ko was compiled for kernel version 2.4.20

while this kernel is version 2.4.20-8


Warning: loading raj.ko will taint the kernel: forced load

See http://www.tux.org/lkml/#export-tainted for information about tainted


modules

Module raj.ko loaded, with warnings

[root@localhost root]# lsmod

Module Size Used by Tainted: GF

raj.ko 856 0 (unused)

ide-cd 35708 0 (autoclean)

cdrom 33728 0 (autoclean) [ide-cd]

soundcore 6404 0 (autoclean)

parport_pc 19076 1 (autoclean)

lp 8996 0 (autoclean)

parport 37056 1 (autoclean) [parport_pc lp]

autofs 13268 0 (autoclean) (unused)

ipt_REJECT 3928 6 (autoclean)

iptable_filter 2412 1 (autoclean)

ip_tables 15096 2 [ipt_REJECT iptable_filter]

keybdev 2944 0 (unused)

mousedev 5492 1

hid 22148 0 (unused)

input 5856 0 [keybdev mousedev hid]

usb-uhci 26348 0 (unused)

ehci-hcd 19976 0 (unused)

usbcore 78784 1 [hid usb-uhci ehci-hcd]

ext3 70784 2

jbd 51892 2 [ext3]

[root@localhost root]# mkdir -p/lib/modules/$(uname -r)/kernel/drivers/raj


[root@localhost root]#cp raj.c raj.ko

[root@localhost root]# vi /etc/modules

[root@localhost root]# reboot

[root@localhost root]# insmod -f raj.ko

[root@localhost root]# dmesg

dmesg

Linux version 2.4.20-8 (bhcompile@porky.devel.redhat.com) (gcc version


3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #1 Thu Mar 13 17:54:28 EST 2003

BIOS-provided physical RAM map:

hello world

[root@localhost root]# rmmod raj.ko

[root@localhost root]# dmesg

Linux version 2.4.20-8 (bhcompile@porky.devel.redhat.com) (gcc version


3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #1 Thu Mar 13 17:54:28 EST 2003

BIOS-provided physical RAM map:

hello world

sum is 5

good bye

Conclusion:

Studied the different commands used in loading and unloading of kernel


module.

You might also like