Search in shivacherukuri.tech@blogger.com

Thursday, December 16, 2010

: http://www.pixelbeat.org/cmdline.html linux cmdline commands

 

 

: http://www.pixelbeat.org/cmdline.html linux cmdline commands

 

 

This is a list of linux commands for common operations.
Note items marked with • are valid/safe to paste without modification into a terminal, so
you may want to keep a terminal window open while reading this so you can cut & paste.

 

Command

Description

apropos word

Show commands pertinent to word. See also threadsafe

 

which command

Show full path name of command

 

time command

See how long a command takes

time cat

Start stopwatch. Ctrl-d to stop. See also sw

nice info

Run a low priority command (info in this case)

renice 19 -p $$

Make shell (script) low priority. Use for non interactive tasks

look prefix

Quickly search (sorted) dictionary

grep --color expr...ion /usr/share/dict/words

Highlight occurances of regular expression in dictionary

 

gpg -c file

Encrypt file

 

gpg file.gpg

Decrypt file

alias hd='od -Ax -tx1z -v'

Handy hexdump. (usage e.g.: • hd /proc/self/cmdline | less)

alias realpath='readlink -f'

Canonicalize path. (usage e.g.: • realpath ~/../$USER)

set | grep $USER

Search current environment

ls /usr/bin | pr -T9 -W$COLUMNS

Print in 9 columns to width of terminal

 

touch -c -t 0304050607 file

Set file timestamp (YYMMDDhhmm)

dir navigation

cd -

Go to previous directory

cd

Go to home directory

 

(cd dir && command)

Go to dir, execute command and return to current dir

pushd .

Put current dir on stack so you can popd back to it

CDs

 

gzip < /dev/cdrom > cdrom.iso.gz

Save copy of data cdrom

 

mkisofs -V NAME -r dir | gzip > cdrom.iso.gz

Create cdrom image from contents of dir

 

mount -o loop cdrom.iso /mnt/dir

Mount the cdrom image at /mnt/dir (read only)

 

cdrecord -v dev=/dev/cdrom blank=fast

Clear a CDRW

 

gzip -dc cdrom.iso.gz | cdrecord -v dev=/dev/cdrom -

Burn cdrom image (use dev=ATAPI -scanbus to confirm dev)

 

cdparanoia -B

Rip audio tracks from CD to wav files in current dir

 

cdrecord -v dev=/dev/cdrom -audio *.wav

Make audio CD from all wavs in current dir (see also cdrdao)

 

oggenc --tracknum='track' track.cdda.wav -o 'track.ogg'

Make ogg file from wav file

archives

 

tar c dir/ | bzip2 > dir.tar.bz2

Make archive of dir/

 

bzip2 -dc dir.tar.bz2 | tar x

Extract archive (use gzip instead of bzip2 for tar.gz files)

 

tar c dir/ | gzip | gpg -c | ssh user@remote 'dd of=dir.tar.gz.gpg'

Make encrypted archive of dir/ on remote machine

 

find dir/ -name '*.txt' | tar c --files-from=- | bzip2 > dir_txt.tar.bz2

Make archive of subset of dir/ and below

 

find dir/ -name '*.txt' | xargs cp -a --target-directory=dir_txt/ --parents

Make copy of subset of dir/ and below

 

( tar c /dir/to/copy ) | ( cd /where/to/ && tar x -p )

Copy (with permissions) copy/ dir to /where/to/ dir

 

( cd /dir/to/copy && tar c . ) | ( cd /where/to/ && tar x -p )

Copy (with permissions) contents of copy/ dir to /where/to/

 

( tar c /dir/to/copy ) | ssh -C user@remote 'cd /where/to/ && tar x -p'

Copy (with permissions) copy/ dir to remote:/where/to/ dir

 

dd bs=1M if=/dev/hda | gzip | ssh user@remote 'dd of=hda.gz'

Backup harddisk to remote machine

rsync (Use the --dry-run option for testing)

 

rsync -P rsync://rsync.server.com/path/to/file file

Only get diffs. Do multiple times for troublesome downloads

 

rsync --bwlimit=1000 fromfile tofile

Locally copy with rate limit. It's like nice for I/O

 

rsync -az -e ssh --delete ~/public_html/ remote.com:'~/public_html'

Mirror web site (using compression and encryption)

 

rsync -auz -e ssh remote:/dir/ . && rsync -auz -e ssh . remote:/dir/

Synchronize current directory with remote one

alias l='ls -l --color=auto'

quick dir listing

ls -lrt

List files by date. See also newest

 

find -name '*.[ch]' | xargs grep -E 'expr'

Search 'expr' in this dir and below. See also findrepo

 

find -type f -print0 | xargs -r0 grep -F 'string'

Search all regular files for 'string' in this dir and below

 

find -maxdepth 1 -type f | xargs grep -F 'string'

Search all regular files for 'string' in this dir

 

find -maxdepth 1 -type d | while read dir; do echo $dir; echo cmd2; done

Process each item with multiple commands (in while loop)

find -type f ! -perm -444

Find files not readable by all (useful for web site)

find -type d ! -perm -111

Find dirs not accessible by all (useful for web site)

locate -r 'file[^/]*\.txt'

Search cached index for names. This re is like glob *file*.txt

networking (Note ifconfig, route, mii-tool, nslookup commands are obsolete)

ip link show

List interfaces

 

ethtool interface

List interface status

 

ip link set dev eth0 name wan

Rename eth0 to wan

 

ip addr add 1.2.3.4/24 brd + dev eth0

Add ip and mask(255.255.255.0)

 

ip link set dev interface up

Bring interface up (or down)

 

ip route add default via 1.2.3.254

Set default gateway to 1.2.3.254

tc qdisc add dev lo root handle 1:0 netem delay 20msec

Add 20ms latency to loopback device (for testing)

tc qdisc del dev lo root

Remove latency added above

host pixelbeat.org

Lookup ip address for name or vice versa

hostname -i

Lookup local ip address (equivalent to host `hostname`)

netstat -tupl

List internet services on a system

netstat -tup

List active connections to/from system

wget (multi purpose download tool)

