Let S Make Linux Together
Let S Make Linux Together
Let S Make Linux Together
Third Edition
Rohit Birla
MillenniumYear®
Tested by Programmers
Suggested by Educators
Written by me
Helped by friends
Revised:
1. Dec 2007
2. Sep 2009
Your Success, Our Strength™
Also Available :
- Review C 3.0.0
- Review C++ 3.0.0
- Review Java 3.0.0
- Review VB part1 3.0.0
- Working with .Net 2.0.0
- Let’s Make Linux Together 3.0.0
- Review DAA 3.0.0
: Note from Author
All material given here is either copied or taken from some else
and given in simple way. We have tried to cover all syllabus.
Before giving any Xerox copy of these notes, make sure that you
have given title page, also available, note from author, preface,
bibliography, content pages. Without these pages, it is illegal to give
those pages as Xerox copy.
Rohit Birla
15 December 2007
6:09:10 PM
Acknowledgement:
Making a book is a bear of undertaking, not only for the person who created it but also
for those around him or those who have to use this book. Mere words can‘t do justice to
the effect these people have had on me, either through technical assistance or moral
support. Still, words are all I have.
This book is derived from its previous editions. Who help me in my previous edition
includes Mr. Ravinder kajal and Mr. Manoj Rana, lecturers in department of computer
science in Maharaja Surjamal Institute. I am thankful to them for their dedication and
attention towards the book.
This book would not have been possible without the work of several other people. Firstly,
I want to thanks Mr. Vikas Polowalia, who give me idea of writing this integrated
solution. Many friends and colleagues have contributed greatly to the quality of this
book. I thank all of you for your help and constructive criticisms. My thanks go to
- Mr. Vikas Polowalia who help me in typing and in finding other topics
- MSI‘s laboratory of computer science
- Mrs. Krishna Devi (mother) who motivate and care me while I was working for
this book.
- Mr. Nishant Kohli for their practical works.
Grateful acknowledgement is extended to all the people who make this book possible
with their enthusiastic and encouragement.
I am grateful for the support given to me by my friends for supporting and motivating me
to write this book efficiently and effectively. They have provided an environment that has
helped me develop my self-confidence and generously given me the resources needed to
make this book. I really appreciate your support. For once words fail me. I have no idea
what I could say that would be appropriate for all the times you all have been there
throughout the years. ―Thank you‖ seems pitifully inadequate, but it‘s all I have.
Rohit Kumar
12/25/2007 11:28:29 AM
Preface:
This book provides an integrated solution for Linux environment. I have tried to write it
in simple language which is easily understandable by all the students. I wrote this book as
a text for an introductory course in Linux Programming at the junior or undergraduate
level. This book work as text book and more correctly you can refer it as notes for your
syllabus. Now to get marks is no more difficult if you complete this book.
To teacher: This book is designed to be both versatile and complete. You will find it
very useful and interesting while reading and teaching from this book. The problems
given in this book will sharpen your mind.
To students: I home that this textbook/ notes provide you with an enjoyable introduction
to the field of Linux. Before starting reading, you must have some knowledge of C.
To professional: the wide range of topics in this book makes it very useful and excellent
handbook. Because each unit is relatively self contained, you can focus in on the topics
that most interest you. Most of the part can be practically implemented and can be seen in
Linux kernel.
To colleagues: I have supplied an extensive bibliography and pointers to the current
literature. This book ends with model test papers and MYLinuxEntrance (T&P). Despite
myriad requests from students for solutions to problems and exercises, we have chosen as
a matter of policy not to supply references for problems and exercises, to remove the
temptation for students to look up a solution rather than to find it themselves.
Refrences:
1. Operating System Principles by Abraham Silberschatz,…
2. Linux Kernel Programming by M. Beck, …
3. Beginning Linux Programming by Neil Methew, …
4. Fedora 6 Bible by Christopher Negus
5. http://www.systhread.net
6. http://en.wikipedia.org/wiki
7. http://www.lynuxworks.com/products/posix
8. HAL by Bill Weinberg
9. http://www.computerhope.com
10. http://lowfatlinux.com
11. http://schemas.microsoft.com/intellisense
12. Memory management by Zhihua (Scott) Jiang
13. http://www.redhat.com/docs/manuals/linux/RHL-9-Manual
14. http://www.ibm.com/developerworks/library/l-linuxboot/index.html
15. http://www.yolinux.com/TUTORIALS/LinuxTutorialInitProcess.html
16. http://www.faqs.org/docs/kernel_2_4/lki-1.html
17. http://oldfield.wattle.id.au/luv/boot.html
18. http://kernel.org
19. http://www.beunited.org/bebook/The%20Kernel%20Kit
20. Named pipes by Faisal Faruqui
21. http://www.fedora.com
22. http://www.2000trainers.com/linux/linux-process-manage
23. http://209.85.175.104/search?q=cache:E13UX3p8EHkJ:tiger.la.asu.edu/Q
uick_Ref/Linux_Syscall_quickref.pdf+linux+system+calls&hl=en&ct=clnk&
cd=1&gl=in
24. http://www.ucl.ac.uk/is/unix/ee.htm
25. http://www.panix.com/~elflord/linux/editors/index.html
26. http://www.cs.rit.edu/~cslab/vi.html
Unit10 : Extras
Note: we have tried to give best of contents including surrounding factors. But it’s not
responsibility of Author for any +/- ve points. Read “Note from Author”.
Unit1:
History of Unix:
- Unix started as a single user OS.
- In 1969, Ken Thomson with Denis Ritchie and other wrote a general purpose OS
for small machines. It attracted a large number of users and then it is developed to
be multi-user OS.
- In 1973, Thompson and Ritchie rewrote the Unix OS in C, breaking away from
the tradition of writing Os in assembly.
- Around 1974, Unix was licensed to universities for educational purposes and few
years later was made commercial available.
- It is interesting to note that MS DOS was created much later than Unix. By that
time industry has begun to accept Unix as standard OX.
- Many vendors such as IBM, SUN, HP and others purchased the code of Unix and
develop their own versions of Unix.
o IBM use AIX
o SUN use SOLARIS
o DEC use ULTRIX
o HP use HP-UNIX
- To avoid confusion, some standards were laid down, known as POSIX ( Portable
Operating System Interface) (for Unix Environment). POSIX was a set pf
Standards that enables soft wares to run on different Unix based OS without
change to source code.
- There are many features which are same to that of Linux.
- In 1984, the BSD (Berkeley Software Distributions) group ported Unix on their
VAX machines. They implemented certain improvements over the original Unix
and created BSD versions of Unix.
- Improvements of BSD versions were:
o Support for virtual memory
o Demand paging
o A new shell (CSH)
o TCP/IP network protocols
The services like remote login, file transfer and e mail are possible
due to the TCP/IP network protocol supported by Unix.
Unix is still the most preferred OS for networking.
Advantages of Unix:
- Unix is more secure than other OS. It allows only authorised users to modify files
and directories.
- It does not infect from viruses.
- Stable: It can stay up for several years without any problem.
- Multi-user OS
- Can be loaded on any type of computer system
- Multi tasking OS: you can work with multiple programs simultaneously.
Disadvantages of Unix:
- Slightly difficult to install and configure
- Difficult to learn for windows users of PC
- Windows soft wares MS office, Internet explorer etc. are not available in Unix
however their replacements are available. eg: Word Perfect and Netscape
Navigator.
Unix Architecture:
kernel
Kernel:
The kernel is the core of OS. This is loaded in RAM as soon as the system starts
up. It manages memory, files, and peripheral devices and also maintains date and
time. The different functions performed by kernel are:
- Managing memory: Allocation and de-allocation of memory
- Scheduling: Enabling each user to work efficiently
- Organizing data transfer between I/O devices and memory
- Accept the instructions from shell and execute them
- Enforce the security measures.
Shell:
Shell is a program which interprets commands given by user. These commands
can be given in two ways: either typed or in a file called shell script. A variety of
shells supported by Unix are: Bourne shell, Korn shell, C shell.
Features of Shell:
- communication between user and Unix system takes place through the shell
- Shell allows background processing
- A sequence of commands can be collected in a file called shell script. The name
of the file can be used to execute the sequence of commands automatically.
- Shell includes features like loop and conditional constructs.
- Input of one command can be taken from the output of another command or
output of one command can be diverted to the input of a file or printer. Two
commands can be combined using pipe operator.
Multi User:
Unix is a multi-user OS. Each user has a different terminal. A terminal consists of
keyboard and a monitor and is connected to main computer known as host computer. A
host consists of hard disks, memory, processor and printer etc. these resources are
accessible to all the users.
Help:
To seek help on a command, we use $ man <command name>
eg: $man cp
A manual page will be displayed on the screen, with a lot of information such as
commands used, its syntax, switches/options available, examples etc.
File System:
- All information in Unix is treated as a file
- A single disk can store thousand of file.
- To manage these files, OS provides a file system.
- Similar files can be grouped in a directory.
- The file system of Unix is the main key to success of Unix system.
****************************************
Unit2:
History of Linux:
- Linus Torvald, a student at the University of Helsinki, Finland introduced
Linux in 1991
- Torvalds worked on Linux project and wrote the source code of Linux kernel.
He made Linux available on net.
- Many programmers added to the code, change it and built in support for all
kind of hardware.
- There are several versions of Linux available for different hardware platforms.
o Linux version 0.02 of Linux kernel was released in 1991
- Torvalds and hundreds of developers from across the world worked on it and
in march 1994, version 1.0 of Linux kernel was released.
o Red Har Linux 6.0 uses version 2.25 of all the Linux kernel
- Linux is Unix clone and has been written from scratch by Torvalds. Torvalds
was working in minix, a miniature version of Unix which was used for
teaching purposes in universities and colleges.
- Linux follows the open development model. Torvalds made the source code
available for study and changes over the internet. (and still is)
- Torvalds accepts modification to the kernel code. The result is that whenever
a new version of Linux having new functionality was released, people work
on it to fix the bug if any.
- To assess whether they are using some version, the following scheme is mage
eg: version 1.x.y if x is even it signifies stable version else changes to be done
very soon it‘s not stable.
Advantages of Linux:
1. Reliability: Linux is stable OS. Linux servers are not shut down for years
together. This means that users on Linux OS work consistently without
reporting OS failure.
2. Backward compatibility: Linux has an excellent support for older hardware. It
can run on different type of processors not just intel 386/ 486 but also on
DEC‘s alpha, sun sparc machine, power PC etc.
3. GUI interface: The graphical interface for Linux is X windows system. It is
devided into 2 subsystem consisting of server and client. Linux has a number
of graphical user interfaces called Desktop Environments such as K Desktop
Environment and GNU Object Model Environment, both of which are
versions of X windows system.
a. When we start KDE, desktop is organized into folder such as auto
start, CDROM, printer and floppy drive in form of icons
b. GNOME can be configured in the way you want to use it. It supports
the drag and drop mechanism. Gnome follows the common client
request bnker architecture (CORBA) standards to allow different
software to communicate easily.
4. Excellent Security features: It support high security that is why many ISP
(internet service providers) are replacing their current OS with Linux system.
5. Development libraries: Linux provides an excellent platform for many
development languages like c++, c, Perl, java, PHP and many more.
6. Can support high user load: Linux can support a large number of users
working simultaneously.
7. No known viruses: Linux is free from any viruses attacks so far, there are no
known viruses for Linux.
8. Multiple Distributors: there are many distributors of Linux
9. Simple upgrade: the installation procedure of most Linux version is menu
driven and easy. It includes the ability to upgrade from prior version. The
upgrade process preserves the existing configuration files and maintains a list
of its actions during installation.
Multiple Distributions:
To install Linux, the user requires a distribution. This consists of a boot diskette
and other diskettes or a CD-ROM. Installation scripts enable even in experienced users to
install systems that can be run. It helps that many software packages are already adapted
to Linux and appropriately configures: this saves a lot of time. Discussions are constantly
taking place with in Linux community on the quality of various distribution of this sort is
a very lengthy and complex task.
Internationally, the RedHat, S.u.S.E, Debian and slackware distributions are
widely used. Which of these distributions is used is a matter of taste. Distributions can be
obtained from FTP servers, e-mail systems, public domains distributors and some
bookshops. Sources of supply can be found by consulting specialist magazines or the
Linux newsgroup in usenet.
Pattern Matching:
1. ls a.???
2. ls a*.*
3. ls a[1 2 4]
4. ls a[1-5]
5. ls a[!1-5]
What are these what are their functions and why they are used? Try these on
system and find difference or you may ask any teacher of Linux. For further
information regarding these put these points in Google search.
Basic Commands:
These commands are executed on a terminal ( main menu > system tools > terminal)
env
Displays the permanent environment variables associated with a user‘s login id
exit command
Used to stop the execution of a shell script.
expr command
Expr (command) command is used for numeric computation.
The operators + (add), -(subtract), *(multiplu), /(divide), (remainder) are allowed.
Calculation are performed in order of normal numeric precedence.
find
The find command searches through directories for files that match the specified criteria.
It can take full pathnames and relative pathnames on the command line.
To display the output on screen the -print option must be specified
for operator
The for operator may be used in looping constructs where there is repetitive execution of
a section of the shell program.
For var in vall val2 val3 val4;
Do commnds; done
fsck
Used to check the file system and repair damaged files. The command takes a device
name as an argument
# /etc/fsck /dev/file-system-to-be-checked.
grave operator
Used to store the standard the output of a command in an enviroment variable. (‗)
grep
The grep (global regular expression and print) command can be used as a filter to search
for strings in files. The pattern may be either a fixed character string or a regular
expression.
Grep ―string‖ filename(s)
HOME
User‘s home directory
if operator
The if operator allows conditional operator
If expression; then commands; fi
if … then…else… fi
$ if; then
commands
efile; then
commands
fi
kill
used to stop background processes
In
used to link files. A duplicate of a file is created with another name
LOGNAME
displays user‘s login name
ls
Lists the files in the current directory
pg
Used to display data one page (screenful) at a time. The command can take a number of
filenames as arguments.
Pg [option] [filename] [filename2]…..
pipe
Operator (1) takes the output of one commands as input of another command.
ps
Gives information about all the active processes.
PS1
The system prompt
pwd
(print working directory) displays the current directory.
rm
The rm (remove) command is used to delete files from a directory. A number of files may
be deleted simultaneously. A file(s) once deleted cannot be retrieved.
rm [filename 1] [filename 2]…
sift command
Using shift $1becomes the source string and other arguments are shifted. $2 is shifted to
$1,$3to $2 and so on.
Sleep
The sleep command is used to suspend the execution of a shell script for the specified
time. This is usually in seconds.
sort
Sort is a utility program that can be used to sort text files in numeric or alphabetical order
Sort [filename]
split
Used to split large file into smaller files
Split-n filename
Split can take a second filename on the command line.
su
Used to switch to superuser or any other user.
sync
Used to copy data in buffers to files
system0
Used to run a UNIX command from within a C program
tail
The tail command may be used to view the end of a file.
Tail [filename]
tar
Used to save and restore files to tapes or other removable media.
Tar [function[modifier]] [filename(s)]
tee
output that is being redirected to a file can also be viewed on standard output.
test command
It compares strings and numeric values.
The test command has two forms : test command itself If test ${variable} = value then
Do commands else do commands
File
The test commands also uses special operators [ ]. These are operators following the of
are interpreted by the shell as different from wildcard characters.
Of [ -f ${variable} ]
Then
Do commands
Elif
[ -d ${variable} ]
then
do commands
else
do commands
fi
many different tests are possible for files. Comparing numbers, character strings, values
of environment variables.
time
Used to display the execution time of a program or a command. Time is reported in
seconds.
Time filename values
tr
The tr command is used to translate characters.
tr [-option] [string1 [string2]]
tty
Displays the terminal pathname
umask
Used to specify default permissions while creating files.
uniq
The uniq command is used to display the uniq(ue) lines in a sorted file.
Sort filename uniq
until
The operator executes the commands within a loop as long as the test condition is false.
wall
Used to send a message to all users logged in.
# /etc/wall message
wait
the command halts the execution of a script until all child processes, executed as
background processes, are completed.
wc
The wc command can be used to count the number of lines, words and characters in a
fine.
wc [filename(s)]
The available options are:
wc -[options] [filename]
-1
-w
-c
while operator
the while operator repeatedly performs an operation until the test condition proves false.
$ while
Ø do
commands
Ø done
who
displays information about all the users currently logged onto the system. The user name,
terminal number and the date and time that each user logged onto the system.
The syntax of the who command is who [options]
write
The write command allows inter-user communication. A user can send messages by
addressing the other user‘s terminal or login id.
write user-name [terminal number]
Linux architecture:
Kernel:
The core of Linux system is the kernel – the OS program. Kernel controls the
resources of computer, allot them to different users and tasks. It interacts directly with
h/w so making programs easy to write and portable across the different platforms
hardware. Since kernel communicates directly with hardware, the part of kernel must be
customized to the h/w features of each system. However kernel does not deal directly
with user. Instead, the login process starts up a separate interactive program called shell
for each user.
Shell:
Linux has a simple user interface b/w user and kernel called shell that has a power
to provide the service that a user wants. It protects the user from having to now the
intricate h/w details.
Counts
A number preceding any vi command tells vi to repeat that command that many
times.
Cursor Movement
j move down
k move up
Screen Movement
xG move to line x
Inserting
Copying Code
yy (yank)'copies' line which may then be put by the p(put) command. Precede
with a count for multiple lines.
Put Command
Find Commands
t find a character on the current line going forward and stop one character
before it
T find a character on the current line going backward and stop one
character before it
; repeat last f, F, t, T
Miscellaneous Commands
Reading files
:r filename
Write file
:# move to line #
To edit a file simply type ee followed by the filename at your Unix prompt, for example:
ee mytext
If a file of that name exists, the start of the file is then displayed on the screen, otherwise
an empty file of that name is created.
man ee
Unlike some other editors, there are no special modes to worry about. Typing ordinary
text will insert it into the document at the position of the cursor, and commands are
provided by [Ctrl] key combinations, a list of which is shown permanently at the top of
the screen as follows:
The caret symbol (^) indicates that the [Ctrl] key should be held down while pressing the
relevant key. On most keyboards, the cursor arrow keys will work correctly as well as the
[Ctrl] commands for cursor movement, and some keyboards also have [Page Up],
[Page Down] and [Delete] keys which can be used.
Using Menus
You can call up a menu of additional commands by pressing [Ctrl+[] or [Esc]. This main
menu appears as follows:
The cursor will be over the top menu item. leave editor in this case.
To select a menu item, move the cursor down to the required item using the cursor
motion commands or arrow keys and press the Enter key. Some items call up a further
menu.
Further Commands
Typing [Ctrl+C] will cause a prompt command: to appear at the bottom of the screen and
the panel at the top of the screen to be replaced by the following list of commands:
help : get help info |file : print file name |line : print line #
read : read a file |char : ascii code of char |0-9 : go to line "#"
write: write a file |case : case sensitive search |exit : leave and save
!cmd : shell "cmd" |nocase: ignore case in search |quit : leave, no
save
expand: expand tabs |noexpand: do not expand tabs
command:
To obey one of these commands, simply type the command name at the prompt and press
the Enter key. Most of the commands are also available via the main menu, so you can
choose your favourite way of doing some tasks. Commands may be abbreviated, as long
as that abbreviation is unique. For example, as no other command starts with a q, you can
quit the editor without saving your changes by typing the sequence [Ctrl+C] [q] [Enter].
A number of programs, including the pine> mailer, call a text editor directly. The default
editor on IS Unix Services is ee.
Tip for mail users: to incorporate a file into a mail message, you can use the read
command on the [Ctrl+C] menu.
Quitting ee
Leaving the editor is achieved by selecting the top item (leave editor) in the main menu,
which calls the following further menu:
So the usual method of finishing an editing session is to type the key sequence [Esc]
[Enter] [Enter]
ee
ee stands for "easy editor" ee is a very easy to use editor which always displays the
keybindings on line so that you don't have to know anything to use it. It is good for
people who don't want to learn how to use a text editor.
Emacs
Jed
Jed is a versatile editor that can "impersonate" a number of well known text editors
includiong emacs. For people looking for a wordstar clone or a lightweight version of
emacs, jed is nice.
Joe
Joe is a lot like jed: it is a lightwieght editor that includes different modes including pico,
wordstar and emacs.
mcedit
mcedit is the editor that ships with midnight commander. It is very dos like, it looks and
feels a lot like dos edit. Good for nostalgic windows refugees.
Nedit
Nedit is a GUI editor which should make windows users feel at home. It has some
programmer-friendly features, and is essentially a superset of the classic windows text
editors (notepad) in functionality.
Pico
Pico ships with the popular email client pine pico is much like ee in a number of ways. It
is not terribly powerful (in fact quite the opposite) but easy to use. Good for people who
don't want to know how to use a text editor.
Process Management
Any application that runs on a Linux system is assigned a process ID or PID. This is a
numerical representation of the instance of the application on the system. In most
situations this information is only relevant to the system administrator who may have to
debug or terminate processes by referencing the PID. Process Management is the series
of tasks a System Administrator completes to monitor, manage, and maintain instances of
running applications.
Multitasking
Each ―turn‖ is called a time slice, and each time slice is only a fraction of a second long.
It is this rapid switching from process to process that allows a computer to ―appear‘ to be
doing two things at once, in much the same way a movie ―appears‖ to be a continuous
picture.
Types of Processes
There are generally two types of processes that run on Linux. Interactive processes are
those processes that are invoked by a user and can interact with the user. VI is an
example of an interactive process. Interactive processes can be classified into foreground
and background processes. The foreground process is the process that you are currently
interacting with, and is using the terminal as its stdin (standard input) and stdout
(standard output). A background process is not interacting with the user and can be in one
of two states – paused or running.
1. Logon as root.
2. Run [cd \]
3. Run [vi]
5. Type [jobs]
6. Notice vi is running in the background
7. Type [fg %1]. This will bring the first background process to the foreground.
8. Close vi.
The second general type of process that runs on Linux is a system process or Daemon
(day-mon). Daemon is the term used to refer to process‘ that are running on the computer
and provide services but do not interact with the console. Most server software is
implemented as a daemon. Apache, Samba, and inn are all examples of daemons.
Any process can become a daemon as long as it is run in the background, and does not
interact with the user. A simple example of this can be achieved using the [ls –R]
command. This will list all subdirectories on the computer, and is similar to the [dir /s]
command on Windows. This command can be set to run in the background by typing [ls
–R &], and although technically you have control over the shell prompt, you will be able
to do little work as the screen displays the output of the process that you have running in
the background. You will also notice that the standard pause (ctrl+z) and kill (ctrl+c)
commands do little to help you.
System Call:
System call is the services provided by Linux kernel. In C programming, it often uses
functions defined in libc
which provides a wrapper for many system calls. Manual page section 2 provides more
information about
system calls. To get an overview, use ―man 2 intro‖ in a command shell.
It is also possible to invoke syscall() function directly. Each system call has a function
number defined in
<syscall.h>or <unistd.h>. Internally, system call is invokded by software interrupt 0x80
to transfer control to
the kernel. System call table is defined in Linux kernel source file
―arch/i386/kernel/entry.S ‖.
System Call Example
#include <syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int main(void) {
long ID1, ID2;
/*-----------------------------*/
/* direct system call */
/* SYS_getpid (func no. is 20) */
/*-----------------------------*/
ID1 = syscall(SYS_getpid);
printf ("syscall(SYS_getpid)=%ld\n", ID1);
/*-----------------------------*/
/* "libc" wrapped system call */
/* SYS_getpid (Func No. is 20) */
/*-----------------------------*/
ID2 = getpid();
printf ("getpid()=%ld\n", ID2);
return(0);
}
System Call Quick Reference
No Func Name Description
Source
1
exit
terminate the current process
kernel/exit.c
2
fork
create a child process
arch/i386/kernel/process.c
3
read
read from a file descriptor
fs/read_write.c
4
write
write to a file descriptor
fs/read_write.c
5
open
open a file or device
fs/open.c
6
close
close a file descriptor
fs/open.c
7
waitpid
wait for process termination
kernel/exit.c
8
creat
create a file or device ("man 2 open" for
information)
fs/open.c
9
link
make a new name for a file
fs/namei.c
10 unlink
delete a name and possibly the file it refers to
fs/namei.c
11 execve
execute program
arch/i386/kernel/process.c
12 chdir
change working directory
fs/open.c
13 time
get time in seconds
kernel/time.c
14 mknod
create a special or ordinary file
fs/namei.c
15 chmod
change permissionsof a file
fs/open.c
16 lchown
change ownership of a file
fs/open.c
18 stat
get file status
fs/stat.c
19 lseek
reposition read/write file offset
fs/read_write.c
20 getpid
get process identification
kernel/sched.c
21 mount
mount filesystems
fs/super.c
22 umount
unmount filesystems
fs/super.c
23 setuid
set real user ID
kernel/sys.c
24 getuid
get real user ID
kernel/sched.c
25 stime
set system time and date
kernel/time.c
26 ptrace
allows a parent process to control the execution of
a child process
arch/i386/kernel/ptrace.c
27 alarm
set an alarm clock for delivery of a signal
kernel/sched.c
28 fstat
get file status
fs/stat.c
29 pause
suspend process until signal
arch/i386/kernel/sys_i386.c
30 utime
set file access and modification times
fs/open.c
33 access
check user's permissions for a file
fs/open.c
34 nice
change process priority
kernel/sched.c
36 sync
update the super block
fs/buffer.c
37 kill
send signal to a process
kernel/signal.c
38 rename
change the name or location of a file
fs/namei.c
39 mkdir
create a directory
fs/namei.c
40 rmdir
remove a directory
fs/namei.c
41 dup
duplicate an open file descriptor
fs/fcntl.c
42 pipe
create an interprocess channel
arch/i386/kernel/sys_i386.c
43 times
get process times
kernel/sys.c
45 brk
change the amount of space allocated for the
calling process's data segment
mm/mmap.c
46 setgid
set real group ID
kernel/sys.c
47 getgid
get real group ID
kernel/sched.c
48 sys_signal
ANSI C signal handling
kernel/signal.c
49 geteuid
get effective user ID
kernel/sched.c
50 getegid
get effective group ID
kernel/sched.c
51 acct
enable or disable process accounting
kernel/acct.c
52 umount2
unmount a file system
fs/super.c
54 ioctl
control device
fs/ioctl.c
55 fcntl
file control
fs/fcntl.c
56 mpx
(unimplemented)
57 setpgid
set process group ID
kernel/sys.c
58 ulimit
(unimplemented)
59 olduname
obsolete uname system call
arch/i386/kernel/sys_i386.c
60 umask
set file creation mask
kernel/sys.c
61 chroot
change root directory
fs/open.c
62 ustat
get file system statistics
fs/super.c
63 dup2
duplicate a file descriptor
fs/fcntl.c
64 getppid
get parent process ID
kernel/sched.c
65 getpgrp
get the process group ID
kernel/sys.c
66 setsid
creates a session and sets the process group ID
kernel/sys.c
67 sigaction
POSIX signal handling functions
arch/i386/kernel/signal.c
68 sgetmask
ANSI C signal handling
kernel/signal.c
69 ssetmask
ANSI C signal handling
kernel/signal.c
70 setreuid
set real and effective user IDs
kernel/sys.c
71 setregid
set real and effective group IDs
kernel/sys.c
72 sigsuspend
install a signal mask and suspend caller until
signal
arch/i386/kernel/signal.c
73 sigpending
examine signals that are blocked and pending
kernel/signal.c
74 sethostname
set hostname
kernel/sys.c
75 setrlimit
set maximum system resource con sumption
kernel/sys.c
76 getrlimit
get maximum system resource con sumption
kernel/sys.c
77 getrusage
get maximum system resource con sumption
kernel/sys.c
78 gettimeofday
get the date and time
kernel/time.c
79 settimeofday
set the date and time
kernel/time.c
80 getgroups
get list of supplementary group IDs
kernel/sys.c
81 setgroups
set list of supplementary group IDs
kernel/sys.c
82 old_select
sync. I/O multiplexing
arch/i386/kernel/sys_i386.c
83 symlink
make a symbolic link to a file
fs/namei.c
84 lstat
get file status
fs/stat.c
85 readlink
read the contents of a symbolic link
fs/stat.c
86 uselib
select shared library
fs/exec.c
87 swapon
start swapping to file/device
mm/swapfile.c
88 reboot
reboot or enable/disable Ctrl-Alt-Del
kernel/sys.c
89 old_readdir
read directory entry
fs/readdir.c
90 old_mmap
map pages of memory
arch/i386/kernel/sys_i386.c
91 munmap
unmap pages of memory
mm/mmap.c
92 truncate
set a file to a specified length
fs/open.c
93 ftruncate
set a file to a specified length
fs/open.c
94 fchmod
change access permission mode of file
fs/open.c
95 fchown
change owner and group of a file
fs/open.c
96 getpriority
get program scheduling priority
kernel/sys.c
97 setpriority
set program scheduling priority
kernel/sys.c
98 profil
execution time profile
99 statfs
get file system statistics
fs/open.c
100 fstatfs
get file system statistics
fs/open.c
101 ioperm
set port input/output permissions
arch/i386/kernel/ioport.c
102 socketcall
socket system calls
net/socket.c
103 syslog
read and/or clear kernel message ring buffer
kernel/printk.c
104 setitimer
set value of interval timer
kernel/itimer.c
105 getitimer
get value of interval timer
kernel/itimer.c
106 sys_newstat
get file status
fs/stat.c
107 sys_newlstat
get file status
fs/stat.c
108 sys_newfstat
get file status
fs/stat.c
109 olduname
get name and information about current kernel
arch/i386/kernel/sys_i386.c
110 iopl
change I/O privilege level
arch/i386/kernel/ioport.c
111 vhangup
virtually hangup the current tty
fs/open.c
112 idle
make process 0 idle
arch/i386/kernel/process.c
113 vm86old
enter virtual 8086 mode
arch/i386/kernel/vm86.c
114 wait4
wait for process termination, BSD style
kernel/exit.c
115 swapoff
stop swapping to file/device
mm/swapfile.c
116 sysinfo
returns information on overall system statistics
kernel/info.c
117 ipc
System V IPC system calls
arch/i386/kernel/sys_i386.c
118 fsync
synchronize a file's complete in-core state with that
on disk
fs/buffer.c
119 sigreturn
return from signal handler and cleanup stack
frame
arch/i386/kernel/signal.c
120 clone
create a child process
arch/i386/kernel/process.c
121 setdomainname
set domain name
kernel/sys.c
122 uname
get name and information about current kernel
kernel/sys.c
123 modify_ldt
get or set ldt
arch/i386/kernel/ldt.c
124 adjtimex
tune kernel clock
kernel/time.c
125 mprotect
set protection of memory mapping
mm/mprotect.c
126 sigprocmask
POSIX signal handling functions
kernel/signal.c
127 create_module
create a loadable module entry
kernel/module.c
128 init_module
initialize a loadable module entry
kernel/module.c
129 delete_module
delete a loadable module entry
kernel/module.c
130 get_kernel_syms
retrieve exported kernel and module symbols
kernel/module.c
131 quotactl
manipulate disk quotas
fs/dquot.c
132 getpgid
get process group ID
kernel/sys.c
133 fchdir
change working directory
fs/open.c
134 bdflush
start, flush, or tune buffer-dirty-flush daemon
fs/buffer.c
135 sysfs
get file system type information
fs/super.c
136 personality
set the process execution domain
kernel/exec_domain.c
137 afs_syscall
(unimplemented)
138 setfsuid
set user identity used for file system checks
kernel/sys.c
139 setfsgid
set group identity used for file system checks
kernel/sys.c
140 sys_llseek
move extended read/write file pointer
fs/read_write.c
141 getdents
read directory entries
fs/readdir.c
142 select
sync. I/O multiplexing
fs/select.c
143 flock
apply or remove an advisory lock on an open file
fs/locks.c
144 msync
synchronize a file with a memory map
mm/filemap.c
145 readv
read data into multiple buffers
fs/read_write.c
146 writev
write data into multiple buffers
fs/read_write.c
147 sys_getsid
get process group ID of session leader
kernel/sys.c
148 fdatasync
synchronize a file's in-core data with that on disk
fs/buffer.c
149 sysctl
read/write system parameters
kernel/sysctl.c
150 mlock
lock pages in memory
mm/mlock.c
151 munlock
unlock pages in memory
mm/mlock.c
152 mlockall
disable paging for calling process
mm/mlock.c
153 munlockall
reenable paging for calling process
mm/mlock.c
154 sched_setparam
set scheduling parameters
kernel/sched.c
155 sched_getparam
get scheduling parameters
kernel/sched.c
156 sched_setscheduler set scheduling algorithm parameters
kernel/sched.c
157 sched_getscheduler get scheduling algorithm parameters
kernel/sched.c
158 sched_yield
yield the processor
kernel/sched.c
159
sched_get_priority_
max
get max static priority range
kernel/sched.c
160
sched_get_priority_
min
get min static priority range
kernel/sched.c
161
sched_rr_get_inter
val
get the SCHED_RR interval for the named process
kernel/sched.c
162 nanosleep
pause execution for a specified time (nano seconds) kernel/sched.c
163 mremap
re-map a virtual memory address
mm/mremap.c
164 setresuid
set real, effective and saved user or group ID
kernel/sys.c
165 getresuid
get real, effective and saved user or group ID
kernel/sys.c
166 vm86
enter virtual 8086 mode
arch/i386/kernel/vm86.c
167 query_module
query the kernel for various bits pertain ing to
modules
kernel/module.c
168 poll
wait for some event on a file descriptor
fs/select.c
169 nfsservctl
syscall interface to kernel nfs daemon
fs/filesystems.c
170 setresgid
set real, effective and saved user or group ID
kernel/sys.c
171 getresgid
get real, effective and saved user or group ID
kernel/sys.c
172 prctl
operations on a process
kernel/sys.c
173 rt_sigreturn
arch/i386/kernel/signal.c
174 rt_sigaction
kernel/signal.c
175 rt_sigprocmask
kernel/signal.c
176 rt_sigpending
kernel/signal.c
177 rt_sigtimedwait
kernel/signal.c
178 rt_sigqueueinfo
kernel/signal.c
179 rt_sigsuspend
arch/i386/kernel/signal.c
180 pread
read from a file descriptor at a given offset
fs/read_write.c
181 sys_pwrite
write to a file descriptor at a given offset
fs/read_write.c
182 chown
change ownership of a file
fs/open.c
183 getcwd
Get current working directory
fs/dcache.c
184 capget
get process capabilities
kernel/capability.c
185 capset
set process capabilities
kernel/capability.c
186 sigaltstack
set/get signal stack context
arch/i386/kernel/signal.c
187 sendfile
transfer data between file descriptors
mm/filemap.c
188 getpmsg
(unimplemented)
189 putpmsg
(unimplemented)
190 vfork
create a child process and block parent
arch/i386/kernel/process.c
System Administration
To look after everything about Linux system, called system administration which
includes
a. monitoring disk space and taking backup
b. handling system problems which are unexpected
c. to handle every eventuality. System administrator must have thorough
practical knowledge of every system component
d. he is responsible for installing all system peripherals
e. he devise the scripts for automating some operations carried out regularly
f. he must also be able to configure the system‘s initialization script
Gnu zip:
$gzip foldername/filename
$gunzip gzipfile
Locating files:
$find <pathlist> <selection criteria> <action>
#find / -name a.txt –print (search file a.txt in / and then display)
#find /home –atime +365 –mailroot (search file whose access time is more than
365 days and then mail it)
#find / -size -2048 –print (search file whose size is below 2 mb)
#find / -size +1024 –atime -365 –rm
Copying diskettes and tapes
Copy floppy to temp folder:
#dd if=/dev/rdsk/f0q18dt of=/temp bs=147456
Input file name output file name block size
Copy tape
#dd if=/dev/rct0 of=/dev/rct1 bs=9K
example1:
copy one file to other
#!/bin/sh
#this is comment
cp $1 $2 #cp will copy first command line argumented file to other
exit 0
example2:
search a word in file
#!/bin/sh
#search a word
echo "Enter strings"
echo "if you have done, press ctrl + d"
cat > str_file
echo "e nter string to find"
read str
grep -s $str "/root/shell_scripts/str_file"
exit 0
example3:
sort n numbers
#!/bin/sh
#sort n numbers
echo "enter n numbers"
echo "after you have done, press ctrl+d"
cat > n_num
sort -n n_num
exit 0
example4:
to display date, process status and calendar of year
#!/bin/sh
date
ps –a
cal 2008
exit 0
example5:
multiplication table
#!/bin/sh
echo “enter a number”
read n
i=1
while [$i –le 10 ]
do
echo “$n X $i = `expr $i \* $n`”
i=`expr $i + 1`
done
exit 0
example6:
fibnoccii series
#!/bin/sh
a=1
b=0
c=1
i=1
n=15
while [ $i –le $n ]
do
c=`expr $a + $b`
echo $c
a=$b
b=$c
i=`expr $i + 1`
done
exit 0
example7:
count word, lines and characters
#!/bin/sh
echo “enter a string”
read str
echo $str > a.txt
wc a.txt
example8:
prime or not
#!/bin/sh
echo “enter a number”
read num
i=2 #counter
k=1 #flag
n=`expr $num / 2 `
echo “n=$n”
while [ $i –le $n ]
do
echo “counter : $i”
j=`expr $num % $i`
echo “remainder: $j”
if [ $j –eq 0 ]
then
echo “not a prime number”
k=0
exit 0
fi
i=`expr $i + 1`
done
if [ $k –eq 1]
then
echo “prime”
else
echo “not prime”
fi
exit 0
example9:
use of for loop
#!/bin/sh
for i in 1 2 3 4 5
do
echo “welcome $i”
done
example10:
use of case
#!/bin/sh
echo “enter a number”
read a
case $a in
1) echo “hello”;;
2) echo “hi”;;
3) echo “by”;;
*) echo “else case”
esac
exit 0
shell script is a language that not ends here but it depends on your practice how
much you can, try your c programs which you have done earlier.
Unit 4
Data Structure in Linux Kernel*:
*- this unit is given as for crammers. If you want to understand this unit, you have
to study at your own yet I have tried to make understandable.
Like of C-functions, Kernel uses kmalloc() and kfree() for allocating small amount
of memory and free(ing) that memory.
void * kmalloc(size_t size,int flags)
void kfree(void * object)
Process Table:
Every process occupy exactly one entry in process table. INIT_TASK macro
points at the first task in the system. It is initialized by starting the system using
INIT_TASK macro. After the system has been booted, that is only responsible for the use
of unclaimed system time (idle process : System idle process (pid:0))
Even if the process table has a dynamic structure, the number of tasks is restricted
to max_threads in system.
int max_thread;
however it can be change by sysctl interface.
for working with each process kernel use for_each_task() macro
#define for_each_task(p)
for (p=&init_task; p != &init_task; p=p->next_task)
Queue and Semaphores:
struct list_head {
struct list_head *next,*prev;
};
struct _wait_queue {
struct task_struct *task;
struct list_head task_list;
};
struct wait_queue_head {
struct list_head task_list;
};
add_wait_queue() and remove_wait_queue() are used for adding deleting in wait queue
extern int sem->count=1;
void down(struct semaphore *sem)
{
while(sem->count <= 0)
sleep_on(&sem->wait);
sem->count -= 1;
}
struct file
{
…
mode_t f_mode; //access mode in which file is opened
loff_t f_pos; //pos of read/write pointer
atomic_t f_count; //simple reference number(index)
unsigned int f_flags; //additional flag for access
struct dentry *fs_dentry; //reference to entry in directory cache
// to access inode
…
};
struct inode
{
…
kdev_t i_dev; //description of device (fd0,cdrom,hda,sda)
unsigned long i_no; //identify file in device (fifth,100th) eg: index no
off_t i_size; //size of file
time_t i_mtime; //last modification time
time_t i_atime; //last access time
time_t i_ctime; //last modification to inode eg: file move, cut-paste.
…
};
Task Structure:
One of the most important concept in a multitasking system such as Linux is the
task : the data structure and algorithms for process management form the central core of
Linux
struct task_struct
{
volatile long state; //current state of process TASK_RUNNING
//TASK_INTERRUPTABLE, TASK_UNINTERRUPTABLE
unsigned long flags; //bit mask of system status (sys. Working, stand
//by, logoff, switch user
unsigned long ptrace; //process is monitored by another process/not
long counter; //number of ticks assigned
long nice; //priority default: {NZERO}
unsigned long policy; //SCHED_FIFO,SCHED_RR,SCHED_OTHER
unsigned long rt_priority; //real-time priority
};
Mounting:
Before a file can be accessed, the file system containing the file must be mounted.
This can be done using either the system call mount or the function mount_root(). Every
mounted file system is represented by a super_block structure. These structures are
placed in a dynamic table super_blocks held by the struct list_head type. The maximum
length of this list is limited by the max_super_blocks variable. The function read_super()
of VFS is used to initialize the superblock. It creates an empty superblock, puts it in the
superblock list and calls the function provided by every file system implementation to
create the superblock.
Superblock:
The file system specific function read_super() reads information from the
corresponding block device. This is also the reason why a process is necessary for
mounting file system.
struct super_block
{
struct list_head s_list; //list of super blocks
kdev_t s_dev; //device
unsigned long s_blocksize; //block size
unsigned char s_dirt; //if superblock has been changed
wait_queue_hed_t s_wait; //waiting queue
…
};
struct super_operations
{
void (*read_inode)(struct inode *);
//inode structure is initialized by this function
void (*write_inode)(struct inode *);
//save info of inode
void (*write_super)(struct super_block *);
//save info of super block
void (*delete_inode)(struct inode *);
//delete inode
…
};
Inode:
struct inode {
struct list_head i_list; //chaining
unsigned long i_ino; //inode number
uid_t i_uid; //user id
gid_t i_gid; //group id
kdev_t i_rdev; //real device
time_t i_atime; //last access time
off_t i_size; //size of file
time_t i_mtime; //last modification time
time_t i_ctime; //last change to inode
…
};
struct inode_operations {
int (*create) ( . . .);
//create the inode
int (*mkdir)(. . .);
//creates a directory
int (*rmdir)(. . .);
//removes a directory
int (*rename)(. . .);
//move a file or rename it
int (*set_attr)(. . .);
//to set attributes of a inode
int (*get_attr)(. . .);
//to get attributes of a inode
…
};
File Structure:
struct list_head {
struct list_head f_list; //chaining
mode_t f_mode; //access type
loff_t f_pos; //position in file
unsigned int f_uid,f_gid; //owner
…
};
struct file_operation
{
loff_t (*llseek)( . . .);
//to deal with positioning with in the file
ssize_t (*read)(. . .);
//reads count bytes from the file and copies them into the buffer
ssize_t (*write)(. . .);
//write count bytes
int (*open)( . . .);
//to open a file
...
};
Proc file system:
Linux supports different filesystem. Each process in the system which is currently
running is assigned a directory /proc/pid where pid is the process identification number of
the relevant process. This directory contains files holding information on certain
characterstics of the process.
When proc file system is mounted, the VFS function read_super() is called by
do_mount() and in turn calls the function proc_read_super() for the proc file system in
the file_system list.
iget() generate the indoe for the proc root directory, which is entered in the
superblock_parse_options() then processes the mount options data that have been
provided and sets the owner of the root inode.
Accessing the file system is always carried out by accessing the root inode of the
file system. The first access is made by calling iget(). If the inode does not exists, this
function then calls the proc_read_inode() function entered in the proc_sops structure
The inode describe the directory with read and execute permissions for all
processes. The proc_root_inode_operations only provides two functions: readdir in form
of proc_readroot() function and lookup as proc_lookuproot(). Both functions operate
using the table root_dir[], which contains the different entries for the root directory
struct proc_dir_entry
{
const char *name; //name of entry
mode_t mode; //mode
uid_t uid; //user id
gid_t gid; //group id
unsigned long size; //size of file
struct proc_dir_entry *next,*parent; //chaining
void *data;
...
};
Ext2 file system:
As Linux was initially developed under MINIX, it is hardly surprising that first
Linux file system was minix file system. However, this file system restricts partitions to
64 MB and file names to 14 chars, so the search for a better file system was obvious.
Although this allowed partitions of up to 2GB and filename up to 255 chars. It included
several signigicant extensions but offered unsatisfactory performance. The second
extended file system (Ext2) was introduced in 1994.
Features:
i) Block Fragmentation: it allows different sized blocks to be allocated.
ii) Access Control List: allows ACL to be associated with each file
iii) Handles compressed and encrypted files
iv) Logical Deletion: an undelete option will allow users to easily recover
removed files.
Structure:
Ext2 file system has blocks and each block has
a. a copy of file system‘s super block
b. a copy of group of block group descriptors
c. a data block bitmap
d. a group of inode
e. an inode bitmap
f. a chunk of data belonging to a file/ data block
An ext2 disk super block is stored in ext2_super_block structure which contains the total
number of inodes, file system size, number of reserved blocks, free blocks counter, free
inodes counter, block size, fragment size and other important information.
Directories:
are maintained by singly link list.
struct ext2_dir_entry_2 {
_u32 inode; //inode number
_u16 rec_len; // length of directory entry
_u8 name_len; //length of file name
_u8 file_type; //type of file
Char name[EXT2_NAME_LEN]; //file name
};
Block allocation:
a. Target oriented: This algo looks for target block if that not found then look with
in 32 blocks near target block if no one is free, then find block at least in same
block group and even if that is not found search else where and allocate that.
b. Pre allocation: If a free block is found, up to eight following blocks are reserved.
When the file is closed, the remaining blocks still reserved are released. This also
guarantees that as many data blocks as possible are collected into one cluster.
Proc vs ext2:
Proc ext2
One processor is chosen by BIOS called Boot Processor (BSP) and used for system
initialization. All other Application Processors (AP) are initially halted by BIOS. The
Multi Processor (MP) specification filled in BIOS and informs OS about existing
multiprocessor system. BIOS initially forwards all interrupts only to boot processor, so
that single processor system see no difference and run only on BSP.
Problems with multiprocessor systems:
For correct functioning of multitasking system, it is important that data in kernel can only
be changed by one processor, so that identical resources cannot be allocated twice.
Unix system:
a) Coarse granted locking: lock whole kernel
b) Finer grained locking: reduce time that a lock must keep => reduce
particularly critical latency time
Linux system:
Rules were established
i. no process running in kernel mode interrupted by other process running in
kernel mode except when it releases control and steps
ii. an interrupt handling can interrupt a process in kernel mode but in end
control return back to same process
iii. interrupt handling will be processed completely and interrupt cannot be by
process in kernel mode and be by interrupt of higher priority
Symmetric Multiprocessing:
There are two processors and kernel decides which process should be allocated to
the processor. Memory is shared b/w processors. When there is some updation in the
process, then they will be stored in process only. This will not be reflected back which
will create problem. We use shared memory because changes are reflected. SMP denote a
multiprocessor architecture in which low CPU is selected as a Master CPU but rather all
of these cooperate on an equal basis. When kernel is to be loaded, the basic processor
CMOS is set which loads the kernel.
Features of SMP:
1. Shared Memory
2. Shared IO Port
3. Hardware Cache Synchronization: Synchronization means providing a cache at
time to process one by one. Suppose both processes are working on same program
and storing variables in different cache and they are doing same modifications at
same time, which is not safe and therefore only one cache is provided at a time.
4. SMP is provided by atomic operation like read/write back to disk, modification
5. Distributed Interrupt Handling: Every process has been provided by its own
interrupt controller known as APIC
Changes to kernel:
In order to implement SMP in Linux, changes have to be made to both portable
and processor specific implementations.
Kernel Initialization:
All processors must be started because BIOS has halted all APs and only boot
processor is running. Only this processor enters start_kernel(), then smp_init() for normal
initialization then smp_boot_cpus(). This activates all other processors. Each processor
receives its own stack. Each processor execute code and jump to start_kernel(). Once
exception handling and interrupt handling are initialized, processors trapped by
smp_callin() inside start_secondary().
asmlinkage void start_secondary(void)
{
trap_init();
init_IRQ();
smp_callin();
cpu_idle(NULL);
}
void smp_callin(void)
{
…
celibrate_delay(); //determine processor‘s bogomips
smp_store_cpu_info(cpuid); //save processors parameters
…
while(!smp_commenced);
…
}
How a halted processor is started:
This is served by APIC which allows to send Interprocessor Interrupt (IPI) and
InitIPI to all processors. This INIT signal works like reset and via this reset flag,
processor jump to BIOS. Then startupIPI is send to begin execution of real mode routine.
After all processors are started, smp_num_cpus contains number of currently running
processors. Then an idle task is created for each processes in order not to blick kernel
mode for all other processors. After smp_init(), smp_commence() is called which sets
smp_commenced flag where all APs can quit smp_callin() and process their individual
idle task.
Spooling:
This is about OS concept: where input is written on magnetic tape and then
processed and latterly output is again written on tape and when printer will free, that will
pick and print. Rest of this topic I leave on you as you r home work
Scheduling:
Linux scheduler shows only slightly changes. Task structure now has
processor;
NO_PROC_ID; //if no processor has assigned as yet
last_processor; number/ID of processor processes last task
Every processor is assigned a new task which is executable and not been assigned
to any other processor. Those task are preferred that last ran on currently available
processor. This led to improvement in system performance when internal processor
caches still contain data valid for selected processes.
current_set(smp_processor_id()); // to set process to current processor
Every significant piece of s/w will contain defects, typical 2-5 per100 loc. Because of
these mistakes, s/w does not behave as it is suppose to. Bug Tracking, identification and
removal can consume a large amount of programmer‘s time during s/w development.
Debugging is not testing (the task of verifying the program‘s operation in all possible
condition) although testing and debugging are related and many bugs are discovered
during testing process.
Types of errors:
Specification errors:
If a program is incorrectly specified, it will inevitably fail to
perform as required. Even the best programmer in the world can
write the wrong program. Before starting programming.
Programmer must understand hat the program needs to do you can
detect and remove many specification errors by removing
requirement and agreeing with person who will use this.
Design errors:
Programs of any size need to be designing before they are created.
Take time to think about how you will construct the program, hat
data structure you ill need and how they will be used
Codding errors:
Every one makes typing errors. Creating source code from design
in an imperfect process, if you find a bug. Instead of rereading or
asking other one to read,. It is surprisingly just how many bugs you
can detect and remove by talking through implementation with
someone else.
Note: compiler (like c) can caught errors at compile time while interpreter (Linux shell)
caught at run time
In brief, following approach used for debugging and testing a Linux program
Example:
Sometime , a segmentation fault occurs , os send s a signal to program saying it
has detected an illegal memory access and is terminating program to prevent
memory from being corrupted, the ability of os to detect illegal memory access
depends on its h/w configuration and its memory management,
#ifdef DEBUG
printf(―x=%d‖,x);
# endif compile with gcc-DEBUG
__LINE__ for current line
__FILE__ for current file # ifdef debug
__DATE__ current date printf(―line‖__LINE__―date‖__DATE__);
__TIME__ current time #endif
$cc –o cfile DEBUG cfile1.c
Controlled execution: add extra lines or use a debugger like gnu debugger (gdb),
xxgdb,tgdb. The emcas editor also has a facility that allows
u to run gdb on your program, set breakpoints and see
which line is being executed.
Working with gdb:
$cc –g –o file1 file1.c (press enter)
$gdb file1 (press enter)
...
...
(gdb) help (press enter)
For displaying commands
(gdb)run (press enter)
Starting program : /root/file1
...
Program received signal . . ., segmentation fault
...
(gdb) print j
$1 = 4
(gdb) print a[3]
$2 = { . . . }
(gdb) help breakpoint
...
(gdb) break 20
To insert breakpoint at line 20
(gdb) run
To continue running
(gdb) print a[0] @ 5
Print data from a[0] to a[5]
(gdb) cont
To continue execution
(gdb) diable break1
To disable first break point
(gdb) commands 2 those commands are written here which are run on second break point
> set variable m=m+1
> cont
>end
Other debuggers:
1. $ valgrind -leak –check=yes –v ./file1
2. printk: in printk debugger, code is checked and an error occurred create the
check points and print an appropriate alarm message. ex: whenever a kernel
segment process wish to call the data and code of user segment process,
verify_area() is fired, which check all area related to process and if any error
is occurred, calls the printk debugger, which print appropriate message.
Modules:
Modules are components of Linux kernel that can be loaded and attached to it as
needed. To add support for a new device, you can now simply instruct a kernel to load its
module. In some cases, you may have to recompile only that module to provide support
for your device. The use of modules has the added advantage of reducing the size if the
kernel program. The kernel can load modules in memory only as they are needed. ex: the
module for the BLOCK devices and FILE SYSTEM .
Select: the select function checks whether data can be read from the device or written to
it. If the device is free or argument wait is NULL, the device will only be checked. If it is
ready for function concerned, select() will return 1 otherwise a 0. If wait is not NULL,
the processes must be held up until the device become available.
Kernel daemon:
The kernel daemon is a process which automatically carries out loading and
removing of modules without user noticing it. ex: whenever a file is accessed by floppy,
so kernel daemon load the block device module for handling the block device and load
the file system modules for particular system. But how does the kernel daemon know that
modules need to be loaded.
Communication between the Linux kernel and kernel daemon is carried out by
means of IPC. The kernel daemon opens a message queue with the new flag
IPC_KERNELD. The kernel sends the message to the kernel daemon by kerneld_send
function. Request is stored in kerneld_msg structure, which includes different
information.
responsibility for loading and releasing modules lies with the functions:
a) request_module: kernel requests the loading of a module and waits until the
operation has been carried out.
b) release_module: removes a module
c) delayed_release_module: allows a module to be removed with a specific delay
d) cancel_release_module: allows a module to be removed with a specified
condition.
Unit6:
InterProcessCommunication(IPC)*
*-This unit is totally written by me after working with IPC however contents are copied
but that are changed to make proper understanding. For any queries regarding this unit
just write to my email. All queries asked within support period will be answered and
explained in detail.
There are many applications in which process need to cooperate with each other. If a
process want to share a resource, it is important to make sure that no other process is
accessing that resource. This situation called race condition. To eliminate the race
conditions is the only use of IPC. A variety of forms of IPC can be used under Linux.
These supports resource sharing, synchronization, connectionless and connection oriented
exchange of data or combination of all of above.
1. Resource Sharing: resources like printer sharing and sharing memory need
communication. These two techniques should be taken care while
communication, so that no process can modify other process or access other
process.
2. Connection less/oriented: In connection oriented, two processes must set up a
connection before communicating ex: you use telephone call, in Linux we use
pipes. In connectionless, we send a packet and leave it to infrastructure to deliver
them. Like for sending letter.
3. Synchronization: are used to eliminate race conditions.
Synchronization in kernel:
Because kernel manages the system, access by processes to these resources must
be synchronized. Normally, a process will not be interrupted by schedule() unless it
explicitly allows the execution of other processes by calling schedule(). Process in kernel
can be interrupted by interrupt handling routine: this may result in race condition even if
process is not executing any function that can lock file.
In Linux kernel, process are locked and particular events are waited for via
waiting queues. A process can sit on waiting queue and will not be interrupted until
processes in waiting queue are reactivated by interrupt handling routine/ another process.
Make the structure of wait_queue and wait_queue_head and list_head. These are already
given in unit4.
For adding and removing tasks from wait queue, we use add_wait_queue() and
remove_wait_queue(). A process can be moved to TASK_INTERRUPTIBLE and
TASK_UNINTERRUPTIBLE state. In first case, a task can be interrupted while not in II
case. Note that, both processes can be written in same wait queue. A process can be sleep
using sleep_on function and wake by wake_up macro.
sleep_on(struct wait_queue **p)
{
struct wait_queue wait;
wait.task=current;
current->state=TASK_UNINTERRUPTIBLE;
add_wait_queue(p,&wait);
schedule();
remove_wait_queue(p,&wait);
}
Synchronization in kernel is done by semaphores. explain up and down functions of
semaphore.
Communication via files:
is the oldest way of exchanging data between programs. Program A writes data to
a file and B read data. In a multitasking system, both programs could be run as processes
at least quasi parallel to each other. Race condition then usually produce inconsistencies
in the file data. Program B reads data before A finished modifying it. In Linux, there are
two ways of locking: mandatory: lock whole kernel and advisory: locking file records;
reading / writing to file will continue even after lock has been set.
Mandatory: It blocks r/w operations through out entire area. There are two methods for
locking entire area
a) lock whole file by means of fcntl() system call. This function is invoked by
flock(). Flock() are not defined as POSIX standard, so programmers are advised
against using it.
b) in addition to files to be locked, there is an auxiliary file known as lock file is
created which refuses access to the file when it is present.
a. link: create a lock file if it does not exist. On a failure, it calls sleep()
b. create: abort with an error code if process which is being called does not
possess the appropriate access right
c) open lock file, if it not exist else error message will appear
- to all these three points is that after a failure, process must repeat its attempt to set
a lock file. The process will call sleep() to wait for 1 sec and then try again.
+ process can work so that no other process can modify it or write data in file
+ no more than one process can excess same data. It means that reading can be done
but writing cannot be done on any area of file
Advisory locking: with advisory locking, all processes accessing the file for r/w
operations have to set the appropriate lock and release it again. Locking file area is
usually referred as record locking. Advisory locking of file area is achieved by system
call fcntl().
If there is no existing lock, then both r/w operations are possible
If more than one read lock exist, then read is possible while write not
If one write lock exists, then r/w both are illegal
- deadlock
+ more than one process work on different area in a single file
Pipes:
Are the ways in which, one process can communicate with other processes in fifo
manner, that is pipe, is a one way flow of data b/w processes, all the data written by a
process to the pipe, is routed by the kernel to another process, which can thus read it.
In Linux shell, pipes can be created by means of |(pipe) operator
Pipes are very simple way of IPC. And thus I leave it to you to understand and make your own notes.
line[n] = '\0';
printf("A messige from the parent process: %s",line);
}
}
Named pipes:
Named pipes allow two unrelated processes to communicate with each other. They are
also known as FIFOs (first-in, first-out) and can be used to establish a one-way (half-
duplex) flow of data.
Named pipes are identified by their access point, which is basically in a file kept on the
file system. Because named pipes have the pathname of a file associated with them, it is
possible for unrelated processes to communicate with each other; in other words, two
unrelated processes can open the file associated with the named pipe and begin
communication. Unlike anonymous pipes, which are process-persistent objects, named
pipes are file system-persistent objects, that is, they exist beyond the life of the process.
They have to be explicitly deleted by one of the processes by calling "unlink" or else
deleted from the file system via the command line.
In order to communicate by means of a named pipe, the processes have to open the file
associated with the named pipe. By opening the file for reading, the process has access to
the reading end of the pipe, and by opening the file for writing, the process has access to
the writing end of the pipe.
A named pipe supports blocked read and write operations by default: if a process opens
the file for reading, it is blocked until another process opens the file for writing, and vice
versa. However, it is possible to make named pipes support non-blocking operations by
specifying the O_NONBLOCK flag while opening them. A named pipe must be opened
either read-only or write-only. It must not be opened for read-write because it is half-
duplex, that is, a one-way channel.
Shells make extensive use of pipes; for example, we use pipes to send the output of one
command as the input of the other command. In real-life UNIX® applications, named
pipes are used for communication, when the two processes need a simple method for
synchronous communication.
A named pipe can be created in two ways -- via the command line or from within a
program.
A named pipe may be created from the shell command line. For this one can use either
the "mknod" or "mkfifo" commands.
Example:
To create a named pipe with the file named "npipe" you can use one of the following
commands:
% mknod npipe p
or
% mkfifo npipe
You can also provide an absolute path of the named pipe to be created.
Now if you look at the file using "ls ?l", you will see the following output:
The 'p' on the first column denotes that this is a named pipe. Just like any file in the
system, it has access permissions that define which users may open the named pipe, and
whether for reading, writing, or both.
Within a Program
The function "mkfifo" can be used to create a named pipe from within a program. The
signature of the function is as follows:
The mkfifo function takes the path of the file and the mode (permissions) with which the
file should be created. It creates the new named pipe file as specified by the path.
The function call assumes the O_CREATE|O_EXCL flags, that is, it creates a new named
pipe or returns an error of EEXIST if the named pipe already exists. The named pipe's
owner ID is set to the process' effective user ID, and its group ID is set to the process'
effective group ID, or if the S_ISGID bit is set in the parent directory, the group ID of the
named pipe is inherited from the parent directory.
A named pipe can be opened for reading or writing, and it is handled just like any other
normal file in the system. For example, a named pipe can be opened by using the open()
system call, or by using the fopen() standard C library function.
As with normal files, if the call succeeds, you will get a file descriptor in the case of
open(), or a 'FILE' structure pointer in the case of fopen(), which you may use either
for reading or for writing, depending on the parameters passed to open() or to fopen().
Therefore, from a user's point of view, once you have created the named pipe, you can
treat it as a file so far as the operations for opening, reading, writing, and deleting are
concerned.
Reading From and Writing to a Named Pipe
Reading from and writing to a named pipe are very similar to reading and writing from or
to a normal file. The standard C library function calls read( ) and write( ) can be used
for reading from and writing to a named pipe. These operations are blocking, by default.
The following points need to be kept in mind while doing read/writes to a named pipe:
A named pipe cannot be opened for both reading and writing. The process opening it
must choose either read mode or write mode. The pipe opened in one mode will
remain in that mode until it is closed.
Read and write operations to a named pipe are blocking, by default. Therefore if a
process reads from a named pipe and if the pipe does not have data in it, the reading
process will be blocked. Similarly if a process tries to write to a named pipe that has
no reader, the writing process gets blocked, until another process opens the named
pipe for reading. This, of course, can be overridden by specifying the
O_NONBLOCK flag while opening the named pipe.
Seek operations (via the Standard C library function lseek) cannot be performed on
named pipes.
Although named pipes give a half-duplex (one-way) flow of data, you can establish full-
duplex communication by using two different named pipes, so each named pipe provides
the flow of data in one direction. However, you have to be very careful about the order in
which these pipes are opened in the client and server, otherwise a deadlock may occur.
For example, let us say you create the following named pipes:
In order to establish a full-duplex channel, here is how the server and the client should
treat these two named pipes:
Let us assume that the server opens the named pipe NP1 for reading and the second pipe
NP2 for writing. Then in order to ensure that this works correctly, the client must open
the first named pipe NP1 for writing and the second named pipe NP2 for reading. This
way a full-duplex channel can be established between the two processes.
Code Samples
The code samples given here were compiled using the GNU C compiler version 3.0.3 and
were run and tested on a SPARC processor-based Sun Ultra 10 workstation running the
Solaris 8 Operating Environment.
The client opens the same named pipe in write mode and writes a user-specified string to
the pipe (see Figure 1).
The following table shows the contents of the header file used by both the client and
server. It contains the definition of the named pipe that is used to communicate between
the client and the server.
Filename : half_duplex.h
Server Code
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
char buf[MAX_BUF_SIZE];
exit (1);
}
fd = open(HALF_DUPLEX, O_RDONLY);
buf[numread] = '0';
count = 0;
buf[count] = toupper(buf[count]);
count++;
Client Code
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int fd;
if (argc != 2) {
exit (1);
fd = open(HALF_DUPLEX, O_WRONLY);
Make sure you run the server first, so that the named pipe gets created.
Expected output:
% hd_server &
The server program will block here, and the shell will return control to the command
line.
% hd_client hello
The client opens the first pipe for writing, and it sends data through this pipe to the
server. The client opens the second pipe for reading, and through this pipe, it reads the
server's response (see Figure 2).
The following table shows the contents of the header file used by both the client and
server. It contains the definition of the two named pipes that are used to communicate
between the client and the server.
Filename : fullduplex.h
Server Code
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
char buf[MAX_BUF_SIZE];
exit (1);
}
ret_val = mkfifo(NP2, 0666);
exit (1);
buf[numread] = '0';
count = 0;
buf[count] = toupper(buf[count]);
count++;
}
/*
* pipe
*/
Client Code
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
char rdbuf[MAX_BUF_SIZE];
if (argc != 2) {
printf("Usage : %s <string to be sent to the server>n", argv[0]);
exit (1);
rdbuf[numread] = '0';
When you run the server, it will create the two named pipes and will block on the read
call. It will wait until the client writes something to the named pipe. After that it will
convert the string to upper case and then write it to the other pipe, which will be read by
the client and displayed on STDOUT. When you run the client you will need to give a
string as an argument.
Make sure you run the server first, so that the named pipe gets created.
Expected output:
% fd_server &
The server program will block here, and the shell will return control to the command
line.
% fd_client hello
The client program will send the string to server and block on the read to await the
server's response.
In the Solaris 2.x operating system, the most efficient way to implement shared memory
applications is to rely on the mmap() function and on the system's native virtual memory
facility. Solaris 2.x also supports System V shared memory, which is another way to let
multiple processes attach a segment of physical memory to their virtual address spaces.
When write access is allowed for more than one process, an outside protocol or
mechanism such as a semaphore can be used to prevent inconsistencies and collisions.
A process creates a shared memory segment using shmget()|. The original owner of a
shared memory segment can assign ownership to another user with shmctl(). It can also
revoke this assignment. Other processes with proper permission can perform various
control functions on the shared memory segment using shmctl(). Once created, a shared
segment can be attached to a process address space using shmat(). It can be detached
using shmdt() (see shmop()). The attaching process must have the appropriate
permissions for shmat(). Once attached, the process can read or write to the segment, as
allowed by the permission requested in the attach operation. A shared segment can be
attached multiple times by the same process. A shared memory segment is described by a
control structure with a unique ID that points to an area of physical memory. The
identifier of the segment is called the shmid. The structure definition for the shared
memory segment control structures and prototypews can be found in <sys/shm.h>.
The key argument is a access value associated with the semaphore ID. The size
argument is the size in bytes of the requested shared memory. The shmflg argument
specifies the initial access permissions and creation control flags.
When the call succeeds, it returns the shared memory segment ID. This call is also used
to get the ID of an existing shared segment (from a process requesting sharing of some
existing memory portion).
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
...
...
key = ...
size = ...
shmflg) = ...
shmctl() is used to alter the permissions and other characteristics of a shared memory
segment. It is prototyped as follows:
The process must have an effective shmid of owner, creator or superuser to perform this
command. The cmd argument is one of following control commands:
SHM_LOCK
-- Lock the specified shared memory segment in memory. The process must have
the effective ID of superuser to perform this command.
SHM_UNLOCK
-- Unlock the shared memory segment. The process must have the effective ID of
superuser to perform this command.
IPC_STAT
-- Return the status information contained in the control structure and place it in
the buffer pointed to by buf. The process must have read permission on the
segment to perform this command.
IPC_SET
-- Set the effective user and group identification and access permissions. The
process must have an effective ID of owner, creator or superuser to perform this
command.
IPC_RMID
-- Remove the shared memory segment.
The buf is a sructure of type struct shmid_ds which is defined in <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
...
shmid = ...
cmd = ...
if ((rtrn = shmctl(shmid, cmd, shmid_ds)) == -1) {
perror("shmctl: shmctl failed");
exit(1);
}
...
shmat() and shmdt() are used to attach and detach shared memory segments. They are
prototypes as follows:
shmat() returns a pointer, shmaddr, to the head of the shared segment associated with a
valid shmid. shmdt() detaches the shared memory segment located at the address
indicated by shmaddr
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
...
p = &ap[nap++];
p->shmid = ...
p->shmaddr = ...
p->shmflg = ...
...
i = shmdt(addr);
if(i == -1) {
perror("shmop: shmdt failed");
} else {
(void) fprintf(stderr, "shmop: shmdt returned %d\n", i);
}
...
We develop two programs here that illustrate the passing of a simple piece of memery (a
string) between the processes if running simulatenously:
shm_server.c
-- simply creates the string and shared memory portion.
shm_client.c
-- attaches itself to the created shared memory portion and uses the string
(printf.
shm_server.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSZ 27
main()
{
char c;
int shmid;
key_t key;
char *shm, *s;
/*
* We'll name our shared memory segment
* "5678".
*/
key = 5678;
/*
* Create the segment.
*/
if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
/*
* Now put some things into the memory for the
* other process to read.
*/
s = shm;
/*
* Finally, we wait until the other process
* changes the first character of our memory
* to '*', indicating that it has read what
* we put there.
*/
while (*shm != '*')
sleep(1);
exit(0);
}
shm_client.c
/*
* shm-client - client program to demonstrate shared memory.
*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSZ 27
main()
{
int shmid;
key_t key;
char *shm, *s;
/*
* We need to get the segment named
* "5678", created by the server.
*/
key = 5678;
/*
* Locate the segment.
*/
if ((shmid = shmget(key, SHMSZ, 0666)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
/*
* Now read what the server put in the memory.
*/
for (s = shm; *s != NULL; s++)
putchar(*s);
putchar('\n');
/*
* Finally, change the first character of the
* segment to '*', indicating we have read
* the segment.
*/
*shm = '*';
exit(0);
}
Semaphore:
Explain p/up and v/down function
Semaphore Example 1: Locking
The most typical use of a semaphore is to protect a chunk of code that can only be
executed by one thread at a time. The semaphore acts as a lock; acquire_sem() locks the
code, release_sem() releases it. Semaphores that are used as locks are (almost always)
created with a thread count of 1.
As a simple example, let's say you keep track of a maximum value like this:
/* max_val is a global. */
uint32 max_val = 0;
...
bump_max() isn't thread safe; there's a race condition between the comparison and the
assignment. So we protect it with a semaphore:
sem_id max_sem;
uint32 max_val = 0;
...
/* Initialize the semaphore during a setup routine. */
status_t init()
{
if ((max_sem = create_sem(1, "max_sem")) < B_NO_ERROR)
return B_ERROR;
...
}
void bump_max(uint32 new_value)
{
if (acquire_sem(max_sem) != B_NO_ERROR)
return;
if (new_value > max_value)
max_value = new_value;
release_sem();
}
________________________________________
Semaphore Example 2: Benaphores
A "benaphore" is a combination of an atomic variable and a semaphore that can improve
locking efficiency. If you're using a semaphore as shown in the previous example, you
should consider using a benaphore instead (if you can).
Here's the example re-written to use a benaphore:
sem_id max_sem;
uint32 max_val = 0;
int32 ben_val = 0;
status_t init()
{
/* This time we initialized the semaphore to 0. */
if ((max_sem = create_sem(0, "max_sem")) < B_NO_ERROR)
return B_ERROR;
...
}
void bump_max(uint32 new_value)
{
int32 previous = atomic_add(&ben_val, 1);
if (previous >= 1)
if (acquire_sem(max_sem) != B_NO_ERROR)
goto get_out;
get_out:
previous = atomic_add(&ben_val, -1);
if (previous > 1)
release_sem(max_sem);
}
The point, here, is that acquire_sem() is called only if it's known (by checking the
previous value of ben_val) that some other thread is in the middle of the critical section.
On the releasing end, the release_sem() is called only if some other thread has since
entered the function (and is now blocked in the acquire_sem() call). An important point,
here, is that the semaphore is initialized to 0.
________________________________________
Semaphore Example 3: Imposing an Execution Order
Semaphores can also be used to coordinate threads that are performing separate
operations, but that need to perform these operations in a particular order. In the
following example, we have a global buffer that's accessed through separate reading and
writing functions. Furthermore, we want writes and reads to alternate, with a write going
first.
We can lock the entire buffer with a single semaphore, but to enforce alternation we need
two semaphores:
sem_id write_sem, read_sem;
char buffer[1024];
release_sem(read_sem);
}
release_sem(write_sem);
}
The initial thread counts ensure that the buffer will be written to before it's read: If a
reader arrives before a writer, the reader will block until the writer releases the read_sem
semaphore.
Message queue:
The basic idea of a message queue is a simple one.
Two (or more) processes can exchange information via access to a common system
message queue. The sending process places via some (OS) message-passing module a
message onto a queue which can be read by another process (Figure 24.1). Each message
is given an identification or type so that processes can select the appropriate message.
Process must share a common key in order to gain access to the queue in the first place
(subject to other permissions -- see below).
Fig. Basic Message Passing IPC messaging lets processes send and receive messages,
and queue messages for processing in an arbitrary order. Unlike the file byte-stream data
flow of pipes, each IPC message has an explicit length. Messages can be assigned a
specific type. Because of this, a server process can direct message traffic between clients
on its queue by using the client process PID as the message type. For single-message
transactions, multiple server processes can work in parallel on transactions sent to a
shared message queue.
Before a process can send or receive a message, the queue must be initialized (through
the msgget function see below) Operations to send and receive messages are performed
by the msgsnd() and msgrcv() functions, respectively.
When a message is sent, its text is copied to the message queue. The msgsnd() and
msgrcv() functions can be performed as either blocking or non-blocking operations. Non-
blocking operations allow for asynchronous message transfer -- the process is not
suspended as a result of sending or receiving a message. In blocking or synchronous
message passing the sending process cannot continue until the message has been
transferred or has even been acknowledged by a receiver. IPC signal and other
mechanisms can be employed to implement such transfer. A blocked message operation
remains suspended until one of the following three conditions occurs:
• The call succeeds.
• The process receives a signal.
• The queue is removed.
Initialising the Message Queue
The msgget() function initializes a new message queue:
int msgget(key_t key, int msgflg)
It can also return the message queue ID (msqid) of the queue corresponding to the key
argument. The value passed as the msgflg argument must be an octal integer with settings
for the queue's permissions and control flags.
The following code illustrates the msgget() function.
#include <sys/ipc.h>;
#include <sys/msg.h>;
...
...
key = ...
msgflg = ...
...
if (msgp == NULL) {
(void) fprintf(stderr, "msgop: %s %d byte messages.\n",
"could not allocate message buffer for", maxmsgsz);
exit(1);
...
msgsz = ...
msgflg = ...
/*
* Declare the message structure.
*/
main()
{
int msqid;
int msgflg = IPC_CREAT | 0666;
key_t key;
message_buf sbuf;
size_t buf_length;
/*
* Get the message queue id for the
* "name" 1234, which was created by
* the server.
*/
key = 1234;
/*
* We'll send message type 1
*/
sbuf.mtype = 1;
buf_length = strlen(sbuf.mtext) ;
/*
* Send a message.
*/
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0) {
printf ("%d, %d, %s, %d\n", msqid, sbuf.mtype, sbuf.mtext, buf_length);
perror("msgsnd");
exit(1);
}
else
printf("Message: \"%s\" Sent\n", sbuf.mtext);
exit(0);
}
The essential points to note here are:
• The Message queue is created with a basic key and message flag msgflg =
IPC_CREAT | 0666 -- create queue and make it read and appendable by all.
• A message of type (sbuf.mtype) 1 is sent to the queue with the message ``Did you
get this?''
message_rec.c -- receiving the above message
The full code listing for message_send.c's companion process, message_rec.c is as
follows:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
/*
* Declare the message structure.
*/
main()
{
int msqid;
key_t key;
message_buf rbuf;
/*
* Get the message queue id for the
* "name" 1234, which was created by
* the server.
*/
key = 1234;
/*
* Receive an answer of message type 1.
*/
if (msgrcv(msqid, &rbuf, MSGSZ, 1, 0) < 0) {
perror("msgrcv");
exit(1);
}
/*
* Print the answer.
*/
printf("%s\n", rbuf.mtext);
exit(0);
}
The essential points to note here are:
• The Message queue is opened with msgget (message flag 0666) and the same key
as message_send.c.
• A message of the same type 1 is received from the queue with the message ``Did
you get this?'' stored in rbuf.mtext.
Some further example message queue programs
The following suite of programs can be used to investigate interactively a variety of
massage passing ideas (see exercises below).
The message queue must be initialised with the msgget.c program. The effects of
controlling the queue and sending and receiving messages can be investigated with
msgctl.c and msgop.c respectively.
msgget.c: Simple Program to illustrate msget()
/*
* msgget.c: Illustrate the msgget() function.
* This is a simple exerciser of the msgget() function. It prompts
* for the arguments, makes the call, and reports the results.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
main()
{
key_t key; /* key to be passed to msgget() */
int msgflg, /* msgflg to be passed to msgget() */
msqid; /* return value from msgget() */
(void) fprintf(stderr,
"All numeric input is expected to follow C conventions:\n");
(void) fprintf(stderr,
"\t0x... is interpreted as hexadecimal,\n");
(void) fprintf(stderr, "\t0... is interpreted as octal,\n");
(void) fprintf(stderr, "\totherwise, decimal.\n");
(void) fprintf(stderr, "IPC_PRIVATE == %#lx\n", IPC_PRIVATE);
(void) fprintf(stderr, "Enter key: ");
(void) scanf("%li", &key);
(void) fprintf(stderr, "\nExpected flags for msgflg argument
are:\n");
(void) fprintf(stderr, "\tIPC_EXCL =\t%#8.8o\n", IPC_EXCL);
(void) fprintf(stderr, "\tIPC_CREAT =\t%#8.8o\n", IPC_CREAT);
(void) fprintf(stderr, "\towner read =\t%#8.8o\n", 0400);
(void) fprintf(stderr, "\towner write =\t%#8.8o\n", 0200);
(void) fprintf(stderr, "\tgroup read =\t%#8.8o\n", 040);
(void) fprintf(stderr, "\tgroup write =\t%#8.8o\n", 020);
(void) fprintf(stderr, "\tother read =\t%#8.8o\n", 04);
(void) fprintf(stderr, "\tother write =\t%#8.8o\n", 02);
(void) fprintf(stderr, "Enter msgflg value: ");
(void) scanf("%i", &msgflg);
main()
{
struct msqid_ds buf; /* queue descriptor buffer for IPC_STAT
and IP_SET commands */
int cmd, /* command to be given to msgctl() */
msqid; /* queue ID to be given to msgctl() */
(void fprintf(stderr,
"All numeric input is expected to follow C conventions:\n");
(void) fprintf(stderr,
"\t0x... is interpreted as hexadecimal,\n");
(void) fprintf(stderr, "\t0... is interpreted as octal,\n");
(void) fprintf(stderr, "\totherwise, decimal.\n");
/* Get the msqid and cmd arguments for the msgctl() call. */
(void) fprintf(stderr,
"Please enter arguments for msgctls() as requested.");
(void) fprintf(stderr, "\nEnter the msqid: ");
(void) scanf("%i", &msqid);
(void) fprintf(stderr, "\tIPC_RMID = %d\n", IPC_RMID);
(void) fprintf(stderr, "\tIPC_SET = %d\n", IPC_SET);
(void) fprintf(stderr, "\tIPC_STAT = %d\n", IPC_STAT);
(void) fprintf(stderr, "\nEnter the value for the command: ");
(void) scanf("%i", &cmd);
switch (cmd) {
case IPC_SET:
/* Modify settings in the message queue control structure.
*/
(void) fprintf(stderr, "Before IPC_SET, get current
values:");
/* fall through to IPC_STAT processing */
case IPC_STAT:
/* Get a copy of the current message queue control
* structure and show it to the user. */
do_msgctl(msqid, IPC_STAT, &buf);
(void) fprintf(stderr, ]
"msg_perm.uid = %d\n", buf.msg_perm.uid);
(void) fprintf(stderr,
"msg_perm.gid = %d\n", buf.msg_perm.gid);
(void) fprintf(stderr,
"msg_perm.cuid = %d\n", buf.msg_perm.cuid);
(void) fprintf(stderr,
"msg_perm.cgid = %d\n", buf.msg_perm.cgid);
(void) fprintf(stderr, "msg_perm.mode = %#o, ",
buf.msg_perm.mode);
(void) fprintf(stderr, "access permissions = %#o\n",
buf.msg_perm.mode & 0777);
(void) fprintf(stderr, "msg_cbytes = %d\n",
buf.msg_cbytes);
(void) fprintf(stderr, "msg_qbytes = %d\n",
buf.msg_qbytes);
(void) fprintf(stderr, "msg_qnum = %d\n", buf.msg_qnum);
(void) fprintf(stderr, "msg_lspid = %d\n",
buf.msg_lspid);
(void) fprintf(stderr, "msg_lrpid = %d\n",
buf.msg_lrpid);
(void) fprintf(stderr, "msg_stime = %s", buf.msg_stime ?
ctime(&buf.msg_stime) : "Not Set\n");
(void) fprintf(stderr, "msg_rtime = %s", buf.msg_rtime ?
ctime(&buf.msg_rtime) : "Not Set\n");
(void) fprintf(stderr, "msg_ctime = %s",
ctime(&buf.msg_ctime));
if (cmd == IPC_STAT)
break;
/* Now continue with IPC_SET. */
(void) fprintf(stderr, "Enter msg_perm.uid: ");
(void) scanf ("%hi", &buf.msg_perm.uid);
(void) fprintf(stderr, "Enter msg_perm.gid: ");
(void) scanf("%hi", &buf.msg_perm.gid);
(void) fprintf(stderr, "%s\n", warning_message);
(void) fprintf(stderr, "Enter msg_perm.mode: ");
(void) scanf("%hi", &buf.msg_perm.mode);
(void) fprintf(stderr, "Enter msg_qbytes: ");
(void) scanf("%hi", &buf.msg_qbytes);
do_msgctl(msqid, IPC_SET, &buf);
break;
case IPC_RMID:
default:
/* Remove the message queue or try an unknown command. */
do_msgctl(msqid, cmd, (struct msqid_ds *)NULL);
break;
}
exit(0);
}
/*
* Print indication of arguments being passed to msgctl(), call
* msgctl(), and report the results. If msgctl() fails, do not
* return; this example doesn't deal with errors, it just reports
* them.
*/
static void
do_msgctl(msqid, cmd, buf)
struct msqid_ds *buf; /* pointer to queue descriptor buffer */
int cmd, /* command code */
msqid; /* queue ID */
{
register int rtrn; /* hold area for return value from msgctl()
*/
#include <stdio.h>
This header file contains declarations used in most input and output and is typically
included in all C programs.
#include <sys/types.h>
This header file contains definitions of a number of data types used in system calls. These
types are used in the next two include files.
#include <sys/socket.h>
The header file socket.h includes a number of definitions of structures needed for sockets.
#include <netinet/in.h>
The header file netinet/in.h contains constants and structures needed for internet domain
addresses.
char buffer[256];
The server reads characters from the socket connection into this buffer.
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
The user needs to pass in the port number on which the server will accept connections as
an argument. This code displays an error message if the user fails to do this.
portno = atoi(argv[1]);
The port number on which the server will listen for connections is passed in as an
argument, and this statement uses the atoi() function to convert this from a string of digits
to an integer.
serv_addr.sin_family = AF_INET;
The variable serv_addr is a structure of type struct sockaddr_in. This structure has four
fields. The first field is short sin_family, which contains a code for the address family. It
should always be set to the symbolic constant AF_INET.
serv_addr.sin_port = htons(portno);
The second field of serv_addr is unsigned short sin_port , which contain the port number.
However, instead of simply copying the port number to this field, it is necessary to
convert this to network byte order using the function htons() which converts a port
number in host byte order to a port number in network byte order.
serv_addr.sin_addr.s_addr = INADDR_ANY;
The third field of sockaddr_in is a structure of type struct in_addr which contains only a
single field unsigned long s_addr. This field contains the IP address of the host. For
server code, this will always be the IP address of the machine on which the server is
running, and there is a symbolic constant INADDR_ANY which gets this address.
listen(sockfd,5);
The listen system call allows the process to listen on the socket for connections. The first
argument is the socket file descriptor, and the second is the size of the backlog queue,
i.e., the number of connections that can be waiting while the process is handling a
particular connection. This should be set to 5, the maximum size permitted by most
systems. If the first argument is a valid socket, this call cannot fail, and so the code
doesn't check for errors. The listen() man page has more information.
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
The accept() system call causes the process to block until a client connects to the server.
Thus, it wakes up the process when a connection from a client has been successfully
established. It returns a new file descriptor, and all communication on this connection
should be done using the new file descriptor. The second argument is a reference pointer
to the address of the client on the other end of the connection, and the third argument is
the size of this structure. The accept() man page has more information.
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
Note that we would only get to this point after a client has successfully connected to our
server. This code initializes the buffer using the bzero() function, and then reads from the
socket. Note that the read call uses the new file descriptor, the one returned by accept(),
not the original file descriptor returned by socket(). Note also that the read() will block
until there is something for it to read in the socket, i.e. after the client has executed a
write(). It will read either the total number of characters in the socket or 255, whichever
is less, and return the number of characters read. The read() man page has more
information.
return 0;
}
This terminates main and thus the program. Since main was declared to be of type int as
specified by the ascii standard, some compilers complain if it does not return anything.
Client code
As before, we will go through the program client.c line by line.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
The header files are the same as for the server with one addition. The file netdb.h defines
the structure hostent, which will be used below.
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
All of this code is the same as that in the server.
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
argv[1] contains the name of a host on the Internet, e.g. [email protected]. The
function:
struct hostent *gethostbyname(char *name)
Takes such a name as an argument and returns a pointer to a hostent containing
information about that host. The field char *h_addr contains the IP address. If this
structure is NULL, the system could not locate a host with this name.
In the old days, this function worked by searching a system file called /etc/hosts but with
the explosive growth of the Internet, it became impossible for system administrators to
keep this file current. Thus, the mechanism by which this function works is complex,
often involves querying large databases all around the country. The gethostbyname() man
page has more information.
if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
The connect function is called by the client to establish a connection to the server. It takes
three arguments, the socket file descriptor, the address of the host to which it wants to
connect (including the port number), and the size of this address. This function returns 0
on success and -1 if it fails. The connect() man page has more information.
Notice that the client needs to know the port number of the server, but it does not need to
know its own port number. This is typically assigned by the system when connect is
called.
When a monitored event occurs, the traced program is stopped and a SIGCHLD signal is
sent to its parent. When the parent wishes to resume the child‘s execution. T can use one
of the PTRACE_CONT
A process can also be traced using some debugging features of the intel
processors. For example: the parent could set the value of the dr0 . . . dr7 debug registers.
The cpu raises the ―debug‖ exception: the exception handler can then suspend the traced
process and send the SIGCHLD signal to the parent.
Unit7:
HAL:
The greatest contributions of the Industrial Revolution were standardization and
interchangeable parts. Open software and the APIs it embodies certainly capture the spirit
of outward standardization, but the same can‘t be said for parts inside the box. Linux, for
all its flexibility and portability, still feels like a flintlock factory when it comes to
retargeting it across new systems, boards, and CPUs.In contrast, the BSP is solidly
industrial. Twenty years ago, the BSP, which stands for Board Support Package, was
coined to describe the abstraction of hardware dependencies in an embedded OS. More
recent TLAs—three-letter acronyms—like HAL and OAL (Hardware and OEM
Abstraction Layers) have joined BSP in the acronym hall of fame, but BSP in pervasive
computing has stuck. Developers, partners, sales people, all call our company regularly to
check on ―BSP availability.‖ A HAL, when implemented well, allows an OS to
generalize many of the particulars of a system‘s CPU, cache, MMU/TLBs, serial ports,
NICs, display device, interrupt controller, memory map, etc., both to allow the OS to
focus on ―big issues‖ and to facilitate porting to new hardware configurations.
The existence of Ready Systems‘ and Wind River‘s BSP/HAL specifications eased the
migration of the VRTX and VxWorks kernels onto literally thousands of boards with
dozens of architectures; the WindowsCE OAL helped Microsoft target over a hundred
boards with dozens of different CPUs in a very short time.
So, why doesn‘t Linux have a HAL? I can tell you the answer in one word – Tradition.
The Linux kernel emanates from kernel.org, which essentially produces a white box OS,
supporting x86/IA-32 compatible CPUs. With that Wintel architecture, things like code
compatibility, BIOS, and chipsets come together to form what I call the PC/AT ―virtual
machine.‖ Linux, like Windows, leverages basic knowledge about this platform, so that
booting and hardware initialization are taken care of, leaving a kernel to worry about the
more interesting things. As one hacker says, ―on x86, it just works!‖
Linux does have a HAL – it‘s the PC. Pervasive computing is not about the ubiquity of
the PC. Architectures other than x86/IA-32, like PowerPC, ARM, MIPS, and
SuperHitachi, dominate the space and each presents its own take on hardware
configuration, while none offers a broadly accepted set of hardware support conventions.
Some abstraction work is indeed under way. As each Linux architecture tree matures,
conventions arise through the magic of Open Source cooperation. The PowerPC tree is a
case in point. The PowerPC CPU family, while binary-compatible for user-space
applications, diverges vastly among members in terms of MMU, cache, floating point,
breakpoint registers, and with Book E, new instructions, and PowerPC boards present
over half a dozen boot monitors.
Porting to new PowerPC hardware might still not be for the faint of heart, but agreed-
upon abstractions have matured to the point that new boards can be added to the corpus
of supported systems with modifications to as few as three files. Now, the MIPS folks are
talking to the PowerPC maintainers and appear to be headed in the same direction.
While these grass-roots efforts represent the best of Open Source, fragmentation across
architectures, which still abounds, cannot be good for Linux overall. The current
prediction is that Linux will truly triumph in embedded where it has not done so on the
desktop. That means the Community needs to get together with both bottom-up and top-
down initiatives to accelerate quick and easy porting to new hardware
POSIX:
What is POSIX®? POSIX is the Portable Operating System Interface, the open operating
interface standard accepted world-wide. It is produced by IEEE and recognized by ISO
and ANSI.
POSIX support assures code portability between systems and is increasingly mandated
for commercial applications and government contracts. For instance, the USA's Joint
Technical Architecture—Army (JTA-A) standards set specifies that conformance to the
POSIX specification is critical to support software interoperability.
POSIX conformance is worth more than POSIX compliance
POSIX conformance is what real-time embedded developers are usually looking for.
POSIX conformance means that the POSIX.1 standard is supported in its entirety. In the
case of the LynxOS real-time operating system, the routines of the POSIX.1b and
POSIX.1c subsets are also supported.
Certified POSIX conformance exists when conformance is certified by an accredited,
independent certification authority. For example, LynxOS has been certified conformant
to POSIX 1003.1-1996 by Mindcraft, Inc. and tested against FIPS 151-2 (Federal
Information Processing Standard).
POSIX compliance is a less powerful label, and could merely mean that a product
provides partial POSIX support. "POSIX compliance" means that documentation is
available that shows which POSIX features are supported and which are not.
Be wary of claims like POSIX operating system or 95% POSIX, which do not
specify POSIX conformance.
Remember that POSIX compliance does not always mean that all POSIX-defined
features are supported.
Different Kernel Designs Overview:
Kernel terminology gets tossed about quite a bit. One of the more common topics
regarding operating system kernels is the overall design. In particular how the kernel is
structured. Generally, there are three major types of kernels; monolithic, microkernel and
hybrid/modular.
Monolithic
A monolithic kernel is one single program that contains all of the code necessary to
perform every kernel related task. Most UNIX and BSD kernels are monolithic by
default. Recently more UNIX and BSD systems have been adding the modular capability
which is popular in the Linux kernel. The Linux kernel started off monolithic, however, it
gravitated towards a modular/hybrid design for several reasons. In the monolithic kernel,
some advantages hinge on these points:
Those points are dependent upon how well the software is written in the first place. It can
be assumed that a stable kernel that has modular capability added to it will, of course,
grow both in raw software terms and regarding internal communications.
Most work in the monolithic kernel is done via system calls. These are interfaces, usually
kept in a tabular structure, that access some subsystem within the kernel such as disk
operations. Essentially calls are made within programs and a checked copy of the request
is passed through the system call. Hence, not far to travel at all.
The disadvantages of the monolithic kernel are converse with the advantages. Modifying
and testing monolithic systems takes longer than their microkernel counterparts. When a
bug surfaces within the core of the kernel the effects can be far reaching. Also, patching
monolithic systems can be more difficult (especially for source patching).
Microkernel
The microkernel architecture is very different from the monolithic. In the microkernel,
only the most fundamental of tasks are are performed such as being able to access some
(not necessarily all) of the hardware, manage memory and coordinate message passing
between the processes. Some systems that use microkernels are QNX and the HURD. In
the case of QNX and HURD, user sessions can be entire snapshots of the system itself or
views as it is referred to. The very essence of the microkernel architecture illustrates
some of its advantages:
Maintenance is generally easier. Patches can be tested in a separate instance, then
swapped in to take over a production instance.
Rapid development time, new software can be tested without having to reboot the
kernel.
More persistence in general, if one instance goes hay-wire, it is often possible to
substitute it with an operational mirror.
Again, all of the points are making certain assumptions about the code itself. Assuming
the code is well formed, those points should stand reasonably well.
Most microkernels use a message passing system of some sort to handle requests from
one server to another. The message passing system generally operates on a port basis
with the microkernel. As an example, if a request for more memory is sent, a port is
opened with the microkernel and the request sent through. Once within the microkernel,
the steps are similar to system calls.
The disadvantages for microkernels are extremely context based. As an example, they
work well for small single purpose (and critical) systems because if not many processes
need to run, then the complications of process management are effectively mitigated.
Modular/Hybrid Kernels
Many traditionally monolithic kernels are now at least adding (if not actively exploiting)
the module capability. The most well known of these kernels is the Linux kernel. The
modular kernel essentially can have parts of it that are built into the core kernel binary or
binaries that load into memory on demand. It is important to note that a code tainted
module has the potential to destabilize a running kernel. Many people become confused
on this point when discussing microkernels. It is possible to write a driver for a
microkernel in a completely separate memory space and test it before going live. When a
kernel module is loaded, it accesses the monolithic portion's memory space by adding to
it what it needs, therefore, opening the doorway to possible pollution. A few advantages
to the modular kernel are:
Faster development time for drivers that can operate from within modules. No
reboot required for testing (provided the kernel is not destabilized).
On demand capability versus spending time recompiling a whole kernel for things
like new drivers or subsystems.
Faster integration of third party technology (related to development but pertinent
unto itself nonetheless).
Modules, generally, communicate with the kernel using a module interface of some sort.
The interface is generalized (although particular to a given operating system) so it is not
always possible to use modules. Often the device drivers may need more flexibility than
the module interface affords. Essentially, it is two system calls and often the safety
checks that only have to be done once in the monolithic kernel now may be done twice.
With more interfaces to pass through, the possibility of increased bugs exists
(which implies more security holes).
Maintaining modules can be confusing for some administrators when dealing with
problems like symbol differences.
Booting process:
1. BIOS: The Basic Input/Output System is the lowest level interface between the
computer and peripherals. The BIOS performs integrity checks on memory and
seeks instructions on the Master Boor Record (MBR) on the floppy drive or hard
drive.
2. The MBR points to the boot loader (GRUB or LILO: Linux boot loader).
3. Boot loader (GRUB or LILO) will then ask for the OS label which will identify
which kernel to run and where it is located (hard drive and partition specified).
The installation process requires to creation/identification of partitions and where
to install the OS. GRUB/LILO are also configured during this process. The boot
loader then loads the Linux operating system.
o See the YoLinux tutorial on creating a boot disk for more information on
GRUB and LILO and also to learn how to put the MBR and boot loader
on a floppy for system recovery.
4. The first thing the kernel does is to execute init program. Init is the root/parent
of all processes executing on Linux.
5. The first processes that init starts is a script /etc/rc.d/rc.sysinit
Boot Script works as:
Run /sbin/initlog
Run devfs to generate/manage system devices
Run network scripts: /etc/sysconfig/network
Start graphical boot (If so configured): rhgb
Start console terminals, load keymap, system fonts and print console greeting:
mingetty, setsysfonts
The various virtual console sessions can be viewed with the key-stroke: ctrl-
alt-F1 through F6. F7 is reserved for the GUI screen invoked in run level 5.
Mount /proc and start device controllers.
Done with boot configuration for root drive. (initrd) Unmount root drive.
Re-mount root file system as read/write
Direct kernel to load kernel parameters and modules: sysctl, depmod, modprobe
Set up clock: /etc/sysconfig/clock
Perform disk operations based on fsck configuration
Check/mount/check/enable quotas non-root file systems: fsck, mount, quotacheck,
quotaon
Initialize logical volume management: vgscan, /etc/lvmtab
Activate syslog, write to log files: dmesg
Configure sound: sndconfig
Activate PAM
Active swqpping: swapon
More details on booting process:
The process of booting a Linux® system consists of a number of stages. But whether
you're booting a standard x86 desktop or a deeply embedded PowerPC® target, much of
the flow is surprisingly similar. This article explores the Linux boot process from the
initial bootstrap to the start of the first user-space application. Along the way, you'll learn
about various other boot-related topics such as the boot loaders, kernel decompression,
the initial RAM disk, and other elements of Linux boot.
In the early days, bootstrapping a computer meant feeding a paper tape containing a boot
program or manually loading a boot program using the front panel address/data/control
switches. Today's computers are equipped with facilities to simplify the boot process, but
that doesn't necessarily make it simple.
Let's start with a high-level view of Linux boot so you can see the entire landscape. Then
we'll review what's going on at each of the individual steps. Source references along the
way will help you navigate the kernel tree and dig in further.
Overview
Figure 1 gives you the 20,000-foot view.
When a system is first booted, or is reset, the processor executes code at a well-known
location. In a personal computer (PC), this location is in the basic input/output system
(BIOS), which is stored in flash memory on the motherboard. The central processing unit
(CPU) in an embedded system invokes the reset vector to start a program at a known
address in flash/ROM. In either case, the result is the same. Because PCs offer so much
flexibility, the BIOS must determine which devices are candidates for boot. We'll look at
this in more detail later.
When a boot device is found, the first-stage boot loader is loaded into RAM and
executed. This boot loader is less than 512 bytes in length (a single sector), and its job is
to load the second-stage boot loader.
When the second-stage boot loader is in RAM and executing, a splash screen is
commonly displayed, and Linux and an optional initial RAM disk (temporary root file
system) are loaded into memory. When the images are loaded, the second-stage boot
loader passes control to the kernel image and the kernel is decompressed and initialized.
At this stage, the second-stage boot loader checks the system hardware, enumerates the
attached hardware devices, mounts the root device, and then loads the necessary kernel
modules. When complete, the first user-space program (init) starts, and high-level system
initialization is performed.
That's Linux boot in a nutshell. Now let's dig in a little further and explore some of the
details of the Linux boot process.
System startup
The system startup stage depends on the hardware that Linux is being booted on. On an
embedded platform, a bootstrap environment is used when the system is powered on, or
reset. Examples include U-Boot, RedBoot, and MicroMonitor from Lucent. Embedded
platforms are commonly shipped with a boot monitor. These programs reside in special
region of flash memory on the target hardware and provide the means to download a
Linux kernel image into flash memory and subsequently execute it. In addition to having
the ability to store and boot a Linux image, these boot monitors perform some level of
system test and hardware initialization. In an embedded target, these boot monitors
commonly cover both the first- and second-stage
boot loaders. Extracting the MBR
In a PC, booting Linux begins in the BIOS at address To see the contents of your
0xFFFF0. The first step of the BIOS is the power-on MBR, use this command:
self test (POST). The job of the POST is to perform # dd if=/dev/hda of=mbr.bin
a check of the hardware. The second step of the bs=512 count=1
BIOS is local device enumeration and initialization. # od -xa mbr.bin
Given the different uses of BIOS functions, the The dd command, which needs
BIOS is made up of two parts: the POST code and to be run from root, reads the
runtime services. After the POST is complete, it is first 512 bytes from /dev/hda
flushed from memory, but the BIOS runtime services (the first Integrated Drive
remain and are available to the target operating Electronics, or IDE drive) and
system. writes them to the mbr.bin file.
To boot an operating system, the BIOS runtime The od command prints the
searches for devices that are both active and bootable binary file in hex and ASCII
in the order of preference defined by the formats.
complementary metal oxide semiconductor (CMOS)
settings. A boot device can be a floppy disk, a CD-ROM, a partition on a hard disk, a
device on the network, or even a USB flash memory stick.
Commonly, Linux is booted from a hard disk, where the Master Boot Record (MBR)
contains the primary boot loader. The MBR is a 512-byte sector, located in the first sector
on the disk (sector 1 of cylinder 0, head 0). After the MBR is loaded into RAM, the BIOS
yields control to it.
Stage 1 boot loader
The primary boot loader that resides in the MBR is a 512-byte image containing both
program code and a small partition table (see Figure 2). The first 446 bytes are the
primary boot loader, which contains both executable code and error message text. The
next sixty-four bytes are the partition table, which contains a record for each of four
partitions (sixteen bytes each). The MBR ends with two bytes that are defined as the
magic number (0xAA55). The magic number serves as a validation check of the MBR.
The job of the primary boot loader is to find and load the secondary boot loader (stage 2).
It does this by looking through the partition table for an active partition. When it finds an
active partition, it scans the remaining partitions in the table to ensure that they're all
inactive. When this is verified, the active partition's boot record is read from the device
into RAM and executed.
Kernel
Manual boot in GRUB
From the GRUB command-
line, you can boot a specific
kernel with a named initrd
image as follows:
grub> kernel /bzImage-
2.6.14.2
[Linux-bzImage,
setup=0x1400,
size=0x29672e]
Figure 3. Major functions flow for the Linux kernel i386 boot
With the call to start_kernel, a long list of initialization functions are called to set up
interrupts, perform further memory configuration, and load the initial RAM disk. In the
end, a call is made to kernel_thread (in arch/i386/kernel/process.c) to start the init
function, which is the first user-space process. Finally, the idle task is started and the
scheduler can now take control (after the call to cpu_idle). With interrupts enabled, the
pre-emptive scheduler periodically takes control to provide multitasking.
During the boot of the kernel, the initial-RAM disk (initrd) that was loaded into memory
by the stage 2 boot loader is copied into RAM and mounted. This initrd serves as a
temporary root file system in RAM and allows the kernel to fully boot without having to
mount any physical disks. Since the necessary modules needed to interface with
peripherals can be part of the initrd, the kernel can be very small, but still support a large
number of possible hardware configurations. After the kernel is booted, the root file
system is pivoted (via pivot_root) where the initrd root file system is unmounted and the
real root file system is mounted.
The initrd function allows you to create a small decompress_kernel output
Linux kernel with drivers compiled as loadable The decompress_kernel
modules. These loadable modules give the kernel the function is where you see the
means to access disks and the file systems on those usual decompression messages
disks, as well as drivers for other hardware assets. emitted to the display:
Because the root file system is a file system on a
disk, the initrd function provides a means of Uncompressing Linux... Ok,
bootstrapping to gain access to the disk and mount booting the kernel.
the real root file system. In an embedded target
without a hard disk, the initrd can be the final root file system, or the final root file
system can be mounted via the Network File System (NFS).
Init
After the kernel is booted and initialized, the kernel starts the first user-space application.
This is the first program invoked that is compiled with the standard C library. Prior to this
point in the process, no standard C applications have been executed.
In a desktop Linux system, the first application started is commonly /sbin/init. But it need
not be. Rarely do embedded systems require the extensive initialization provided by init
(as configured through /etc/inittab). In many cases, you can invoke a simple shell script
that starts the necessary embedded applications.
Overview of Linux and compiling the kernel:
WHAT IS LINUX?
Linux is a clone of the operating system Unix, written from scratch by Linus Torvalds
with assistance from a loosely-knit team of hackers across the Net. It aims towards
POSIX and Single UNIX Specification compliance.
It has all the features you would expect in a modern fully-fledged Unix, including true
multitasking, virtual memory, shared libraries, demand loading, shared copy-on-write
executables, proper memory management, and multistack networking including IPv4 and
IPv6. It is distributed under the GNU General Public License - see the
accompanying COPYING file for more details.
DOCUMENTATION:
- There is a lot of documentation available both in electronic form on the Internet and in
books, both Linux-specific and pertaining to general UNIX questions. I'd recommend
looking into the documentation subdirectories on any Linux FTP site for the LDP (Linux
Documentation Project) books. This README is not meant to be documentation on the
system: there are much better sources available.
- There are various README files in the Documentation/ subdirectory: these typically
contain kernel-specific installation notes for some drivers for example. See
Documentation/00-INDEX for a list of what is contained in each file. Please read the
Changes file, as it contains information about the problems, which may result by
upgrading your kernel.
- You can also upgrade between 2.6.xx releases by patching. Patches are distributed in
the traditional gzip and the newer bzip2 format. To install by patching, get all the newer
patch files, enter the top level directory of the kernel source (linux-2.6.xx) and execute:
gzip -cd ../patch-2.6.xx.gz | patch -p1
or
bzip2 -dc ../patch-2.6.xx.bz2 | patch -p1
(repeat xx for all versions bigger than the version of your current source tree,
_in_order_) and you should be ok. You may want to remove the backup files (xxx~ or
xxx.orig), and make sure that there are no failed patches (xxx# or xxx.rej). If there are,
either you or me has made a mistake.
Unlike patches for the 2.6.x kernels, patches for the 2.6.x.y kernels (also known as the -
stable kernels) are not incremental but instead apply directly to the base 2.6.x kernel.
Please read Documentation/applying-patches.txt for more information.
Alternatively, the script patch-kernel can be used to automate this process. It
determines the current kernel version and applies any patches found.
linux/scripts/patch-kernel linux
The first argument in the command above is the location of the kernel source. Patches
are applied from the current directory, but an alternative directory can be specified as the
second argument.
- If you are upgrading between releases using the stable series patches (for example,
patch-2.6.xx.y), note that these "dot-releases" are not incremental and must be applied to
the 2.6.xx base tree. For example, if your base kernel is 2.6.12 and you want to apply
the 2.6.12.3 patch, you do not and indeed must not first apply the 2.6.12.1 and 2.6.12.2
patches. Similarly, if you are running kernel version 2.6.12.2 and want to jump to
2.6.12.3, you must first reverse the 2.6.12.2 patch (that is, patch -R) _before_ applying
the 2.6.12.3 patch. You can read more on this in Documentation/applying-patches.txt
- Make sure you have no stale .o files and dependencies lying around:
cd linux
make mrproper
You should now have the sources correctly installed.
SOFTWARE REQUIREMENTS
Compiling and running the 2.6.xx kernels requires up-to-date versions of various
software packages. Consult Documentation/Changes for the minimum version numbers
required and how to get updates for these packages. Beware that using excessively old
versions of these packages can cause indirect errors that are very difficult to track down,
so don't assume that you can just update packages when obvious problems arise during
build or operation.
When compiling the kernel all output files will per default be stored together with the
kernel source code. Using the option "make O=output/dir" allow you to specify an
alternate place for the output files (including .config).
Example:
kernel source code: /usr/src/linux-2.6.N
build directory: /home/name/build/kernel
Please note: If the 'O=output/dir' option is used then it must be used for all invocations of
make.
Do not skip this step even if you are only upgrading one minor version. New
configuration options are added in each release, and odd problems will turn up if the
configuration files are not set up as expected. If you want to carry your existing
configuration to a new version with minimal work, use "make oldconfig", which will
only ask you for the answers to new questions.
- Make sure you have at least gcc 3.2 available. For more information, refer to
Documentation/Changes. Please note that you can still run a.out user programs with this
kernel.
- If you configured any of the parts of the kernel as `modules', you will also have to do
"make modules_install".
- Keep a backup kernel handy in case something goes wrong. This is especially true for
the development releases, since each new release contains new code which has not been
debugged. Make sure you keep a backup of the modules corresponding to that kernel, as
well. If you are installing a new kernel with the same version number as your working
kernel, make a backup of your modules directory before you do a "make
modules_install". Alternatively, before compiling, use the kernel config option
"LOCALVERSION" to append a unique suffix to the regular kernel version.
LOCALVERSION can be set in the "General Setup" menu.
- In order to boot your new kernel, you'll need to copy the kernel image (e.g.
.../linux/arch/i386/boot/bzImage after compilation) to the place where your regular
bootable kernel is found.
- Booting a kernel directly from a floppy without the assistance of a bootloader such as
LILO, is no longer supported.
If you boot Linux from the hard drive, chances are you use LILO which uses the
kernel image as specified in the file /etc/lilo.conf. The kernel image file is usually
/vmlinuz, /boot/vmlinuz, /bzImage or /boot/bzImage. To use the new kernel, save a
copy of the old image and copy the new image over the old one. Then, you MUST
RERUN LILO to update the loading map!! If you don't, you won't be able to boot the
new kernel image.
Reinstalling LILO is usually a matter of running /sbin/lilo. You may wish to edit
/etc/lilo.conf to specify an entry for your old kernel image (say, /vmlinux.old) in case the
new one does not work. See the LILO docs for more information.
After reinstalling LILO, you should be all set. Shutdown the system, reboot, and
enjoy!
If you ever need to change the default root device, video mode, ramdisk size, etc. in
the kernel image, use the 'rdev' program (or alternatively the LILO boot options when
appropriate). No need to recompile the kernel to change these parameters.
- Reboot with the new kernel and enjoy.
- If you have problems that seem to be due to kernel bugs, please check the file
MAINTAINERS to see if there is a particular person associated with the part of the
kernel that you are having trouble with. If there isn't anyone listed there, then the second
best thing is to mail them to me ([email protected]), and possibly to any
other relevant mailing-list or to the newsgroup.
- In all bug-reports, *please* tell what kernel you are talking about, how to duplicate the
problem, and what your setup is (use your common sense). If the problem is new, tell
me so, and if the problem is old, please try to tell me when you first noticed it.
or similar kernel debugging information on your screen or in your system log, please
duplicate it *exactly*. The dump may look incomprehensible to you, but it does contain
information that may help debugging the problem. The text above the dump is also
important: it tells something about why the kernel dumped code (in the above example
it's due to a bad kernel pointer). More information on making sense of the dump is in
Documentation/oops-tracing.txt
- If you compiled the kernel with CONFIG_KALLSYMS you can send the dump
as is, otherwise you will have to use the "ksymoops" program to make sense of the
dump (but compiling with CONFIG_KALLSYMS is usually preferred). This utility can
be downloaded from ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops/ .
Alternately you can do the dump lookup by hand:
- In debugging dumps like the above, it helps enormously if you can look up what the
EIP value means. The hex value as such doesn't help me or anybody else very much: it
will depend on your particular kernel setup. What you should do is take the hex value
from the EIP line (ignore the "0010:"), and look it up in the kernel namelist to see which
kernel function contains the offending address.
To find out the kernel function name, you'll need to find the system binary associated
with the kernel that exhibited the symptom. This is the file 'linux/vmlinux'. To extract
the namelist and match it against the EIP from the kernel crash, do:
nm vmlinux | sort | less
This will give you a list of kernel addresses sorted in ascending order, from which it is
simple to find the function that contains the offending address. Note that the address
given by the kernel debugging messages will not necessarily match exactly with the
function addresses (in fact, that is very unlikely), so you can't just 'grep' the list: the list
will, however, give you the starting point of each kernel function, so by looking for the
function that has a starting address lower than the one you are searching for but is
followed by a function with a higher address you will find the one you want. In fact, it
may be a good idea to include a bit of "context" in your problem report, giving a few
lines around the interesting one.
If you for some reason cannot do the above (you have a pre-compiled kernel image or
similar), telling me as much about your setup as possible will help. Please read the
REPORTING-BUGS document for details.
- Alternately, you can use gdb on a running kernel. (read-only; i.e. you cannot change
values or set break points.) To do this, first compile the kernel with -g; edit
arch/i386/Makefile appropriately, then do a "make clean". You'll also need to enable
CONFIG_PROC_FS (via "make config").
After you've rebooted with the new kernel, do "gdb vmlinux /proc/kcore". You can
now use all the usual gdb commands. The command to look up the point where your
system crashed is "l *0xXXXXXXXX". (Replace the XXXes with the EIP value.)
gdb'ing a non-running kernel currently fails because gdb (wrongly) disregards the
starting offset for which the kernel is compiled.
Unit8:
3. a) write a program via sockets where client send a number to server and server
returns its square(6)
b) i) demonstrate the use of pipes and fifo in a programs(6)
ii) write difference b/w pipe and fifo
4. explain multiprocessing(12.5)
5. a. what are modules(6)
b. what is debugging. explain GDB or SDB(1/2 + 6)
6. a. name any five file systems and explain any one file system(6)
b. name any six editors and explain any one (6.5)
7. explain booting process of Linux(12.5)
8. give answers
a. write name of different environment variables (1.5)
b. what is HAL(1.5)
c. what is POSIX(1.5)
d. what is IPC and race condition(2)
e. explain concept of virtual address space(6)
9. give answers
a. explain static and dynamic allocation(2.5)
b. why cat and ls commands are used(2)
c. what are – dd,uucp,gunzip,gzip,tar,wc,tty,echo,rm,mv(5)
d. what is lp command(1)
e. what is man command(1)
f. what are internal and external commands(1)
Model test paper 3:
1. explain(12.5)
shutdown,mount,unmount,mv,nice,kmalloc,bc,cal,cmp,comm.,whereis,zcat,zless,f
ind,pause,wait4,access,diff,fsck,in,ni,pwd,su,tee,uniq
2. i. write shell scripts(10)
a. to find factorial
b. to check prime/not
c. to display table
d. to copy two files into third file
e. take a number and show corresponding month
ii. what is memory and i/o symmetry(2.5)
3. answer
a. what is proc,explain(4)
b. write difference b/w proc and ext2(2)
c. what are modules(2.5)
d. explain structure of inode,superblock and their operations(4)
4. explain
a. explain process management(4)
b. explain system calls(4.5)
c. explain multiprocessing(4)
5. write c programs
a. to demonstrate the use of shared memory(3)
b. msg queue(3)
c. write client server program using sockets(4.5)
d. explain why pipe mechanisms is not efficient in client server
application.(2)
6. write short note on system administration
7. what is architecture independent memory model
8. explain various data structures in Linux kernel
9. what are various IPC mechanisms and explain semaphores and explain use of
semaphores in c program.
Unit9:
Millennium year recommends to solve all question given in this unit to get good marks
MY Linux entrance 2007 (theory)
1) answer
a. linux is compatible with _____________ standard.
b. Linux born in _____________
c. Linux is still a__________- bit os
d. In ext2, file name length can be of________________-
e. ______________-fn, is I c fn. Called in booting of Linux
f. loof _t structure use for ________________
g. max_thread can be altered by ___________ interface
h. what is query_module
i. what is gdb
j. APIC stands for
2) explain any 10 features of Linux
3) explain any 20 commands
4) explain memory management
5) explain
a. all six data structure in Linux(6)
b. system administration(2)
c. process management(2)
6) explain
a. representation of file system in kernel with atleast of six structures(3)
b. explain proc and ext2 and write difference b/w ntfs and ext2(4)
c. explain any six system calls(3)
7) explain
a. all ipc mechanisms with c examples(8)
b. synchronization in kernel(2)
8) write short note on(10)
a. HAL
b. Compiling kernel
c. POSIX
d. Different types of kernel
e. Booting up of linux
MY Linux entrance 2007 (practical)
1 answers :
a) POSIX-1003.1
b) 1991
c) 32
d) 255
e) start_kernel()
f) telling f_pos
g) sysctl
j) Advance Programmable Interrupt controller
Practical:
19: check if it is a folder, then move inside and delete files and then folder
for file in *
do
if [ -d $file ] ; then
cd $file
rm *
cd ..
rm *
else
rm *
done
20. echo
$ SHELL
$ USERNAME
$ PATH
$ LOGNAME
$ OSTYPE
$ COLUMNS
$ HOME
$ LINES
$ BASH_VERSION
Unit10:
Example1: write a shell script to read name, grade, basic salary and display it
#!/bin/sh
echo ―enter name:‖
read name
echo ―enter grade:‖
read gd
echo ―enter basic salary:‖
read bs
echo ―name: $name, grade: $grade, bs=$bs‖
exit 0