(cd cmdline && wget -nd -pHEKk http://www.pixelbeat.org/cmdline.html)

Store local browsable version of a page to the current dir

 

wget -c http://www.example.com/large.file

Continue downloading a partially downloaded file

 

wget -r -nd -np -l1 -A '*.jpg' http://www.example.com/

Download a set of files to the current directory

 

wget ftp://remote/file[1-9].iso/

FTP supports globbing directly

wget -q -O- http://www.pixelbeat.org/timeline.html | grep 'a href' | head

Process output directly

 

echo 'wget url' | at 01:00

Download url at 1AM to current dir

 

wget --limit-rate=20k url

Do a low priority download (limit to 20KB/s in this case)

 

wget -nv --spider --force-html -i bookmarks.html

Check links in a file

 

wget --mirror http://www.example.com/

Efficiently update a local copy of a site (handy from cron)

windows (note samba is the package that provides all this windows specific networking support)

smbtree

Find windows machines. See also findsmb

 

nmblookup -A 1.2.3.4

Find the windows (netbios) name associated with ip address

 

smbclient -L windows_box

List shares on windows machine or samba server

 

mount -t smbfs -o fmask=666,guest //windows_box/share /mnt/share

Mount a windows share

 

echo 'message' | smbclient -M windows_box

Send popup to windows machine (off by default in XP sp2)

math

echo '(1 + sqrt(5))/2' | bc -l

Quick math (Calculate รถ)

echo 'obase=16; ibase=10; 123' | bc

Base conversion (decimal to hexadecimal)

echo $((0x2dec))

Base conversion (hex to dec) ((shell arithmetic expansion))

echo 'pad=20; min=64; (100*10^6)/((pad+min)*8)' | bc

More complex (int) e.g. This shows max FastE packet rate

echo 'pad=20; min=64; print (100E6)/((pad+min)*8)' | python

Python handles scientific notation

echo 'pad=20; plot [64:1518] (100*10**6)/((pad+x)*8)' | gnuplot -persist

Plot FastE packet rate vs packet size

seq 100 | (tr '\n' +; echo 0) | bc

Add a column of numbers. See also add and funcpy

text manipulation (note sed uses stdin and stdout, so if you want to edit files, append <oldfile >newfile)

 

sed 's/string1/string2/g'

Replace string1 with string2

 

sed 's/\(.*\)1/\12/g'

Modify anystring1 to anystring2

 

sed '/ *#/d; /^ *$/d'

Remove comments and blank lines

 

sed ':a; /\\$/N; s/\\\n//; ta'

Concatenate lines with trailing \

 

sed 's/[ \t]*$//'

Remove trailing spaces from lines

 

sed 's/\([\\`\\"$\\\\]\)/\\\1/g'

Escape shell metacharacters active within double quotes

 

sed -n '1000p;1000q'

Print 1000th line

 

sed -n '10,20p;20q'

Print lines 10 to 20

 

sed -n 's/.*<[tT][iI][tT][lL][eE]>\(.*\)<\/[tT][iI][tT][lL][eE]>.*/\1/p;T;q'

Extract title from HTML web page.

 

sort -t. -k1,1n -k2,2n -k3,3n -k4,4n

Sort IPV4 ip addresses

echo 'Test' | tr '[:lower:]' '[:upper:]'

Case conversion

tr -dc '[:print:]' < /dev/urandom

Filter non printable characters

grep 'processor' /proc/cpuinfo | wc -l

Count lines

set operations (Note LANG=C is for speed) (Note also these assume no duplicate lines within a file)

 

LANG=C sort file1 file2 | uniq

Union of unsorted files

 

LANG=C sort file1 file2 | uniq -d

Intersection of unsorted files

 

LANG=C sort file1 file1 file2 | uniq -u

Difference of unsorted files

 

LANG=C sort file1 file2 | uniq -u

Symmetric Difference of unsorted files

 

LANG=C comm file1 file2 | sed 's/^\t*//'

Union of sorted files

 

LANG=C comm -12 file1 file2

Intersection of sorted files

 

LANG=C comm -13 file1 file2

Difference of sorted files

 

LANG=C comm -3 file1 file2 | sed 's/^\t*//'

Symmetric Difference of sorted files

calendar

cal -3

Display a calendar

cal 9 1752

Display a calendar for a particular month year

date -d fri

What date is it this friday. See also day

date --date='25 Dec' +%A

What day does xmas fall on, this year

date --date '1970-01-01 UTC 1234567890 seconds'

Convert number of seconds since the epoch to a date

TZ=':America/Los_Angeles' date

What time is it on West coast of US (use tzselect to find TZ)

 

echo "mail -s 'get the train' P@draigBrady.com < /dev/null" | at 17:45

Email reminder

echo "DISPLAY=$DISPLAY xmessage cooker" | at "NOW + 30 minutes"

Popup reminder

locales

printf "%'d\n" 1234

Print number with thousands grouping appropriate to locale

BLOCK_SIZE=\'1 ls -l

get ls to do thousands grouping appropriate to locale

echo "I live in `locale territory`"

Extract info from locale database

locale | cut -d= -f1 | xargs locale -kc | less

List fields in locale database

LANG=en_IE.utf8 locale int_prefix

Lookup locale info for specific country. See also ccodes

disk space (See also FSlint)

ls -lSr

Show files, biggest last

du -s * | sort -k1,1rn | head

Show top disk users in current dir. See also dutop

df -h

Show free disk space

df -i

Show free inodes

fdisk -l

Show disks partitions sizes and types (run as root)

rpm -q -a --qf '%10{SIZE}\t%{NAME}\n' | sort -k1,1n

List all packages by installed size (Bytes) on rpm distros

dpkg-query -W -f='${Installed-Size;10}\t${Package}\n' | sort -k1,1n

List all packages by installed size (KBytes) on deb distros

dd bs=1 seek=2TB if=/dev/null of=ext3.test

Create a large test file (taking no space). See also truncate

monitoring/debugging

strace -c ls >/dev/null

Summarise/profile system calls made by command

strace -f -e open ls >/dev/null

List system calls made by command

ltrace -f -e getenv ls >/dev/null

List library calls made by command

lsof -p $$

List paths that process id has open

lsof ~

List processes that have specified path open

tcpdump not port 22

Show network traffic except ssh. See also tcpdump_not_me

ps -e -o pid,args --forest

List processes in a hierarchy

ps -e -o pcpu,cpu,nice,state,cputime,args --sort pcpu | sed '/^ 0.0 /d'

List processes by % cpu usage

ps -e -orss=,args= | sort -b -k1,1n | pr -TW$COLUMNS

List processes by mem usage. See also ps_mem.py

ps -C firefox-bin -L -o pid,tid,pcpu,state

List all threads for a particular process

ps -p 1,2

List info for particular process IDs

last reboot

Show system reboot history.

free -m

Show amount of (remaining) RAM (-m displays in MB)

watch -n1 'cat /proc/interrupts'

Watch changeable data continuously

System information (see also sysinfo)

 

hdparm -i /dev/hda

Show info about disk hda

 

hdparm -tT /dev/hda

Do a read speed test on disk hda

 

badblocks -s /dev/hda

Test for unreadable blocks on disk hda

mount | column -t

Show mounted filesystems on the system (and align output)

cat /proc/partitions

Show all partitions registered on the system

grep MemTotal /proc/meminfo

Show RAM total seen by the system

grep "model name" /proc/cpuinfo

Show CPU(s) info

lspci -tv

Show PCI info

lsusb -tv

Show USB info

recode (Obsoletes iconv, dos2unix, unix2dos)

recode -l | less

Show available conversions (aliases on each line)

 

recode windows-1252.. file_to_change.txt

Windows "ansi" to local charset (auto does CRLF conversion)

 

recode utf-8/CRLF.. file_to_change.txt

Windows utf8 to local charset

 

recode iso-8859-15..utf8 file_to_change.txt

Latin9 (western europe) to utf8

 

recode ../b64 < file.txt > file.b64

Base64 encode

 

recode /qp.. < file.txt > file.qp

Quoted printable decode

 

recode ..HTML < file.txt > file.html

Text to HTML

recode -lf windows-1252 | grep euro

Lookup table of characters

echo -n 0x80 | recode latin-9/x1..dump

Show what a code represents in latin-9 charmap

echo -n 0x20AC | recode ucs-2/x2..latin-9/x

Show latin-9 encoding

echo -n 0x20AC | recode ucs-2/x2..utf-8/x

Show utf-8 encoding

interactive

mc

Powerful filemanager that can browse rpm, tar, ftp, ssh, ...

screen

Virtual terminals with detach capability, ...

links

Web browser

gnuplot

Interactive/scriptable graphing

octave

Matlab like environment

 


We won't tell. Get more on shows you hate to love
(and love to hate): Yahoo! TV's Guilty Pleasures list.

: socket programming C

 

 

An Introduction to Socket Programming


Contents:
„h Introduction
„h BEWARE
„h Existing Services
„h Netstat Observations
„h Host names and IP numbers
„h Programming Calls
„h Services and Ports
„h Programming Calls
„h Socket Addressing
„h File Descriptors and Sockets
„h File Descriptors
„h Sockets
„h Client Connect
„h Client Communication
„h Stdio Buffers
„h Server Applications
„h Server Bind
„h Listen and Accept
„h Inetd Services
„h Inetd Comments
„h Whois Daemon
„h Running the Daemon
„h The Code
„h Connecting to the Server
„h Whois Client
„h Perl Socket Programming
„h Final Comments
„h Note Well
„h Suggested Reading
„h Author

Please Post & Get Full In formation about Socket Programming In C

[hide]
Introduction:
These course notes are directed at Unix application programmers who want to develop client/server applications in the TCP/IP domain (with some hints for those who want to write UDP/IP applications). Since the Berkeley socket interface has become something of a standard these notes will apply to programmers on other platforms.
Fundamental concepts are covered including network addressing, well known services, sockets and ports. Sample applications are examined with a view to developing similar applications that serve other contexts. Our goals are
„h to develop a function, tcpopen(server,service), to connect to service.
„h to develop a server that we can connect to.
This course requires an understanding of the C programming language and an appreciation of the programming environment (ie. compilers, loaders, libraries, Makefiles and the RCS revision control system). If you want to know about socket programming with perl(1) then see below but you should read everything first.
Our example is the UWO/ITS whois(1) service -- client and server sources available in:
Network Services: http://www.uwo.ca/its/network
Look for the whois(1) client and the whoisd(8) server. You'll find extensive documentation on the UWO/ITS Whois/CSO server -- that's the whoisd(8) server. It also includes some Perl clients which access the server to provide a gateway service (for the Finding People Web page and for CSO/PH clients). The Unix whois(1) client will be pretty obvious after you've read these notes.

BEWARE:
If C code scares you, then you'll get some concepts but you might be in the wrong course. You need to be a programmer to write programs (of course). This isn't an Introduction to C (or Perl)!


Existing Services:
Before starting, let's look at existing services. On a Unix machine there are usually lots of TCP/IP and UDP/IP services installed and running:
[1:17pm julian] netstat -a
Active Internet connections (including servers)
Proto R-Q S-Q Local Address Foreign Address (state)
tcp 0 0 julian.2717 vnet.ibm.com.smtp ESTABLISHED
tcp 0 0 julian.smtp uacsc2.alban.55049 TIME_WAIT
tcp 0 13 julian.nntp watserv1.wat.3507 ESTABLISHED
tcp 0 0 julian.nntp gleep.csd.uw.3413 ESTABLISHED
tcp 0 0 julian.telnet uwonet-serve.55316 ESTABLISHED
tcp 0 0 julian.login no8sun.csd.u.1023 ESTABLISHED
tcp 0 0 julian.2634 Xstn15.gaul..6000 ESTABLISHED
etc...
tcp 0 0 *.printer *.* LISTEN
tcp 0 0 *.smtp *.* LISTEN
tcp 0 0 *.waisj *.* LISTEN
tcp 0 0 *.account *.* LISTEN
tcp 0 0 *.whois *.* LISTEN
tcp 0 0 *.nntp *.* LISTEN
etc...
udp 0 0 *.ntp *.*
udp 0 0 *.syslog *.*
udp 0 0 *.xdmcp *.*

Netstat Observations:
Inter Process Communication (or IPC) is between host.port pairs (or host.service if you like). A process pair uses the connection -- there are client and server applications on each end of the IPC connection.
Note the two protocols on IP -- TCP (Transmission Control Protocol) and UDP (User Datagram Prototocol). There's a third protocl ICMP (Internet Control Message Protocol) which we'll not look at -- it's what makes IP work in the first place!
We'll be looking in more detail at TCP services and will not look at UDP -- but see a sample Access Control List client/server pair which uses UDP services, you'll find that in:
Access Control Lists: http://www.uwo.ca/its/network/security/acl
TCP services are connection orientated (like a stream, a pipe or a tty like connection) while UDP services are connectionless (more like telegrams or letters).
We recognize many of the services -- SMTP (Simple Mail Transfer Protocol as used for E-mail), NNTP (Network News Transfer Protocol service as used by Usenet News), NTP (Network Time Protocol as used by xntpd(8)), and SYSLOG is the BSD service implemented by syslogd(1M).
The netstat(1M) display shows many TCP services as ESTABLISHED (there is a connection between client.port and server.port) and others in a LISTEN state (a server application is listening at a port for client connections). You'll often see connections in a CLOSE_WAITE state -- they're waiting for the socket to be torn down.

Host names and IP numbers:
Hosts have names (eg. julian.uwo.ca) but IP addressing is by number (eg. [129.100.2.12]). In the old days name/number translations were tabled in /etc/hosts.
[2:38pm julian] page /etc/hosts
# /etc/hosts: constructed out of private data and DNS. Some machines
# need to know some things at boot time. Otherwise, rely on DNS.
#
127.0.0.1 localhost
129.100.2.12 julian.uwo.ca
129.100.2.26 backus.ccs.uwo.ca loghost.its.uwo.ca
129.100.2.33 filehost.ccs.uwo.ca
129.100.2.14 panther.uwo.ca
etc...
These days name to number translations are implemented by the Domain Name Service (or DNS) -- see named(8). and resolv.conf(4).
[2:43pm julian] page /etc/resolv.conf
# $Author: reggers $
# $Date: 1997/05/02 20:17:16 $
# $Id: socket.html,v 1.8 1997/05/02 20:17:16 reggers Exp $
# $Source: /usr/src/usr.local/doc/courses/socket/RCS/socket.html,v $
# $Locker: $
#
# The default /etc/resolv.conf for the ITS solaris systems.
#
nameserver 129.100.2.12
nameserver 129.100.2.51
nameserver 129.100.10.252
domain its.uwo.ca
search ncsm.its.uwo.ca its.uwo.ca uwo.ca

Programming Calls:
Programmers don't scan /etc/hosts nor do they communicate with the DNS. The C library routines gethostbyname(3) (and gethostbyaddr(3) on the same page) each return a pointer to an object with the following structure:
struct hostent {
char *h_name; /* official name */
char **h_aliases; /* alias list */
int h_addrtype; /* address type */
int h_length; /* address length */
char **h_addr_list; /* address list */
};
#define h_addr h_addr_list[0]
/* backward compatibility */
The structure h_addr_list is a list of IP numbers (recall that a machine might have several interfaces, each will have a number).
Good programmers would try to connect to each address listed in turn (eg. some versions of ftp(1) do that). Lazy programmers (like me) just use h_addr -- the first address listed. But see the acl(1) and acld(8) example noted earlier -- the client will try each server until it gets an answer or runs out of servers to ask.
Client applications connect to a host.port (cf. netstat output) for a service provided by the application found at that address.
Proto R-Q S-Q Local Address Foreign Address (state)
tcp 0 0 julian.2717 vnet.ibm.com.smtp ESTABLISHED
tcp 0 13 julian.nntp watserv1.wat.3507 ESTABLISHED

The connection is usually prefaced by translating a host name into an IP number (but if you knew the IP number you could carefully skip that step).
int tcpopen(host,service)
char *service, *host;
{
struct hostent *hp;
etc...
if ((hp=gethostbyname(host)) == NULL) then error...

I say "carefully" because the IP address is a structure of 4 octets. Watch out for byte ordering. An unsigned long isn't the same octet sequence on all machines. See byteorder(3N) for host to net conversions (host format to/from network format).

Services and Ports:
Services have names (eg. SMTP the Simple Mail Transfer Protocol). Ports have numbers (eg. SMTP is a service on port 25). The mapping from service names to port numbers is listed in /etc/services.
[1:22pm julian] page /etc/services
# $Author: reggers $
# $Date: 1997/05/02 20:17:16 $
#
# Network services, Internet style
etc...
ftp 21/tcp
telnet 23/tcp
smtp 25/tcp mail
whois 43/tcp nicname
domain 53/tcp nameserver
domain 53/udp nameserver
tftp 69/udp
finger 79/tcp
nntp 119/tcp readnews untp
ntp 123/udp
snmp 161/udp
xdmcp 177/udp xdm
etc...

Programming Calls:
But programmers don't scan /etc/services, they use library routines. The C library routines getservbyname(3N) (and getservbyport(3N) on the same page) each return a pointer to an object with the following structure containing the broken-out fields of a line in /etc/services.
struct servent {
char *s_name; /* name of service */
char **s_aliases; /* alias list */
int s_port; /* port for service */
char *s_proto; /* protocol to use */
};

Client applications connect to a service port. Usually this is prefaced by translating a service name (eg. SMTP) into the port number (but if you knew the port number you could carefully skip that step).
int tcpopen(host,service)
char *service, *host;
{
struct servent *sp;
etc...
if ((sp=getservbyname(service,"tcp")) == NULL) then error...

Ie. to determine the port number for a particular tcp service. Note that you'd do the same to determine port numbers for UDP services.

Socket Addressing:
A Socket Address is a host.port pair (communication is between host.port pairs -- one on the server, the other on the client). We know how to determine host numbers and service numbers so we're well on our way to filling out a structure were we specify those numbers. The structure is sockaddr_in, which has the address family is AF_INET as in this fragment:
int tcpopen(host,service)
char *service, *host;
{ int unit;
struct sockaddr_in sin;
struct servent *sp;
struct hostent *hp;
etc...
if ((sp=getservbyname(service,"tcp")) == NULL) then error...
if ((hp=gethostbyname(host)) == NULL) then error...

bzero((char *)&sin, sizeof(sin));
sin.sin_family=AF_INET;
bcopy(hp->h_addr,(char *)&sin.sin_addr, hp->h_length);
sin.sin_port=sp->s_port;
etc...

The code fragment is filling in the IP address type AF_INET, port number and IP address in the Socket Address structure -- the address of the remote host.port where we want to connect to find a service.
There's a generic Socket Address structure, a sockaddr, used for communication in arbitrary domains. It has an address family field and an address (or data) field:
/* from: /usr/include/sys/socket.h */
struct sockaddr {
u_short sa_family; /* address family */
char sa_data[14]; /* max 14 byte addr */
};

The sockaddr_in structure is for Internet Socket Addresses (address family AF_INET). An instance of the generic socket address.
/* from: /usr/include/netinet/in.h */
struct sockaddr_in {
short sin_family; /* AF_INET */
u_short sin_port; /* service port */
struct in_addr sin_addr; /* host number */
char sin_zero[8]; /* not used */
};
The family defines the interpretation of the data. In other domains addressing will be different -- services in the UNIX domain are names (eg. /dev/printer). In the sockaddr_in structure we've got fields to specify a port and a host IP number (and 8 octets that aren't used at all!). That structure specifies one end of an IPC connection. Creating that structure and filling in the right numbers has been pretty easy so far.

File Descriptors and Sockets:

File Descriptors:
File Descriptors are the fundamental I/O object. You read(2) and write(2) to file descriptors.
int cc, fd, nbytes;
char *buf;

cc = read(fd, buf, nbytes);
cc = write(fd, buf, nbytes)
The read attempts to read nbytes of data from the object referenced by the file descriptor fd into the buffer pointed to by buf. The write does a write to the file descriptor from the buffer. Unix I/O is a byte stream.
File descriptors are numbers used for I/O. Usually the result of open(2) and creat(2) calls.
All Unix applications run with stdin as file descriptor 0, stdout as file descriptor 1, and stderr as file descriptior 3. But stdin is a FILE (see stdio(3S)) not a file descriptor. If you want a stdio FILE on a file descriptor use fdopen(3S).
Sockets:
A Socket is a Unix file descriptor created by the socket(3N) call -- you don't open(2) or creat(2) a socket. By way of comparison pipe(2) creates file descriptors too -- you might be familiar with pipes which predate sockets in the development of the Unix system.
int s, domain, type, protocol;
s = socket(domain, type, protocol);
etc...
cc = read(s, buf, nbytes);
The domain parameter specifies a communications domain (or address family). For IP use AF_INET but note that socket.h lists all sorts of address families. This is to inform the system how an address should be understood -- on different networks, like AF_DECnet, addressing may be longer than the four octets of an IP number. We're only concerned with IP and the AF_INET address family.
The type parameter specifies the semantics of communication (sometimes know as a specification of quality of services). For TCP/IP use SOCK_STREAM (for UDP/IP use SOCK_DGRAM). Note that any address family might support those service types. See socket.h for a list of service types that might be supported.
A SOCK_STREAM is a sequenced, reliable, two-way connection based byte stream. If a data cannot be successfully transmitted within a reasonable length of time the connection is considered broken and I/O calls will indicate an error.
The protocol specifies a particular protocol to be used with the socket -- for TCP/IP use 0. Actually there's another programmers interface getprotobyname(3N) that provides translates protocol names to numbers. It's an interface to the data found in /etc/protocols -- compare with the translation of service names to port numbers discussed above.

Client Connect:
A client application creates a socket(3N)and then issues a connect(3N) to a service specified in a sockaddr_in structure:
int tcpopen(host,service)
char *service, *host;
{ int unit;
struct sockaddr_in sin;
struct servent *sp;
struct hostent *hp;

if ((sp=getservbyname(service,"tcp")) == NULL) then error...
if ((hp=gethostbyname(host)) == NULL) then Ierror...
bzero((char *)&sin, sizeof(sin))
etc...
if ((unit=socket(AF_INET,SOCK_STREAM,0)) < 0) then error...
if (connect(unit,&sin,sizeof(sin)) < 0) then error...
return(unit);
}
The result returned is a file descriptor which is connected to a server process. A communications channel on which one can conduct an application specific protocol.
Client Communication:
Having connected a socket to a server to establish a file descriptor communication is with the usual Unix I/O calls. You have Inter Process Communication (or IPC) to a server.
Many programmers turn file descriptors into stdio(3S) streams so they can use fputs, fgets, fprintf, etc. -- use fdopen(3S).
main(argc,argv)
int argc;
char *argv[];
{
int unit,i;
char buf[BUFSIZ];
FILE *sockin,*sockout;

if ((unit=tcpopen(WHOHOST,WHOPORT))
< 0) then error...
sockin=fdopen(unit,"r");
sockout=fdopen(unit,"w");
etc...
fprintf(sockout,"%s\n",argv[i]);
etc...
while (fgets(buf,BUFSIZ,sockin)) etc...

Stdio Buffers:
Stdio streams have powerful manipulation tools (eg. fscanf is amazing). But beware, streams are buffered! This means a well placed fflush(3S) is often required to flush a buffer to the peer.
fprintf(sockout,"%s\n",argv[i]);
fflush(sockout);

while (fgets(buf,BUFSIZ,sockin)) etc...
Many client/server protocols are client driven -- the client sends a command and expects an answer. The server won't see the command if the client doesn't flush the output. Likewise, the client won't see the answer if the server doesn't flush it's output.
Watch out for client and server blocking -- both waiting for input from the other.

Server Applications:
A system offers a service by having an application running that is listening at the service port and willing to accept a connection from a client. If there is no application listening at the service port then the machine doesn't offer that service.
The SMTP service is provided by an application listening on port 25. On Unix systems this is usually the sendmail(1M) application which is started at boot time.
[2:20pm julian] ps -agx | grep sendmail
419 ? SW 0:03 /usr/lib/sendmail -bd -q15m
18438 ? IW 0:01 /usr/lib/sendmail -bd -q15m

[2:28pm julian] netstat -a | grep smtp
tcp 0 0 julian.3155 acad3.alask.smtp SYN_SENT
tcp 0 0 *.smtp *.* LISTEN

In the example we have a process listening to the smtp port (for inbound mail) and another process talking to the smtp port on acad3.alaska.edu (ie. sending mail to that system).
So how do we get a process bound behind a port?
Server Bind:
A Server uses bind(3N) to establish the local host.port assignment -- ie. so it is the process behind that port. That's really only required for servers -- applications which accept(3N) connections to provide a service.
struct servent *sp;
struct sockaddr_in sin;

if ((sp=getservbyname(service,"tcp")) == NULL) then error...

sin.sin_family=AF_INET;
sin.sin_port=sp->s_port;
sin.sin_addr.s_addr=htonl(INADDR_ANY);

if ((s=socket(AF_INET,SOCK_STREAM,0)) < 0) then error...
if (bind(s, &sin, sizeof(sin)) < 0) then error...
htonl(3N) converts a long to the right sequence (given different byte ordering on different machines). The IP address INADDR_ANY means all interfaces. You could, if you wanted, provide a service only on some interfaces -- eg. if you only provided the service on the loopback interface (127.0.0.1) then the service would only be available to clients on the same system.
What this code fragment does is specify a local interface and port (into the sin structure). The process is bound to that port -- it's now the process behind the local port.
Client applications usually aren't concerned about the local host.port assignment (the connect(3N) does a bind o some random but unused local port on the right interface). But rcp(1) and related programs (like rlogin(1) and rsh(1)) do connect from reserved port numbers.
I've done the same in some of my programming. See, for example, the version of tcpopen.c used in our Passwdd/Passwd -- An authentication Daemon/Client. There's an instance where a client application connects from a reserved port.
Listen and Accept:
To accept connections, a socket is created with socket(3N), it's bound to a service port with bind(3N), a queue for incoming connections is specified with listen(3N) and then the connections are accepted with accept(3N) as in this fragment:
struct servent *sp;
struct sockaddr_in sin,from;

if ((sp=getservbyname(service,"tcp")) == NULL) then error...
sin.sin_family=etc...
if ((s=socket(AF_INET,SOCK_STREAM,0)) < 0) then error...
if (bind(s, &sin, sizeof(sin)) < 0) then error...
if (listen(s,QUELEN) < 0) then error...
for (;;) {
if ((g=accept(f,&from,&len)) < 0) then error...
if (!fork()) {
child handles request...
...and exits
exit(0);
}
close(g); /* parent releases file */
}

This is the programming schema used by utilities like sendmail(1M) and others -- they create their socket and listen for connections. When connections are made, the process forks off a child to handle that service request and the parent process continues to listen for and accept further service requests.
But, you really don't want to use that programming paradigm unless you really have to. There are lots of hidden issues (like becoming a detached process and more) that you'd rather avoid.
Fortunately, there's an easier method.

Inetd Services:
Not all services are started at boot time by running a server application. Eg. you won't usually see a process running for the finger service like you do for the smtp service. Many are handled by the InterNet Daemon inetd(1M). This is a generic service configured by the file inetd.conf(4).
[2:35pm julian] page /etc/inetd.conf
# $Author: reggers $
# $Date: 1997/05/02 20:17:16 $
#
# Internet server configuration database
ftp stream tcp nowait root /usr/etc/ftpd ftpd
telnet stream tcp nowait root /usr/etc/telnetd telnetd
shell stream tcp nowait root /usr/etc/rshd rshd
login stream tcp nowait root /usr/etc/rlogind rlogind
exec stream tcp nowait root /usr/etc/rexecd rexecd
uucpd stream tcp nowait root /usr/etc/uucpd uucpd
finger stream tcp nowait nobody /usr/etc/fingerd fingerd
etc...
whois stream tcp nowait nobody /usr/lib/whois/whoisd whoisd
etc...


Inetd Comments:
For each service listed in /etc/inetd.conf the inetd(1M) process, and that is a process is started at boot time, executes the socket(3N), bind(3N), listen(3N) and accept(3N) calls as discussed above. Inetd also handles many of the daemon issues (signal handling, set process group and controlling tty) which we've studiously avoided.
The inetd(1M) process spawns the appropriate server application (with fork(2) and exec(2)) when a client connects to the service port. The daemon continues to listen for further connections to the service while the spawned child process handles the request which just came in.
The server application (ie. the child spawned by inetd(1M)) is started with stdin and stdout connected to the remote host.port of the client process which made the connection. Any input/output by the server appliation on stdin/stdout are sent/received by the client application. You have Inter Process Communication (or IPC)!
This means, any application written to use stdin/stdout can be a server application. Writing a server application should therefore be fairly simple.
Whois Daemon:
On julian we have an entry in /etc/inetd.conf for the UWO/ITS whois service:
[3:25pm julian] grep whois /etc/inetd.conf
whois stream tcp nowait nobody /usr/lib/whois/whoisd whoisd
This is our local directory service -- it's implemented on a TCP/IP stream (all whois services are), at the whois port (all whois services should be at that port), it's ran as user nobody (you don't need to run servers as user root), the program to run is /usr/lib/whois/whoisd, and the command line to the program is just whoisd.
This is a standard whois service -- it implements the trivial protocol required of all whois servers. Any whois client can use the service. The program conducts an application protocol on stdin/stdout (which is usually connected by a TCP/IP socket to a client application). The protocol is trivial -- server accepts a one line query, answers back and exits.

Running the Daemon:
You can run the whois daemon (on the server) to see what it does:
[3:27pm julian] echo reggers | /usr/lib/whois/whoisd
There were 1 matches on your request.

Full Name: Quinton, Reg
Department: Info Tech Svcs
Room: NSC 214
Phone: 679-2111x(6026)
Index Key: 481800
Machine Address: reggers@julian.uwo.ca
Directory Addresses: reg.quinton@uwo.ca
: r.quinton@uwo.ca
: reggers@uwo.ca
: quinton@uwo.ca

For more information try 'whois help'.
The program is command driven -- you give a command (or query string) on stdin, it produces results on stdout, and exits. This is a very simple protocol, compare with fingerd(1M).
Actually the example is a misrepresentation -- our server will only answer questions if it's input is a socket in the AF_INET. That's because we want to syslog(3) all transactions -- we want to know where the connection came from.

The Code:
The server program is easy enough -- read a line, switch on command, and exit.
fgets(string,BUFSIZ,stdin); read from socket...

/* for some reason people send the whois phrase */

again:
strcpy(verb,""); strcpy(args,"");
sscanf(buf,"%[^ \t\r\n]%*c%[^\r\n]",verb,args);
if (!strcasecmp(verb,"whois")) {
strcpy(buf,args);
goto again;
}
sscanf(buf,"%[^\r\n]",buf);

/* switch on command verbs */
if (!strcasecmp(verb,"help"))
givehelp(args); output sent to stdout...
else etc...

/* or just display a person */
else listdisplay(lookbyname(buf));
output sent to stdout...

fflush(stdout); push output to client ...
Server programs can be that simple.

Connecting to the Server:
You can make a telnet(1) connection to the whois service on the server.
[3:47pm julian] telnet julian whois
Trying 129.100.2.12 ... Connected to julian.uwo.ca.
Escape character is '^]'.
reggers .... my command input
There were 1 matches on your request.

Full Name: Quinton, Reg
Department: Info Tech Svcs
Room: NSC 214
Phone: 679-2111x(6026)
Index Key: 481800
Machine Address: reggers@julian.uwo.ca
Directory Addresses: reg.quinton@uwo.ca
: r.quinton@uwo.ca
: reggers@uwo.ca
: quinton@uwo.ca

For more information try 'whois help'.
Connection closed by foreign host.
But we wouldn't normally use telnet as the client application (although in this case we could).

Whois Client:
The whois(1) client makes a TCP/IP connection to the server (using the tcpopen function we've developed here) and conducts the kind of protocol that you would type if you where to make a connection by hand:
[7:30am julian] whois reggers
There were 1 matches on your request.

Full Name: Quinton, Reg
Department: Info Tech Svcs
Room: NSC 214
Phone: 679-2111x(6026)
Index Key: 481800
Machine Address: reggers@julian.uwo.ca
Directory Addresses: reg.quinton@uwo.ca
: r.quinton@uwo.ca
: reggers@uwo.ca
: quinton@uwo.ca

For more information try 'whois help'.
The client sends the command "reggers", the server sends back the answer and the client displays the answer received to the user. When the server is finished the connection is closed.
If you understand the development of the tcpopen function then the rest of the code for that client should not be too difficult. See the entire distribution for that application -- there's only one main program to complete the kit.

Perl Socket Programming:
These days it's not unusal to see socket programming in perl(1) as well as C programs. Assuming you have been able to follow the notions presented above in the development of a tcpopen function written in C as used by our whois(1) client the following is for the Perl enthusiast:
sub tcpopen {
use Socket; # need socket interface
my($server, $service) = @_; # args to this function
my($proto, $port, $iaddr); # local variables
my($handle)="$server\:\:$service"; # localized obscure handle

die("550:Cannot getprotobyname('tcp')\r\n")
unless ($proto = getprotobyname('tcp'));

die("550:Cannot getservbyname($service)\r\n")
unless ($port = getservbyname($service, 'tcp'));

die("550:Cannot gethostbyname($server)\r\n")
unless ($iaddr = gethostbyname($server));

die("550:Cannot create socket\r\n")
unless socket($handle, PF_INET, SOCK_STREAM, $proto);

die("550:Cannot connect($service://$server)\r\n")
unless connect($handle, sockaddr_in($port, $iaddr));

# unbuffered I/O to that service

select($handle); $| = 1; select(STDOUT); $| = 1;

return($handle);
}
See whois2ph(8), the whois2ph source, whois2html(8), and the whois2html source -- both are production gateways in Perl to interface with our whoisd(8) server.

Final Comments:
The whois example uses a line based protocol. The strategy is common but by no means universal. For example, the lpd protocols use octets (ie. single characters) for the commands.
Inetd servers are the simplest to implement. However, this may not be optimal. Especially if the server has to do a lot of work first (eg. loading in a big data base).
Stand alone servers have to deal with many daemon issues -they should ignore most signals, set a unique process group and get rid of the controlling terminal.
Daemons like nntp could (in theory) handle many clients from a single daemon using interrupt driven I/O. As currently implemented most have an nntp daemon for each client (but INN uses a single daemon for flooding).
You'll note that Socket programmers use alarm(2), setjmp(2), and signal(2) calls. The intent is to prevent a process (client or server) from hanging in a wait for I/O state by setting and trapping on an alarm.
Note Well:
„h The best way to code a client/server program is to reuse code from an existing service. There's lots of public domain examples to work from -- nntp, lpd, sendmail, and even our whois service.
„h A simple solution that works is much better than a fancy solution that doesn't -- keep it simple.
„h Presentation issues, ie. the display for the user, should not effect the protocol or server. Again, protocols have to be simple!
„h Don't ever assume the client or server applications are well behaved!


Suggested Reading:
It shoud be clear that we have lots of real world examples you can look at and work from:
„h UWO/ITS Whois/CSO server, by Reg Quinton, UWO/ITS, 1992-97
„h UWO/ITS Whois client, by Reg Quinton, UWO/ITS, 1992-97
„h Passwdd/Passwd -- An authentication Daemon/Client, by Reg Quinton, UWO/ITS, 1992-97
„h ACL -- Access Control Lists, by Reg Quinton, UWO/ITS, 1995-97
More detailed documentation, should you need it, can be found at:
„h Introductory 4.3BSD Interprocess Communication, by Stuart Sechrest, (in) UNIX Programmer's Supplementary Documents, Vol1, 4.3 Berkeley Software Distribution, PS1:7.
„h Advanced 4.3BSD Interprocess Communication, by Samuel J. Leffler et al, (in) UNIX Programmer's Supplementary Documents, Vol1, 4.3 Berkeley Software Distribution, PS1:8.
„h Introduction to the Internet Protocols, Computer Science Facilities Group, Rutgers. (See ftp:/ftp.uwo.ca/nic)
„h Networking with BSD-style Sockets, by John Romkey, (in) Unix World, July-Aug. 1989.
„h How to Write Unix Daemons, by Dave Lennert, (in) Unix World, Dec. 1988.
„h A Socket-Based Interprocess Communications Tutorial, Chpt. 10 of SunOS Network Programming Guide.
„h An Advanced Socket-Based Interprocess Communications Tutorial, Chpt. 11 of SunOS Network Programming Guide. [/hide]



--

writing own OS

 

 

How to write an operating system
Writing an operating system is something that can not only be interesting (if you're one of those
people that get turned on by Int 13....) but it is also a great learning experience. Through creating
your own operating system you will learn exactly what goes on behind the scenes, elevating you above
the average programmer that just writes in Visual Basic.

In this tutorial you will be tought by examples, and by the end you should have created your own operating system.

Tools:
EasyOs easyos.zip 300kb
EasyOS is a very simple operating system, it contains all the tools needed to build an operating system.
(Not written by me, although I did add bits to it and mess it up a bit)

A quick explanation of assembly: (see here for a good tutorial)

si and ah Think of si as something to put text into, and ah as something to put numbers into.
mov This (mov)es data. mov ah,0 would move 0 into ah. (The data on the right is moved into the left)
Int Think of these as functions. Different int's do different things when ah is different. Ahem. Eg.
when ah = 0 and you call int 10 it prints si to the screen.
Stuff To put words and stuff in your program you can't just do mov si,'some words' (well, you can but
you wont like the resutls) so instead you have to declare the words first. You do this by putting the
name of what you want the words to be called by, then the data type (nearly always db) then the words themselves. Eg:
name db 'some words'
Jump To give sections of code a label, just type the label and add a : at the end, eg code: .
You can then use jmp to jump to it, eg jmp code If To do an if in assembly you use cmp, eg
cmp al,0 (if al=0). On the next line you then put je code, and if al=0 then the program jumps to
the section of code called code. If you use jne code, then if al is not 0 the program will jump to code.
The stack The stack is where stuff is stored. push pushes stuff into it, pop pulls stuff out.
The following example would put cx into dx:
push cx pop dx

Now you know everything there is to know about assembly, you can now understand most of the program that
boot's EasyOs. Drives (hard drives and floppy's) are split into lots of bits, all 512 bytes long
(enough to fit 512 letters in). These are calle sectors. The first sector is what the computer looks
for when it boots. It is called the bootsector.
Open the folder src and then open boot.asm. Or if you are lazy, just look at the code below (its the same).
; This is a comment
[ORG 0x7C00] ;This just tells the program where it is in the memory. Not important
[BITS 16] ;Not important too.

jmp start ; Jump over BIOS parameter block

start: ;The label for the start of the actual program

push cs ;Put cs onto the stack
pop ds ;Take it out and put it into ds


mov si,Print_loading ;Print loading message
call printstring ;Call is like jump, but it goes back. Like a function


;The complicated bit: Loads the next program
mov ah,02h ;When ah=, int13 reads a disk sector
mov al,4 ;Al is how many sectors to read
mov ch,0 ;The track to read from
mov cl,2 ;Sector Id
mov dh,0 ;Head
mov dl,0 ;Drive (0 is floppy)
mov bx,0x1000 ;Es and Bx put together are where to load the program too (see jmp 0x1000:0x00)
mov es,bx
mov bx,0x00
int 13h ;Int 13 is all functions for disks

mov si,putdot ;Print a ".".
call printstring

jmp 0x1000:0x00 ;Run Bootinit from stack.

printstring: ;Print string routine.
mov ah,0eh ;Mov ah into 0, so int 10 prints
stringloop: ;The following code loads each seperate charcter so it can be printed
lodsb
cmp al,00 ;If al =0, then the string has all been loaded
je endstring
int 10h ;When int 10 is called, and ah=, it prints
jmp stringloop
endstring:
ret ;Ret returns



putdot db '.',0
Print_loading db 13,10,'Loading Easy OS v0.01a...',0
times 425 db 0 ;wastes 425 bytes on purpose, so the sector is full (The program must be 512 bytes long)


You may have noticed that numbers, like int 10h, end in h. They don't have to, it just looks funky (there is a real reason, but it's boring).
Anyway, now copy the program called copyboot in the folder called utils to the folder with test.asm in. Open the dos prompt and type: (Make sure a blank floppy is inserted)
copyboot test.com 0
copyboot is the name of the program, test.com the name of the file to copy, and 0 is the sector.
In the program above all it does is print a string then load whats at sector 1. The program that easyos loads under the src folder called bootinit. If you assemble it with nasm, then copy it to sector 1 and restart, the bootsector will load it.
There isn't much more to be learnt from EasyOs, so run either setup.exe or make.bat to build the whole thing. The difference is setup.exe lets you setup a root password for EasyOs. If you just run make.bat the passwords is the default password: monty (named after my psychotic dog).
Now restart and be amazed. Wow. Pretty crappy, but it isn't that bad.


Fat 12
No, its not a fat people supprt group but a file system. If you try and access the floppy disk Windows will say it need s to be formatted. Formatted? You ask. Formatting is basically organising the sectors so you can give them names. Underneath Windows and Fat, you are still just accessing sectors. I won't go into Fat here, check out http://www.maverick.subnet.dk/ for some info. Anyway, the bootsector needs to have some information in it that when Windows reads it it tells it it is fat. The following BootSector was disgustingly ripped by me of NYAOS (I have no idea what i stands for). With your A* qualification in assembly language you can no doubt understand it.
; NYAOS Boot Sector © Copyright Sean Tash 1998
; assemble with:
; nasm -f bin -o bootsect.bin bootsect.asm
bits 16
org 0x7C00

start: jmp short begin
nop
bsOEM db "NYAOS1.0" ; OEM String
bsSectSize dw 512 ; Bytes per sector
bsClustSize db 1 ; Sectors per cluster
bsRessect dw 1 ; # of reserved sectors
bsFatCnt db 2 ; # of fat copies
bsRootSize dw 224 ; size of root directory
bsTotalSect dw 2880 ; total # of sectors if < 32 meg
bsMedia db 0xF0 ; Media Descriptor
bsFatSize dw 9 ; Size of each FAT
bsTrackSect dw 18 ; Sectors per track
bsHeadCnt dw 2 ; number of read-write heads
bsHidenSect dd 0 ; number of hidden sectors
bsHugeSect dd 0 ; if bsTotalSect is 0 this value is
; the number of sectors
bsBootDrv db 0 ; holds drive that the bs came from
bsReserv db 0 ; not used for anything
bsBootSign db 29h ; boot signature 29h
bsVolID dd 0 ; Disk volume ID also used for temp
; sector # / # sectors to load
bsVoLabel db "NO NAME " ; Volume Label
bsFSType db "FAT12 " ; File System type

begin: cli ; disable interrupts
mov [bsBootDrv],dl ; save drive number
mov ax,0x9000 ; put stack at 0x98000
mov ss,ax
mov sp,0x8000

mov cx,[bsTrackSect] ; update int 1E FDC param table
mov bx,0x0078
lds si,[ds:bx]
mov byte [si+4], cl
mov byte [si+9], 0x0F

sti ; enable interrupts
push ds
mov dl,[bsBootDrv] ; reset controller
xor ax,ax
int 0x13
pop ds
jc bootfail2 ; display error message
jmp _l1
bootfail2: jmp bootfail
_l1:
mov ax,0x0000
mov es,ax
mov ds,ax

mov si,MsgLoad ; display load message
call putstr

; find the root directory

xor ax,ax
mov al,[bsFatCnt]
mov bx,[bsFatSize]
mul bx
add ax,word [bsHidenSect]
adc ax,word [bsHidenSect+2]
add ax,word [bsRessect] ; ax holds root directory location
mov word [BootSig],ax

call checkroot

xor ax,ax
add ax,word [start]
add ax,word [bsVolID] ; sector number
add ax,word [BootSig]
sub ax,2 ; correction for a mis-calc
mov cx,word [bsVolID+2] ; number of sectors

mov bx,0x8000
mov es,bx


nextsector: push ax ; save registers
push cx
push dx
push es

xor bx,bx ; set zero offset
call readsect ; read a sector

mov si,MsgDot ; display a dot
call putstr

pop es ; restore registers
pop dx
pop cx
pop ax
mov bx,es
add bx,20h ; increment address 512 bytes
mov es,bx
inc ax ; read next sector
loopnz nextsector

mov ax,0x8000 ; set segment registers and jump
mov es,ax
mov ds,ax
push ax
mov ax,0
push ax
retf

checkroot:
push ax ; save registers
push bx
push cx
push dx
push si
push di

mov ax,0x8000 ; put root directory at 0x80000
mov es,ax
mov ax,32 ; AX = ((32*RootSize)/512) + 2
mul word [bsRootSize]
div word [bsSectSize]
mov cx,ax ; cx holds # of sectors in root
mov word [start],ax
mov ax,word [BootSig] ; get prev. saved loc. for root dir

r1: xor bx,bx
push cx ; save count
push ax ; save sector number
push es
push dx
call readsect
xor bx,bx
l_1: mov di,bx ; set address to check from
mov cx,11 ; check 11 bytes
mov si,FileName ; address of string to check with
repz cmpsb
je foundit
add bx,32 ; check next entry
cmp bx,[bsSectSize] ; end of sector?
je l_2
jmp l_1
l_2: pop dx ; restore registers
pop es
pop ax
pop cx
inc ax ; read next sector
loopnz r1
jmp bootfail
foundit: pop dx ; get these off the stack
pop es
pop ax
pop cx

mov di,0x1A ; get clustor #
add di,bx
push bx ; save bx for finding # of sectors
mov ax,[es:di]
xor bx,bx ; calculate sector #
mov bl,[bsClustSize]
mul bx ; ax holds sector #
mov word [bsVolID],ax

pop bx ; get location of directory entry
mov di,0x1C
add di,bx
mov ax,[es:di] ; put number of bytes in ax
xor dx,dx
mov bx,[bsClustSize] ; # of bytes / 512
div bx
inc ax
mov word [bsVolID+2],ax ; save number of sectors to load

pop di ; restore registers
pop si
pop dx
pop cx
pop bx
pop ax

ret ; return to caller

putstr: ; SI = address of string to display
lodsb
or al,al
jz short putstrd
mov ah,0x0E
mov bx,0x0007
int 0x10
jmp putstr
putstrd: retn ; return to caller

bootfail: ; display failure message
mov si,MsgBad ; display error message
call putstr
xor ax,ax ; wait for keypress
int 0x16
int 0x19 ; reboot

readsect: ; ES:BX = Location ; AX = Sector
mov si,[bsTrackSect]
div si ; divide logical sect by track size
inc dl ; sector # begins at 1
mov [bsReserv],dl ; sector to read
xor dx,dx ; logical track left in ax
div word [bsHeadCnt] ; leaves head in dl, cyl in ax
mov dh, [bsBootDrv] ;
xchg dl,dh ; head to dh, drive to dl
mov cx,ax ; cyl to cx
xchg cl,ch ; low 8 bits of cyl to ch, hi 2 bits
shl cl,6 ; shifted to bits 6 and 7
or cl, byte [bsReserv] ; or with sector number
mov al,1 ; number of sectors
mov ah,2 ; use read function of int 0x13
int 0x13 ; read sector
jc bootfail ; display error message
ret ; return to caller

padding times 45 db 0
FileName db "OSLOADERCOM"
MsgBad db "Disk Error...",13,10,0
MsgDot db ".",0
MsgLoad db "doors loading",0
BootSig db 0x55, 0xAA



Anyways, copy the above program, save it, build it with nasm, copy it with copyboot.
As you can guess above, it loads a program called 'OSLOADER.COM' off of the floppy. So, if you want a particularily funky os, build the following with nasm:
;Funky squares
;
;Assembles with NASM
;Made by Frej somewhere between april and may 2000
;Bits reprogrammed to run within DeviatorOS
;
;This demo is just to show you how small graphical demos can get ;)
;Reprogrammed for DeviatorOS as demo program

org 0x0000
mov ax,cs
mov ds,ax
mov es,ax ; fix segment regs

start: mov bx,cs ;put codesegment to bx
add bh,0x20 ;add 2000 to bx
mov ds,bx ;and put it to ds
mov ax,0x13 ;set ax to videomode 13
int 10h ;and do that
Main: push ds ;put buffer seg to stack
pop es ;and put that into es
in ax,0x40 ;generate "random" number (timer)
shl ax,4 ;multiply random # with 16
mov di,ax ;box offset (random)
mov al,255 ;color of the box
mov bx,50 ;height=50
pl: add di,270 ;di+270 (320-width(50))
mov cx,50 ;# bytes to copy to buffer
rep stosb ;and do it
dec bx ;decrement bx
jnz pl ;jump if bx not zero
mov bh,0xFA ;assume bl = 0 (-> bx = FA00)
Smudge: mov al,[bx+1] ;right color to al
mov cl,[bx-1] ;left color to cl
add ax,cx ;and add it to ax
mov cl,[bx-320] ;upper color to cl
add ax,cx ;and add it to ax
mov cl,[bx+320] ;lower color to cl
add ax,cx ;and add it to ax
shr ax,2 ;divide with 4
mov [bx],al ;and but the avarage color to buffer
dec bx ;decrement bx
jnz Smudge ;jump if bx not zero
mov ax,0xA000 ;vga seg
mov es,ax ;put it to es
mov ch,0xFA ;# bytes to copy to vga
xor di,di ;zero vga offset
xor si,si ;zero buffer offset
rep movsb ;and do that
in al,0x60 ;check for keys
dec al ;was it esc?
jnz Main ;nope, continue
mov ax,3 ;text mode
int 10h ;get back into text mode
xor ah,ah ;yes, return to OS
int 0x18 ;back to good old kernel
;Note:- This was, as you can guess, ripped by from an os. So when it goes back to the 'good ol kernel' it just restarts.

Build it with nasm, but rather than faffing around copyboot, just name is as OSLOADER.COM and copy it to the floppy.
Now restart and enjoy the funkiness. Woah dood.


C
Time to escape assembly language. The boot sector has to be written in assembly, but nothing else does. Unfortunately you can't just go and write a cool shell with Visual C++. First of all, its has to be a .com program, not .exe.
.exe programs are just .com with a bit of extra info. at the start giving some info on what the program is. It's very easy to add .exe capabililty to an os, or you can download a program called exe2com.
The serious problem though is that you can create your own ints to make things easier. EasyOs does this (look in kernel.asm under the src folder) and Dos does this too (Dos makes int 21). By default, compilers build a program with these ints.

For linux lovers
The following code is for Gcc on linux and nasm for dos or linux. Dos/ Windows users can download Djgpp from http://www.delorie.com/djgpp/, which is like gcc. The line
gcc -c -O2 -Wall -g -o hello.o hello.c
Tells gcc to build a plain binary. I don't know who wrote the following, e-mail me if you do.

--
siva